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