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