umount.c revision 1.27 1 /* $NetBSD: umount.c,v 1.27 2000/06/06 07:09:15 chs Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1980, 1989, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)umount.c 8.8 (Berkeley) 5/8/95";
45 #else
46 __RCSID("$NetBSD: umount.c,v 1.27 2000/06/06 07:09:15 chs Exp $");
47 #endif
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <sys/mount.h>
53 #include <sys/time.h>
54 #include <sys/socket.h>
55
56 #include <netdb.h>
57 #include <rpc/rpc.h>
58 #include <rpc/pmap_clnt.h>
59 #include <rpc/pmap_prot.h>
60 #include <nfs/rpcv2.h>
61
62 #include <err.h>
63 #include <fstab.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
68
69 typedef enum { MNTANY, MNTON, MNTFROM } mntwhat;
70
71 int fake, fflag, verbose, raw;
72 char *nfshost;
73
74 int checkvfsname __P((const char *, char **));
75 char *getmntname __P((char *, mntwhat, char **));
76 char **makevfslist __P((char *));
77 int main __P((int, char *[]));
78 int namematch __P((struct hostent *));
79 int selected __P((int));
80 int umountfs __P((char *, char **));
81 void usage __P((void));
82 int xdr_dir __P((XDR *, char *));
83
84 int
85 main(argc, argv)
86 int argc;
87 char *argv[];
88 {
89 int all, ch, errs, mnts;
90 char **typelist = NULL;
91 struct statfs *mntbuf;
92
93 /* Start disks transferring immediately. */
94 sync();
95
96 all = 0;
97 while ((ch = getopt(argc, argv, "AaFfRh:t:v")) != -1)
98 switch (ch) {
99 case 'A':
100 case 'a':
101 all = 1;
102 break;
103 case 'F':
104 fake = 1;
105 break;
106 case 'f':
107 fflag = MNT_FORCE;
108 break;
109 case 'h': /* -h implies -A. */
110 all = 1;
111 nfshost = optarg;
112 break;
113 case 'R':
114 raw = 1;
115 break;
116 case 't':
117 if (typelist != NULL)
118 errx(1, "only one -t option may be specified.");
119 typelist = makevfslist(optarg);
120 break;
121 case 'v':
122 verbose = 1;
123 break;
124 default:
125 usage();
126 /* NOTREACHED */
127 }
128 argc -= optind;
129 argv += optind;
130
131 if ((argc == 0 && !all) || (argc != 0 && all) || (all && raw))
132 usage();
133
134 /* -h implies "-t nfs" if no -t flag. */
135 if ((nfshost != NULL) && (typelist == NULL))
136 typelist = makevfslist("nfs");
137
138 errs = 0;
139 if (all) {
140 if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
141 warn("getmntinfo");
142 errs = 1;
143 }
144 for (errs = 0, mnts--; mnts > 0; mnts--) {
145 if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
146 continue;
147 if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
148 errs = 1;
149 }
150 } else {
151 for (errs = 0; *argv != NULL; ++argv)
152 if (umountfs(*argv, typelist) != 0)
153 errs = 1;
154 }
155 exit(errs);
156 }
157
158 int
159 umountfs(name, typelist)
160 char *name;
161 char **typelist;
162 {
163 enum clnt_stat clnt_stat;
164 struct hostent *hp;
165 struct sockaddr_in saddr;
166 struct stat sb;
167 struct timeval pertry, try;
168 CLIENT *clp;
169 int so;
170 char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN];
171 mntwhat what;
172
173 hp = NULL;
174 delimp = NULL;
175
176 if (raw) {
177 mntpt = name;
178 } else {
179
180 if (realpath(name, rname) == NULL) {
181 warn("%s", rname);
182 return (1);
183 }
184
185 what = MNTANY;
186 mntpt = name = rname;
187
188 if (stat(name, &sb) == 0) {
189 if (S_ISBLK(sb.st_mode))
190 what = MNTON;
191 else if (S_ISDIR(sb.st_mode))
192 what = MNTFROM;
193 }
194
195 switch (what) {
196 case MNTON:
197 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
198 warnx("%s: not currently mounted", name);
199 return (1);
200 }
201 break;
202 case MNTFROM:
203 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
204 warnx("%s: not currently mounted", mntpt);
205 return (1);
206 }
207 break;
208 default:
209 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
210 name = rname;
211 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
212 warnx("%s: not currently mounted", name);
213 return (1);
214 }
215 }
216 }
217
218 if (checkvfsname(type, typelist))
219 return (1);
220
221 hp = NULL;
222 if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
223 if ((delimp = strchr(name, '@')) != NULL) {
224 hostp = delimp + 1;
225 *delimp = '\0';
226 hp = gethostbyname(hostp);
227 *delimp = '@';
228 } else if ((delimp = strchr(name, ':')) != NULL) {
229 *delimp = '\0';
230 hostp = name;
231 hp = gethostbyname(hostp);
232 name = delimp + 1;
233 *delimp = ':';
234 }
235 }
236
237 if (!namematch(hp))
238 return (1);
239 }
240
241 if (verbose)
242 (void)printf("%s: unmount from %s\n", name, mntpt);
243 if (fake)
244 return (0);
245
246 if (unmount(mntpt, fflag) < 0) {
247 warn("%s", mntpt);
248 return (1);
249 }
250
251 if (!raw && !strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
252 (hp != NULL) && !(fflag & MNT_FORCE)) {
253 *delimp = '\0';
254 memset(&saddr, 0, sizeof(saddr));
255 saddr.sin_family = AF_INET;
256 saddr.sin_port = 0;
257 memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
258 pertry.tv_sec = 3;
259 pertry.tv_usec = 0;
260 so = RPC_ANYSOCK;
261 if ((clp = clntudp_create(&saddr,
262 RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
263 clnt_pcreateerror("Cannot MNT PRC");
264 return (1);
265 }
266 clp->cl_auth = authunix_create_default();
267 try.tv_sec = 20;
268 try.tv_usec = 0;
269 clnt_stat = clnt_call(clp,
270 RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
271 if (clnt_stat != RPC_SUCCESS) {
272 clnt_perror(clp, "Bad MNT RPC");
273 return (1);
274 }
275 auth_destroy(clp->cl_auth);
276 clnt_destroy(clp);
277 }
278 return (0);
279 }
280
281 char *
282 getmntname(name, what, type)
283 char *name;
284 mntwhat what;
285 char **type;
286 {
287 static struct statfs *mntbuf;
288 static int mntsize;
289 int i;
290
291 if (mntbuf == NULL &&
292 (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
293 warn("getmntinfo");
294 return (NULL);
295 }
296 for (i = mntsize - 1; i >= 0; i--) {
297 if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
298 if (type)
299 *type = mntbuf[i].f_fstypename;
300 return (mntbuf[i].f_mntonname);
301 }
302 if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
303 if (type)
304 *type = mntbuf[i].f_fstypename;
305 return (mntbuf[i].f_mntfromname);
306 }
307 }
308 return (NULL);
309 }
310
311 int
312 namematch(hp)
313 struct hostent *hp;
314 {
315 char *cp, **np;
316
317 if ((hp == NULL) || (nfshost == NULL))
318 return (1);
319
320 if (strcasecmp(nfshost, hp->h_name) == 0)
321 return (1);
322
323 if ((cp = strchr(hp->h_name, '.')) != NULL) {
324 *cp = '\0';
325 if (strcasecmp(nfshost, hp->h_name) == 0)
326 return (1);
327 }
328 for (np = hp->h_aliases; *np; np++) {
329 if (strcasecmp(nfshost, *np) == 0)
330 return (1);
331 if ((cp = strchr(*np, '.')) != NULL) {
332 *cp = '\0';
333 if (strcasecmp(nfshost, *np) == 0)
334 return (1);
335 }
336 }
337 return (0);
338 }
339
340 /*
341 * xdr routines for mount rpc's
342 */
343 int
344 xdr_dir(xdrsp, dirp)
345 XDR *xdrsp;
346 char *dirp;
347 {
348 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
349 }
350
351 void
352 usage()
353 {
354 (void)fprintf(stderr,
355 "usage: %s\n %s\n",
356 "umount [-fvFR] [-t fstypelist] special | node",
357 "umount -a[fvF] [-h host] [-t fstypelist]");
358 exit(1);
359 }
360