umount.c revision 1.6 1 /*-
2 * Copyright (c) 1980, 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1980, 1989 The Regents of the University of California.\n\
37 All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 /*static char sccsid[] = "from: @(#)umount.c 5.16 (Berkeley) 6/3/91";*/
42 static char rcsid[] = "$Id: umount.c,v 1.6 1994/04/14 03:25:38 cgd Exp $";
43 #endif /* not lint */
44
45 #include <sys/param.h>
46 #include <sys/stat.h>
47 #include <sys/mount.h>
48
49 #ifdef NFS
50 #include <sys/time.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <netdb.h>
54 #include <rpc/rpc.h>
55 #include <rpc/pmap_clnt.h>
56 #include <rpc/pmap_prot.h>
57 #include <nfs/rpcv2.h>
58 #endif
59
60 #include <err.h>
61 #include <fstab.h>
62 #include <stdio.h>
63 #include <string.h>
64 #include <stdlib.h>
65 #include <unistd.h>
66
67 #ifdef NFS
68 char *nfshost;
69 #endif
70
71 int vflag, all, errs, fake;
72 int fflag = MNT_NOFORCE;
73
74 #define MNTON 1
75 #define MNTFROM 2
76 #define MNTTYPE 3
77
78 char **typelist;
79
80 struct fstab *allocfsent __P((struct fstab *));
81 int badtype __P((char *, char **));
82 void freefsent __P((struct fstab *));
83 char *getmntname __P((char *, int, char *));
84 char **maketypelist __P((char *));
85 void umountall __P((char **));
86 int umountfs __P((char *, char **, int));
87 void usage __P((void));
88 #ifdef NFS
89 int namematch __P((struct hostent *, char *));
90 int xdr_dir __P((XDR *, char *));
91 #endif
92
93 int
94 main(argc, argv)
95 int argc;
96 char **argv;
97 {
98 extern char *optarg;
99 extern int optind;
100 int ch;
101
102 sync();
103 while ((ch = getopt(argc, argv, "afFh:t:v")) != EOF)
104 switch((char)ch) {
105 case 'v':
106 vflag++;
107 break;
108 case 'f':
109 fflag = MNT_FORCE;
110 break;
111 case 'F':
112 fake++;
113 break;
114 case 'a':
115 all++;
116 break;
117 case 't':
118 typelist = maketypelist(optarg);
119 break;
120 #ifdef NFS
121 case 'h':
122 /* -h flag implies -a, and "-t nfs" if no -t flag */
123 nfshost = optarg;
124 all++;
125 if (typelist == NULL)
126 typelist = maketypelist(MOUNT_NFS);
127 break;
128 #endif /* NFS */
129 case '?':
130 default:
131 usage();
132 /* NOTREACHED */
133 }
134 argc -= optind;
135 argv += optind;
136
137 if (argc == 0 && !all)
138 usage();
139 if (all) {
140 if (argc > 0)
141 usage();
142 if (setfsent() == 0)
143 err(1, "%s", FSTAB);
144 umountall(typelist);
145 exit(0);
146 } else
147 setfsent();
148 while (argc > 0) {
149 if (umountfs(*argv++, 0, 0) == 0)
150 errs++;
151 argc--;
152 }
153 exit(errs);
154 }
155
156 void
157 usage()
158 {
159 fprintf(stderr,
160 "%s\n%s\n",
161 "Usage: umount [-fv] special | node",
162 #ifndef NFS
163 " or umount -a[fv] [-t fstypelist]"
164 #else
165 " or umount -a[fv] [-h host] [-t fstypelist]"
166 #endif
167 );
168 exit(1);
169 }
170
171 void
172 umountall(typelist)
173 char **typelist;
174 {
175 register struct fstab *fs;
176 struct fstab *allocfsent();
177
178 if ((fs = getfsent()) == (struct fstab *)0)
179 return;
180 fs = allocfsent(fs);
181 umountall(typelist);
182 if (strcmp(fs->fs_file, "/") == 0) {
183 freefsent(fs);
184 return;
185 }
186 if (strcmp(fs->fs_type, FSTAB_RW) &&
187 strcmp(fs->fs_type, FSTAB_RO) &&
188 strcmp(fs->fs_type, FSTAB_RQ)) {
189 freefsent(fs);
190 return;
191 }
192 (void) umountfs(fs->fs_file, typelist, 1);
193 freefsent(fs);
194 }
195
196 struct fstab *
197 allocfsent(fs)
198 register struct fstab *fs;
199 {
200 register struct fstab *new;
201 register char *cp;
202
203 new = (struct fstab *)malloc((unsigned)sizeof (*fs));
204 cp = (char *)malloc((unsigned)strlen(fs->fs_file) + 1);
205 strcpy(cp, fs->fs_file);
206 new->fs_file = cp;
207 cp = (char *)malloc((unsigned)strlen(fs->fs_type) + 1);
208 strcpy(cp, fs->fs_type);
209 new->fs_type = cp;
210 cp = (char *)malloc((unsigned)strlen(fs->fs_spec) + 1);
211 strcpy(cp, fs->fs_spec);
212 new->fs_spec = cp;
213 new->fs_passno = fs->fs_passno;
214 new->fs_freq = fs->fs_freq;
215 return (new);
216 }
217
218 void
219 freefsent(fs)
220 register struct fstab *fs;
221 {
222
223 if (fs->fs_file != NULL)
224 free(fs->fs_file);
225 if (fs->fs_spec != NULL)
226 free(fs->fs_spec);
227 if (fs->fs_type != NULL)
228 free(fs->fs_type);
229 free((char *)fs);
230 }
231
232 int
233 umountfs(name, typelist, all)
234 char *name;
235 char **typelist;
236 int all;
237 {
238 char *mntpt;
239 struct stat stbuf;
240 char type[MFSNAMELEN+1];
241 #ifdef NFS
242 register CLIENT *clp;
243 struct hostent *hp = 0;
244 struct sockaddr_in saddr;
245 struct timeval pertry, try;
246 enum clnt_stat clnt_stat;
247 int so = RPC_ANYSOCK;
248 char *hostp, *delimp;
249 #endif /* NFS */
250
251 if (stat(name, &stbuf) < 0) {
252 if (getmntname(name, MNTFROM, type) != 0)
253 mntpt = name;
254 else if ((mntpt = getmntname(name, MNTON, type)) == 0) {
255 if (!all)
256 warnx("%s: not currently mounted\n", name);
257 return (0);
258 }
259 } else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) {
260 if ((mntpt = getmntname(name, MNTON, type)) == 0) {
261 if (!all)
262 warnx("%s: not currently mounted\n", name);
263 return (0);
264 }
265 } else if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
266 mntpt = name;
267 if (getmntname(mntpt, MNTFROM, type) == 0) {
268 if (!all)
269 warnx("%s: not currently mounted\n", name);
270 return (0);
271 }
272 } else {
273 if (!all)
274 warnx("%s: not a directory or special device\n", name);
275 return (0);
276 }
277
278 if (badtype(type, typelist))
279 return(1);
280 #ifdef NFS
281 if ((delimp = strchr(name, '@')) != NULL) {
282 hostp = delimp + 1;
283 *delimp = '\0';
284 hp = gethostbyname(hostp);
285 *delimp = '@';
286 } else if ((delimp = strchr(name, ':')) != NULL) {
287 *delimp = '\0';
288 hostp = name;
289 hp = gethostbyname(hostp);
290 name = delimp+1;
291 *delimp = ':';
292 }
293
294 if (!namematch(hp, nfshost))
295 return(1);
296 #endif /* NFS */
297 if (!fake && unmount(mntpt, fflag) < 0) {
298 warn("%s", mntpt);
299 return (0);
300 }
301 if (vflag)
302 fprintf(stderr, "%s: Unmounted from %s\n", name, mntpt);
303
304 #ifdef NFS
305 if (!fake && hp != NULL && (fflag & MNT_FORCE) == 0) {
306 *delimp = '\0';
307 bzero((char *)&saddr, sizeof saddr);
308 bcopy(hp->h_addr,(caddr_t)&saddr.sin_addr,hp->h_length);
309 saddr.sin_family = AF_INET;
310 saddr.sin_port = 0;
311 pertry.tv_sec = 3;
312 pertry.tv_usec = 0;
313 if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
314 pertry, &so)) == NULL) {
315 clnt_pcreateerror("Cannot MNT PRC");
316 return (1);
317 }
318 clp->cl_auth = authunix_create_default();
319 try.tv_sec = 20;
320 try.tv_usec = 0;
321 clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, name,
322 xdr_void, (caddr_t)0, try);
323 if (clnt_stat != RPC_SUCCESS) {
324 clnt_perror(clp, "Bad MNT RPC");
325 return (1);
326 }
327 auth_destroy(clp->cl_auth);
328 clnt_destroy(clp);
329 }
330 #endif /* NFS */
331 return (1);
332 }
333
334 char *
335 getmntname(name, what, type)
336 char *name;
337 int what;
338 char *type;
339 {
340 int mntsize, i;
341 struct statfs *mntbuf;
342
343 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
344 warn("umount");
345 return (0);
346 }
347 for (i = 0; i < mntsize; i++) {
348 if (what == MNTON && !strcmp(mntbuf[i].f_mntfromname, name)) {
349 if (type) {
350 strncpy(type, mntbuf[i].f_fstypename,
351 MFSNAMELEN);
352 type[MFSNAMELEN] = '\0';
353 }
354 return (mntbuf[i].f_mntonname);
355 }
356 if (what == MNTFROM && !strcmp(mntbuf[i].f_mntonname, name)) {
357 if (type) {
358 strncpy(type, mntbuf[i].f_fstypename,
359 MFSNAMELEN);
360 type[MFSNAMELEN] = '\0';
361 }
362 return (mntbuf[i].f_mntfromname);
363 }
364 }
365 return (0);
366 }
367
368 static int skipvfs;
369
370 int
371 badtype(type, typelist)
372 char *type;
373 char **typelist;
374 {
375 if (typelist == NULL)
376 return(0);
377 while (*typelist) {
378 if (!strcmp(type, *typelist))
379 return(skipvfs);
380 typelist++;
381 }
382 return(!skipvfs);
383 }
384
385 char **
386 maketypelist(fslist)
387 char *fslist;
388 {
389 register char *nextcp, **av;
390 register int i;
391
392 if (fslist == NULL)
393 return(NULL);
394 if (fslist[0] == 'n' && fslist[1] == 'o') {
395 fslist += 2;
396 skipvfs = 1;
397 } else
398 skipvfs = 0;
399 for (i = 0, nextcp = fslist; *nextcp; nextcp++)
400 if (*nextcp == ',')
401 i++;
402 av = (char **)malloc((i+2) * sizeof(int));
403 if (av == NULL)
404 return(NULL);
405 for (i = 0; fslist; fslist = nextcp) {
406 if ((nextcp = strchr(fslist, ',')) != NULL)
407 *nextcp++ = '\0';
408 av[i++] = strdup(fslist);
409 }
410 av[i++] = 0;
411 return(av);
412 }
413
414 #ifdef NFS
415 int
416 namematch(hp, nfshost)
417 struct hostent *hp;
418 char *nfshost;
419 {
420 register char *cp;
421 register char **np;
422
423 if (hp == NULL || nfshost == NULL)
424 return(1);
425 if (strcasecmp(nfshost, hp->h_name) == 0)
426 return(1);
427 if ((cp = strchr(hp->h_name, '.')) != NULL) {
428 *cp = '\0';
429 if (strcasecmp(nfshost, hp->h_name) == 0)
430 return(1);
431 }
432 for (np = hp->h_aliases; *np; np++) {
433 if (strcasecmp(nfshost, *np) == 0)
434 return(1);
435 if ((cp = strchr(*np, '.')) != NULL) {
436 *cp = '\0';
437 if (strcasecmp(nfshost, *np) == 0)
438 return(1);
439 }
440 }
441 return(0);
442 }
443
444 /*
445 * xdr routines for mount rpc's
446 */
447 int
448 xdr_dir(xdrsp, dirp)
449 XDR *xdrsp;
450 char *dirp;
451 {
452 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
453 }
454 #endif /* NFS */
455