umount.c revision 1.22 1 /* $NetBSD: umount.c,v 1.22 1997/12/18 07:11:49 mikel 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.22 1997/12/18 07:11:49 mikel 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 #include <sys/socketvar.h>
56
57 #include <netdb.h>
58 #include <rpc/rpc.h>
59 #include <rpc/pmap_clnt.h>
60 #include <rpc/pmap_prot.h>
61 #include <nfs/rpcv2.h>
62
63 #include <err.h>
64 #include <fstab.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <unistd.h>
69
70 typedef enum { MNTANY, MNTON, MNTFROM } mntwhat;
71
72 int fake, fflag, verbose;
73 char *nfshost;
74
75 int checkvfsname __P((const char *, char **));
76 char *getmntname __P((char *, mntwhat, char **));
77 char **makevfslist __P((char *));
78 int main __P((int, char *[]));
79 int namematch __P((struct hostent *));
80 int selected __P((int));
81 int umountall __P((char **));
82 int umountfs __P((char *, char **));
83 void usage __P((void));
84 int xdr_dir __P((XDR *, char *));
85
86 int
87 main(argc, argv)
88 int argc;
89 char *argv[];
90 {
91 int all, ch, errs, mnts;
92 char **typelist = NULL;
93 struct statfs *mntbuf;
94
95 /* Start disks transferring immediately. */
96 sync();
97
98 all = 0;
99 while ((ch = getopt(argc, argv, "AaFfh:t:v")) != -1)
100 switch (ch) {
101 case 'A':
102 all = 2;
103 break;
104 case 'a':
105 all = 1;
106 break;
107 case 'F':
108 fake = 1;
109 break;
110 case 'f':
111 fflag = MNT_FORCE;
112 break;
113 case 'h': /* -h implies -A. */
114 all = 2;
115 nfshost = optarg;
116 break;
117 case 't':
118 if (typelist != NULL)
119 errx(1, "only one -t option may be specified.");
120 typelist = makevfslist(optarg);
121 break;
122 case 'v':
123 verbose = 1;
124 break;
125 default:
126 usage();
127 /* NOTREACHED */
128 }
129 argc -= optind;
130 argv += optind;
131
132 if ((argc == 0 && !all) || (argc != 0 && all))
133 usage();
134
135 /* -h implies "-t nfs" if no -t flag. */
136 if ((nfshost != NULL) && (typelist == NULL))
137 typelist = makevfslist("nfs");
138
139 errs = 0;
140 switch (all) {
141 case 2:
142 if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
143 warn("getmntinfo");
144 errs = 1;
145 break;
146 }
147 for (errs = 0, mnts--; mnts > 0; mnts--) {
148 if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
149 continue;
150 if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
151 errs = 1;
152 }
153 break;
154 case 1:
155 if (setfsent() == 0)
156 err(1, "%s", _PATH_FSTAB);
157 errs = umountall(typelist);
158 break;
159 case 0:
160 for (errs = 0; *argv != NULL; ++argv)
161 if (umountfs(*argv, typelist) != 0)
162 errs = 1;
163 break;
164 }
165 exit(errs);
166 }
167
168
169 int
170 umountall(typelist)
171 char **typelist;
172 {
173 struct statfs *fs;
174 int n;
175 int rval;
176
177 n = getmntinfo(&fs, MNT_NOWAIT);
178 if (n == 0)
179 err(1, "%s", "");
180
181 rval = 0;
182 while (--n >= 0) {
183 /* Ignore the root. */
184 if (strncmp(fs[n].f_mntonname, "/", MNAMELEN) == 0)
185 continue;
186
187 if (checkvfsname(fs[n].f_fstypename, typelist))
188 continue;
189
190 if (umountfs(fs[n].f_mntonname, typelist))
191 rval = 1;
192 }
193 return (rval);
194 }
195
196 int
197 umountfs(name, typelist)
198 char *name;
199 char **typelist;
200 {
201 enum clnt_stat clnt_stat;
202 struct hostent *hp;
203 struct sockaddr_in saddr;
204 struct stat sb;
205 struct timeval pertry, try;
206 CLIENT *clp;
207 int so;
208 char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN];
209 mntwhat what;
210
211 hp = NULL;
212 delimp = NULL;
213 if (realpath(name, rname) == NULL) {
214 warn("%s", rname);
215 return (1);
216 }
217
218 what = MNTANY;
219 mntpt = name = rname;
220
221 if (stat(name, &sb) == 0) {
222 if (S_ISBLK(sb.st_mode))
223 what = MNTON;
224 else if (S_ISDIR(sb.st_mode))
225 what = MNTFROM;
226 }
227
228 switch (what) {
229 case MNTON:
230 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
231 warnx("%s: not currently mounted", name);
232 return (1);
233 }
234 break;
235 case MNTFROM:
236 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
237 warnx("%s: not currently mounted", mntpt);
238 return (1);
239 }
240 break;
241 default:
242 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
243 name = rname;
244 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
245 warnx("%s: not currently mounted", name);
246 return (1);
247 }
248 }
249 }
250
251 if (checkvfsname(type, typelist))
252 return (1);
253
254 hp = NULL;
255 if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
256 if ((delimp = strchr(name, '@')) != NULL) {
257 hostp = delimp + 1;
258 *delimp = '\0';
259 hp = gethostbyname(hostp);
260 *delimp = '@';
261 } else if ((delimp = strchr(name, ':')) != NULL) {
262 *delimp = '\0';
263 hostp = name;
264 hp = gethostbyname(hostp);
265 name = delimp + 1;
266 *delimp = ':';
267 }
268 }
269
270 if (!namematch(hp))
271 return (1);
272
273 if (verbose)
274 (void)printf("%s: unmount from %s\n", name, mntpt);
275 if (fake)
276 return (0);
277
278 if (unmount(mntpt, fflag) < 0) {
279 warn("%s", mntpt);
280 return (1);
281 }
282
283 if (!strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
284 (hp != NULL) && !(fflag & MNT_FORCE)) {
285 *delimp = '\0';
286 memset(&saddr, 0, sizeof(saddr));
287 saddr.sin_family = AF_INET;
288 saddr.sin_port = 0;
289 memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
290 pertry.tv_sec = 3;
291 pertry.tv_usec = 0;
292 so = RPC_ANYSOCK;
293 if ((clp = clntudp_create(&saddr,
294 RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
295 clnt_pcreateerror("Cannot MNT PRC");
296 return (1);
297 }
298 clp->cl_auth = authunix_create_default();
299 try.tv_sec = 20;
300 try.tv_usec = 0;
301 clnt_stat = clnt_call(clp,
302 RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
303 if (clnt_stat != RPC_SUCCESS) {
304 clnt_perror(clp, "Bad MNT RPC");
305 return (1);
306 }
307 auth_destroy(clp->cl_auth);
308 clnt_destroy(clp);
309 }
310 return (0);
311 }
312
313 char *
314 getmntname(name, what, type)
315 char *name;
316 mntwhat what;
317 char **type;
318 {
319 static struct statfs *mntbuf;
320 static int mntsize;
321 int i;
322
323 if (mntbuf == NULL &&
324 (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
325 warn("getmntinfo");
326 return (NULL);
327 }
328 for (i = mntsize - 1; i >= 0; i--) {
329 if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
330 if (type)
331 *type = mntbuf[i].f_fstypename;
332 return (mntbuf[i].f_mntonname);
333 }
334 if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
335 if (type)
336 *type = mntbuf[i].f_fstypename;
337 return (mntbuf[i].f_mntfromname);
338 }
339 }
340 return (NULL);
341 }
342
343 int
344 namematch(hp)
345 struct hostent *hp;
346 {
347 char *cp, **np;
348
349 if ((hp == NULL) || (nfshost == NULL))
350 return (1);
351
352 if (strcasecmp(nfshost, hp->h_name) == 0)
353 return (1);
354
355 if ((cp = strchr(hp->h_name, '.')) != NULL) {
356 *cp = '\0';
357 if (strcasecmp(nfshost, hp->h_name) == 0)
358 return (1);
359 }
360 for (np = hp->h_aliases; *np; np++) {
361 if (strcasecmp(nfshost, *np) == 0)
362 return (1);
363 if ((cp = strchr(*np, '.')) != NULL) {
364 *cp = '\0';
365 if (strcasecmp(nfshost, *np) == 0)
366 return (1);
367 }
368 }
369 return (0);
370 }
371
372 /*
373 * xdr routines for mount rpc's
374 */
375 int
376 xdr_dir(xdrsp, dirp)
377 XDR *xdrsp;
378 char *dirp;
379 {
380 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
381 }
382
383 void
384 usage()
385 {
386 (void)fprintf(stderr,
387 "usage: %s\n %s\n",
388 "umount [-fvF] [-t fstypelist] special | node",
389 "umount -a[fvF] [-h host] [-t fstypelist]");
390 exit(1);
391 }
392