xref: /original-bsd/sbin/umount/umount.c (revision 0e8defd9)
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.15 (Berkeley) 04/16/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 ((mntpt = getmntname(name, MNTON, &type)) == 0)
206 			return (0);
207 	} else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) {
208 		if ((mntpt = getmntname(name, MNTON, &type)) == 0)
209 			return (0);
210 	} else if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
211 		mntpt = name;
212 		if ((name = getmntname(mntpt, MNTFROM, &type)) == 0)
213 			return (0);
214 	} else {
215 		fprintf(stderr, "%s: not a directory or special device\n",
216 			name);
217 		return (0);
218 	}
219 
220 	if (badtype(type, typelist))
221 		return(1);
222 #ifdef NFS
223 	if ((delimp = index(name, '@')) != NULL) {
224 		hostp = delimp + 1;
225 		*delimp = '\0';
226 		hp = gethostbyname(hostp);
227 		*delimp = '@';
228 	} else if ((delimp = index(name, ':')) != NULL) {
229 		*delimp = '\0';
230 		hostp = name;
231 		hp = gethostbyname(hostp);
232 		name = delimp+1;
233 		*delimp = ':';
234 	}
235 
236 	if (!namematch(hp, nfshost))
237 		return(1);
238 #endif	/* NFS */
239 	if (!fake && unmount(mntpt, fflag) < 0) {
240 		perror(mntpt);
241 		return (0);
242 	}
243 	if (vflag)
244 		fprintf(stderr, "%s: Unmounted from %s\n", name, mntpt);
245 
246 #ifdef	NFS
247 	if (!fake && hp != NULL && (fflag & MNT_FORCE) == 0) {
248 		*delimp = '\0';
249 		bcopy(hp->h_addr,(caddr_t)&saddr.sin_addr,hp->h_length);
250 		saddr.sin_family = AF_INET;
251 		saddr.sin_port = 0;
252 		pertry.tv_sec = 3;
253 		pertry.tv_usec = 0;
254 		if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
255 		    pertry, &so)) == NULL) {
256 			clnt_pcreateerror("Cannot MNT PRC");
257 			return (1);
258 		}
259 		clp->cl_auth = authunix_create_default();
260 		try.tv_sec = 20;
261 		try.tv_usec = 0;
262 		clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, name,
263 			xdr_void, (caddr_t)0, try);
264 		if (clnt_stat != RPC_SUCCESS) {
265 			clnt_perror(clp, "Bad MNT RPC");
266 			return (1);
267 		}
268 		auth_destroy(clp->cl_auth);
269 		clnt_destroy(clp);
270 	}
271 #endif /* NFS */
272 	return (1);
273 }
274 
275 char *
276 getmntname(name, what, type)
277 	char *name;
278 	int what;
279 	int *type;
280 {
281 	int mntsize, i;
282 	struct statfs *mntbuf;
283 
284 	if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
285 		perror("umount");
286 		return (0);
287 	}
288 	for (i = 0; i < mntsize; i++) {
289 		if (what == MNTON && !strcmp(mntbuf[i].f_mntfromname, name)) {
290 			if (type)
291 				*type = mntbuf[i].f_type;
292 			return (mntbuf[i].f_mntonname);
293 		}
294 		if (what == MNTFROM && !strcmp(mntbuf[i].f_mntonname, name)) {
295 			if (type)
296 				*type = mntbuf[i].f_type;
297 			return (mntbuf[i].f_mntfromname);
298 		}
299 	}
300 	fprintf(stderr, "%s: not currently mounted\n", name);
301 	return (0);
302 }
303 
304 static int skipvfs;
305 
306 badtype(type, typelist)
307 	int type;
308 	int *typelist;
309 {
310 	if (typelist == 0)
311 		return(0);
312 	while (*typelist) {
313 		if (type == *typelist)
314 			return(skipvfs);
315 		typelist++;
316 	}
317 	return(!skipvfs);
318 }
319 
320 int *
321 maketypelist(fslist)
322 	char *fslist;
323 {
324 	register char *nextcp;
325 	register int *av, i;
326 
327 	if (fslist == NULL)
328 		return(NULL);
329 	if (fslist[0] == 'n' && fslist[1] == 'o') {
330 		fslist += 2;
331 		skipvfs = 1;
332 	} else
333 		skipvfs = 0;
334 	for (i = 0, nextcp = fslist; *nextcp; nextcp++)
335 		if (*nextcp == ',')
336 			i++;
337 	av = (int *)malloc((i+2) * sizeof(int));
338 	if (av == NULL)
339 		return(NULL);
340 	for (i = 0; fslist; fslist = nextcp) {
341 		if (nextcp = index(fslist, ','))
342 			*nextcp++ = '\0';
343 		if (strcmp(fslist, "ufs") == 0)
344 			av[i++] = MOUNT_UFS;
345 		else if (strcmp(fslist, "nfs") == 0)
346 			av[i++] = MOUNT_NFS;
347 		else if (strcmp(fslist, "mfs") == 0)
348 			av[i++] = MOUNT_MFS;
349 		else if (strcmp(fslist, "pc") == 0)
350 			av[i++] = MOUNT_PC;
351 	}
352 	av[i++] = 0;
353 	return(av);
354 }
355 
356 #ifdef	NFS
357 namematch(hp, nfshost)
358 	struct hostent *hp;
359 	char *nfshost;
360 {
361 	register char *cp;
362 	register char **np;
363 
364 	if (hp == NULL || nfshost == NULL)
365 		return(1);
366 	if (strcasecmp(nfshost, hp->h_name) == 0)
367 		return(1);
368 	if (cp = index(hp->h_name, '.')) {
369 		*cp = '\0';
370 		if (strcasecmp(nfshost, hp->h_name) == 0)
371 			return(1);
372 	}
373 	for (np = hp->h_aliases; *np; np++) {
374 		if (strcasecmp(nfshost, *np) == 0)
375 			return(1);
376 		if (cp = index(*np, '.')) {
377 			*cp = '\0';
378 			if (strcasecmp(nfshost, *np) == 0)
379 				return(1);
380 		}
381 	}
382 	return(0);
383 }
384 
385 /*
386  * xdr routines for mount rpc's
387  */
388 xdr_dir(xdrsp, dirp)
389 	XDR *xdrsp;
390 	char *dirp;
391 {
392 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
393 }
394 #endif /* NFS */
395