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