xref: /original-bsd/sbin/umount/umount.c (revision 9c5e301d)
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 is permitted
6  * provided that all copyright information, including this notice,
7  * is retained in all such forms, and that any documentation,
8  * advertising or other materials related to such distribution and
9  * use acknowledge that the software was
10  * developed by the University of California, Berkeley.  The name
11  * of the University may not be used to endorse or promote products
12  * derived from this software without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17  */
18 
19 #ifndef lint
20 char copyright[] =
21 "@(#) Copyright (c) 1980, 1989 The Regents of the University of California.\n\
22  All rights reserved.\n";
23 #endif /* not lint */
24 
25 #ifndef lint
26 static char sccsid[] = "@(#)umount.c	5.14 (Berkeley) 02/27/91";
27 #endif /* not lint */
28 
29 #include <sys/param.h>
30 #include <sys/stat.h>
31 #include <sys/mount.h>
32 
33 #ifdef NFS
34 #include <sys/time.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <netdb.h>
38 #include <rpc/rpc.h>
39 #include <rpc/pmap_clnt.h>
40 #include <rpc/pmap_prot.h>
41 #include <nfs/rpcv2.h>
42 #endif
43 
44 #include <fstab.h>
45 #include <stdio.h>
46 #include <string.h>
47 
48 #ifdef NFS
49 int xdr_dir();
50 char *nfshost;
51 #endif
52 
53 int	vflag, all, errs, fake;
54 int	fflag = MNT_NOFORCE;
55 char	*getmntname();
56 
57 #define	MNTON	1
58 #define	MNTFROM	2
59 #define	MNTTYPE 3
60 
61 int *typelist, *maketypelist();
62 
63 main(argc, argv)
64 	int argc;
65 	char **argv;
66 {
67 	extern char *optarg;
68 	extern int optind;
69 	int ch;
70 
71 	sync();
72 	while ((ch = getopt(argc, argv, "afFh:t:v")) != EOF)
73 		switch((char)ch) {
74 		case 'v':
75 			vflag++;
76 			break;
77 		case 'f':
78 			fflag = MNT_FORCE;
79 			break;
80 		case 'F':
81 			fake++;
82 			break;
83 		case 'a':
84 			all++;
85 			break;
86 		case 't':
87 			typelist = maketypelist(optarg);
88 			break;
89 #ifdef	NFS
90 		case 'h':
91 			/* -h flag implies -a, and "-t nfs" if no -t flag */
92 			nfshost = optarg;
93 			all++;
94 			if (typelist == NULL)
95 				typelist = maketypelist("nfs");
96 			break;
97 #endif /* NFS */
98 		case '?':
99 		default:
100 			usage();
101 			/* NOTREACHED */
102 		}
103 	argc -= optind;
104 	argv += optind;
105 
106 	if (argc == 0 && !all)
107 		usage();
108 	if (all) {
109 		if (argc > 0)
110 			usage();
111 		if (setfsent() == 0)
112 			perror(FSTAB), exit(1);
113 		umountall(typelist);
114 		exit(0);
115 	} else
116 		setfsent();
117 	while (argc > 0) {
118 		if (umountfs(*argv++, 0) == 0)
119 			errs++;
120 		argc--;
121 	}
122 	exit(errs);
123 }
124 
125 usage()
126 {
127 	fprintf(stderr,
128 		"%s\n%s\n",
129 		"Usage: umount [-fv] special | node",
130 #ifndef	NFS
131 		"    or umount -a[fv] [-t fstypelist]"
132 #else
133 		"    or umount -a[fv] [-h host] [-t fstypelist]"
134 #endif
135 	      );
136 	exit(1);
137 }
138 
139 umountall(typelist)
140 	char **typelist;
141 {
142 	register struct fstab *fs;
143 	struct fstab *allocfsent();
144 
145 	if ((fs = getfsent()) == (struct fstab *)0)
146 		return;
147 	fs = allocfsent(fs);
148 	umountall(typelist);
149 	if (strcmp(fs->fs_file, "/") == 0) {
150 		freefsent(fs);
151 		return;
152 	}
153 	if (strcmp(fs->fs_type, FSTAB_RW) &&
154 	    strcmp(fs->fs_type, FSTAB_RO) &&
155 	    strcmp(fs->fs_type, FSTAB_RQ)) {
156 		freefsent(fs);
157 		return;
158 	}
159 	(void) umountfs(fs->fs_file, typelist);
160 	freefsent(fs);
161 }
162 
163 struct fstab *
164 allocfsent(fs)
165 	register struct fstab *fs;
166 {
167 	register struct fstab *new;
168 	register char *cp;
169 
170 	new = (struct fstab *)malloc((unsigned)sizeof (*fs));
171 	cp = (char *)malloc((unsigned)strlen(fs->fs_file) + 1);
172 	strcpy(cp, fs->fs_file);
173 	new->fs_file = cp;
174 	cp = (char *)malloc((unsigned)strlen(fs->fs_type) + 1);
175 	strcpy(cp, fs->fs_type);
176 	new->fs_type = cp;
177 	cp = (char *)malloc((unsigned)strlen(fs->fs_spec) + 1);
178 	strcpy(cp, fs->fs_spec);
179 	new->fs_spec = cp;
180 	new->fs_passno = fs->fs_passno;
181 	new->fs_freq = fs->fs_freq;
182 	return (new);
183 }
184 
185 freefsent(fs)
186 	register struct fstab *fs;
187 {
188 
189 	if (fs->fs_file)
190 		free(fs->fs_file);
191 	if (fs->fs_spec)
192 		free(fs->fs_spec);
193 	if (fs->fs_type)
194 		free(fs->fs_type);
195 	free((char *)fs);
196 }
197 
198 umountfs(name, typelist)
199 	char *name;
200 	int *typelist;
201 {
202 	char *mntpt;
203 	struct stat stbuf;
204 	int type;
205 #ifdef NFS
206 	register CLIENT *clp;
207 	struct hostent *hp = 0;
208 	struct sockaddr_in saddr;
209 	struct timeval pertry, try;
210 	enum clnt_stat clnt_stat;
211 	int so = RPC_ANYSOCK;
212 	char *hostp, *delimp;
213 #endif /* NFS */
214 
215 	if (stat(name, &stbuf) < 0) {
216 		if ((mntpt = getmntname(name, MNTON, &type)) == 0)
217 			return (0);
218 	} else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) {
219 		if ((mntpt = getmntname(name, MNTON, &type)) == 0)
220 			return (0);
221 	} else if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
222 		mntpt = name;
223 		if ((name = getmntname(mntpt, MNTFROM, &type)) == 0)
224 			return (0);
225 	} else {
226 		fprintf(stderr, "%s: not a directory or special device\n",
227 			name);
228 		return (0);
229 	}
230 
231 	if (badtype(type, typelist))
232 		return(1);
233 #ifdef NFS
234 	if ((delimp = index(name, '@')) != NULL) {
235 		hostp = delimp + 1;
236 		*delimp = '\0';
237 		hp = gethostbyname(hostp);
238 		*delimp = '@';
239 	} else if ((delimp = index(name, ':')) != NULL) {
240 		*delimp = '\0';
241 		hostp = name;
242 		hp = gethostbyname(hostp);
243 		name = delimp+1;
244 		*delimp = ':';
245 	}
246 
247 	if (!namematch(hp, nfshost))
248 		return(1);
249 #endif	/* NFS */
250 	if (!fake && unmount(mntpt, fflag) < 0) {
251 		perror(mntpt);
252 		return (0);
253 	}
254 	if (vflag)
255 		fprintf(stderr, "%s: Unmounted from %s\n", name, mntpt);
256 
257 #ifdef	NFS
258 	if (!fake && hp != NULL && (fflag & MNT_FORCE) == 0) {
259 		*delimp = '\0';
260 		bcopy(hp->h_addr,(caddr_t)&saddr.sin_addr,hp->h_length);
261 		saddr.sin_family = AF_INET;
262 		saddr.sin_port = 0;
263 		pertry.tv_sec = 3;
264 		pertry.tv_usec = 0;
265 		if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
266 		    pertry, &so)) == NULL) {
267 			clnt_pcreateerror("Cannot MNT PRC");
268 			return (1);
269 		}
270 		clp->cl_auth = authunix_create_default();
271 		try.tv_sec = 20;
272 		try.tv_usec = 0;
273 		clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, name,
274 			xdr_void, (caddr_t)0, try);
275 		if (clnt_stat != RPC_SUCCESS) {
276 			clnt_perror(clp, "Bad MNT RPC");
277 			return (1);
278 		}
279 		auth_destroy(clp->cl_auth);
280 		clnt_destroy(clp);
281 	}
282 #endif /* NFS */
283 	return (1);
284 }
285 
286 char *
287 getmntname(name, what, type)
288 	char *name;
289 	int what;
290 	int *type;
291 {
292 	int mntsize, i;
293 	struct statfs *mntbuf;
294 
295 	if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
296 		perror("umount");
297 		return (0);
298 	}
299 	for (i = 0; i < mntsize; i++) {
300 		if (what == MNTON && !strcmp(mntbuf[i].f_mntfromname, name)) {
301 			if (type)
302 				*type = mntbuf[i].f_type;
303 			return (mntbuf[i].f_mntonname);
304 		}
305 		if (what == MNTFROM && !strcmp(mntbuf[i].f_mntonname, name)) {
306 			if (type)
307 				*type = mntbuf[i].f_type;
308 			return (mntbuf[i].f_mntfromname);
309 		}
310 	}
311 	fprintf(stderr, "%s: not currently mounted\n", name);
312 	return (0);
313 }
314 
315 static int skipvfs;
316 
317 badtype(type, typelist)
318 	int type;
319 	int *typelist;
320 {
321 	if (typelist == 0)
322 		return(0);
323 	while (*typelist) {
324 		if (type == *typelist)
325 			return(skipvfs);
326 		typelist++;
327 	}
328 	return(!skipvfs);
329 }
330 
331 int *
332 maketypelist(fslist)
333 	char *fslist;
334 {
335 	register char *nextcp;
336 	register int *av, i;
337 
338 	if (fslist == NULL)
339 		return(NULL);
340 	if (fslist[0] == 'n' && fslist[1] == 'o') {
341 		fslist += 2;
342 		skipvfs = 1;
343 	} else
344 		skipvfs = 0;
345 	for (i = 0, nextcp = fslist; *nextcp; nextcp++)
346 		if (*nextcp == ',')
347 			i++;
348 	av = (int *)malloc((i+2) * sizeof(int));
349 	if (av == NULL)
350 		return(NULL);
351 	for (i = 0; fslist; fslist = nextcp) {
352 		if (nextcp = index(fslist, ','))
353 			*nextcp++ = '\0';
354 		if (strcmp(fslist, "ufs") == 0)
355 			av[i++] = MOUNT_UFS;
356 		else if (strcmp(fslist, "nfs") == 0)
357 			av[i++] = MOUNT_NFS;
358 		else if (strcmp(fslist, "mfs") == 0)
359 			av[i++] = MOUNT_MFS;
360 		else if (strcmp(fslist, "pc") == 0)
361 			av[i++] = MOUNT_PC;
362 	}
363 	av[i++] = 0;
364 	return(av);
365 }
366 
367 #ifdef	NFS
368 namematch(hp, nfshost)
369 	struct hostent *hp;
370 	char *nfshost;
371 {
372 	register char *cp;
373 	register char **np;
374 
375 	if (hp == NULL || nfshost == NULL)
376 		return(1);
377 	if (strcasecmp(nfshost, hp->h_name) == 0)
378 		return(1);
379 	if (cp = index(hp->h_name, '.')) {
380 		*cp = '\0';
381 		if (strcasecmp(nfshost, hp->h_name) == 0)
382 			return(1);
383 	}
384 	for (np = hp->h_aliases; *np; np++) {
385 		if (strcasecmp(nfshost, *np) == 0)
386 			return(1);
387 		if (cp = index(*np, '.')) {
388 			*cp = '\0';
389 			if (strcasecmp(nfshost, *np) == 0)
390 				return(1);
391 		}
392 	}
393 	return(0);
394 }
395 
396 /*
397  * xdr routines for mount rpc's
398  */
399 xdr_dir(xdrsp, dirp)
400 	XDR *xdrsp;
401 	char *dirp;
402 {
403 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
404 }
405 #endif /* NFS */
406