xref: /csrg-svn/sbin/umount/umount.c (revision 69305)
148132Sbostic /*-
261558Sbostic  * Copyright (c) 1980, 1989, 1993
361558Sbostic  *	The Regents of the University of California.  All rights reserved.
439890Smckusick  *
548132Sbostic  * %sccs.include.redist.c%
621185Sdist  */
721185Sdist 
812808Ssam #ifndef lint
961558Sbostic static char copyright[] =
1061558Sbostic "@(#) Copyright (c) 1980, 1989, 1993\n\
1161558Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1239890Smckusick #endif /* not lint */
136007Swnj 
1421185Sdist #ifndef lint
15*69305Smckusick static char sccsid[] = "@(#)umount.c	8.8 (Berkeley) 05/08/95";
1639890Smckusick #endif /* not lint */
1721185Sdist 
1812808Ssam #include <sys/param.h>
1938640Smckusick #include <sys/stat.h>
2038446Smckusick #include <sys/mount.h>
2138446Smckusick #include <sys/time.h>
2238446Smckusick #include <sys/socket.h>
2338446Smckusick #include <sys/socketvar.h>
2466166Sbostic 
2538446Smckusick #include <netdb.h>
2638446Smckusick #include <rpc/rpc.h>
2738446Smckusick #include <rpc/pmap_clnt.h>
2838446Smckusick #include <rpc/pmap_prot.h>
2938446Smckusick #include <nfs/rpcv2.h>
301141Sbill 
3166153Spendry #include <err.h>
3246723Sbostic #include <fstab.h>
3346723Sbostic #include <stdio.h>
3466153Spendry #include <stdlib.h>
3546723Sbostic #include <string.h>
3666153Spendry #include <unistd.h>
3746723Sbostic 
3866153Spendry typedef enum { MNTON, MNTFROM } mntwhat;
3966153Spendry 
4069303Smckusick int	fake, fflag, vflag;
4166166Sbostic char	*nfshost;
4246723Sbostic 
4369303Smckusick int	 checkvfsname __P((const char *, char **));
4469303Smckusick char	*getmntname __P((char *, mntwhat, char **));
4569303Smckusick char	**makevfslist __P((char *));
4666166Sbostic int	 selected __P((int));
4766166Sbostic int	 namematch __P((struct hostent *));
4869303Smckusick int	 umountall __P((char **));
4969303Smckusick int	 umountfs __P((char *, char **));
5066166Sbostic void	 usage __P((void));
5166166Sbostic int	 xdr_dir __P((XDR *, char *));
526007Swnj 
5366153Spendry int
main(argc,argv)541141Sbill main(argc, argv)
556007Swnj 	int argc;
5666166Sbostic 	char *argv[];
571141Sbill {
58*69305Smckusick 	int all, ch, errs, mnts;
5969303Smckusick 	char **typelist = NULL;
60*69305Smckusick 	struct statfs *mntbuf;
611141Sbill 
6266166Sbostic 	/* Start disks transferring immediately. */
631141Sbill 	sync();
6466166Sbostic 
6566166Sbostic 	all = 0;
66*69305Smckusick 	while ((ch = getopt(argc, argv, "AaFfh:t:v")) != EOF)
6766153Spendry 		switch (ch) {
68*69305Smckusick 		case 'A':
69*69305Smckusick 			all = 2;
70*69305Smckusick 			break;
7166153Spendry 		case 'a':
7266166Sbostic 			all = 1;
7340062Smckusick 			break;
7466166Sbostic 		case 'F':
7566166Sbostic 			fake = 1;
7666166Sbostic 			break;
7740062Smckusick 		case 'f':
7840062Smckusick 			fflag = MNT_FORCE;
7940062Smckusick 			break;
80*69305Smckusick 		case 'h':	/* -h implies -A. */
81*69305Smckusick 			all = 2;
8240062Smckusick 			nfshost = optarg;
8340062Smckusick 			break;
8466153Spendry 		case 't':
8569303Smckusick 			if (typelist != NULL)
8669303Smckusick 				errx(1, "only one -t option may be specified.");
8769303Smckusick 			typelist = makevfslist(optarg);
8866153Spendry 			break;
8966153Spendry 		case 'v':
9066166Sbostic 			vflag = 1;
9166153Spendry 			break;
9240062Smckusick 		default:
9340062Smckusick 			usage();
9440062Smckusick 			/* NOTREACHED */
9540062Smckusick 		}
9640062Smckusick 	argc -= optind;
9740062Smckusick 	argv += optind;
9840062Smckusick 
9966166Sbostic 	if (argc == 0 && !all || argc != 0 && all)
10040062Smckusick 		usage();
10166153Spendry 
10266166Sbostic 	/* -h implies "-t nfs" if no -t flag. */
10366166Sbostic 	if ((nfshost != NULL) && (typelist == NULL))
10469303Smckusick 		typelist = makevfslist("nfs");
10566166Sbostic 
106*69305Smckusick 	switch (all) {
107*69305Smckusick 	case 2:
108*69305Smckusick 		if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
109*69305Smckusick 			warn("getmntinfo");
110*69305Smckusick 			errs = 1;
111*69305Smckusick 			break;
112*69305Smckusick 		}
113*69305Smckusick 		for (errs = 0, mnts--; mnts > 0; mnts--) {
114*69305Smckusick 			if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
115*69305Smckusick 				continue;
116*69305Smckusick 			if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
117*69305Smckusick 				errs = 1;
118*69305Smckusick 		}
119*69305Smckusick 		break;
120*69305Smckusick 	case 1:
12166166Sbostic 		if (setfsent() == 0)
12266166Sbostic 			err(1, "%s", _PATH_FSTAB);
12369303Smckusick 		errs = umountall(typelist);
124*69305Smckusick 		break;
125*69305Smckusick 	case 0:
12666166Sbostic 		for (errs = 0; *argv != NULL; ++argv)
12769303Smckusick 			if (umountfs(*argv, typelist) != 0)
12866166Sbostic 				errs = 1;
129*69305Smckusick 		break;
130*69305Smckusick 	}
13166166Sbostic 	exit(errs);
1321141Sbill }
1336007Swnj 
13466166Sbostic int
umountall(typelist)13569303Smckusick umountall(typelist)
13669303Smckusick 	char **typelist;
1371446Sbill {
13866166Sbostic 	struct fstab *fs;
13966166Sbostic 	int rval, type;
14054873Smckusick 	char *cp;
14169303Smckusick 	struct vfsconf vfc;
14240062Smckusick 
14366166Sbostic 	while ((fs = getfsent()) != NULL) {
14466166Sbostic 		/* Ignore the root. */
14554873Smckusick 		if (strcmp(fs->fs_file, "/") == 0)
14654873Smckusick 			continue;
14766166Sbostic 		/*
14866166Sbostic 		 * !!!
14966166Sbostic 		 * Historic practice: ignore unknown FSTAB_* fields.
15066166Sbostic 		 */
15154873Smckusick 		if (strcmp(fs->fs_type, FSTAB_RW) &&
15254873Smckusick 		    strcmp(fs->fs_type, FSTAB_RO) &&
15354873Smckusick 		    strcmp(fs->fs_type, FSTAB_RQ))
15454873Smckusick 			continue;
15566166Sbostic 		/* If an unknown file system type, complain. */
15669303Smckusick 		if (getvfsbyname(fs->fs_vfstype, &vfc) < 0) {
15766166Sbostic 			warnx("%s: unknown mount type", fs->fs_vfstype);
15866166Sbostic 			continue;
15966166Sbostic 		}
16069303Smckusick 		if (checkvfsname(fs->fs_vfstype, typelist))
16166166Sbostic 			continue;
16266166Sbostic 
16366166Sbostic 		/*
16466166Sbostic 		 * We want to unmount the file systems in the reverse order
16566166Sbostic 		 * that they were mounted.  So, we save off the file name
16666166Sbostic 		 * in some allocated memory, and then call recursively.
16766166Sbostic 		 */
16866166Sbostic 		if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL)
16966166Sbostic 			err(1, NULL);
17066166Sbostic 		(void)strcpy(cp, fs->fs_file);
17169303Smckusick 		rval = umountall(typelist);
17269303Smckusick 		return (umountfs(cp, typelist) || rval);
17312808Ssam 	}
17466166Sbostic 	return (0);
1751446Sbill }
1761141Sbill 
17766153Spendry int
umountfs(name,typelist)17869303Smckusick umountfs(name, typelist)
1796007Swnj 	char *name;
18069303Smckusick 	char **typelist;
1811141Sbill {
18266153Spendry 	enum clnt_stat clnt_stat;
18366166Sbostic 	struct hostent *hp;
18438446Smckusick 	struct sockaddr_in saddr;
18566166Sbostic 	struct stat sb;
18638446Smckusick 	struct timeval pertry, try;
18766166Sbostic 	CLIENT *clp;
18869303Smckusick 	int so;
18969303Smckusick 	char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN];
1901141Sbill 
19166153Spendry 	if (realpath(name, rname) == NULL) {
19266153Spendry 		warn("%s", rname);
19367792Smckusick 		return (1);
19466153Spendry 	}
19566153Spendry 
19666153Spendry 	name = rname;
19766153Spendry 
19866166Sbostic 	if (stat(name, &sb) < 0) {
19966166Sbostic 		if (((mntpt = getmntname(name, MNTFROM, &type)) == NULL) &&
20066166Sbostic 		    ((mntpt = getmntname(name, MNTON, &type)) == NULL)) {
20166153Spendry 			warnx("%s: not currently mounted", name);
20266166Sbostic 			return (1);
20349967Smckusick 		}
20466166Sbostic 	} else if (S_ISBLK(sb.st_mode)) {
20566166Sbostic 		if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
20666153Spendry 			warnx("%s: not currently mounted", name);
20766166Sbostic 			return (1);
20849967Smckusick 		}
20966166Sbostic 	} else if (S_ISDIR(sb.st_mode)) {
21038640Smckusick 		mntpt = name;
21166166Sbostic 		if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
21266153Spendry 			warnx("%s: not currently mounted", mntpt);
21366166Sbostic 			return (1);
21449967Smckusick 		}
21538640Smckusick 	} else {
21666153Spendry 		warnx("%s: not a directory or special device", name);
21766166Sbostic 		return (1);
2181141Sbill 	}
21940062Smckusick 
22069303Smckusick 	if (checkvfsname(type, typelist))
22167792Smckusick 		return (1);
22266166Sbostic 
22368220Spendry 	hp = NULL;
22469303Smckusick 	if (!strcmp(type, "nfs")) {
22568220Spendry 		if ((delimp = strchr(name, '@')) != NULL) {
22668220Spendry 			hostp = delimp + 1;
22768220Spendry 			*delimp = '\0';
22868220Spendry 			hp = gethostbyname(hostp);
22968220Spendry 			*delimp = '@';
23068220Spendry 		} else if ((delimp = strchr(name, ':')) != NULL) {
23168220Spendry 			*delimp = '\0';
23268220Spendry 			hostp = name;
23368220Spendry 			hp = gethostbyname(hostp);
23468220Spendry 			name = delimp + 1;
23568220Spendry 			*delimp = ':';
23668220Spendry 		}
23768220Spendry 	}
23868220Spendry 
23966166Sbostic 	if (!namematch(hp))
24067792Smckusick 		return (1);
24140062Smckusick 
24266166Sbostic 	if (vflag)
24366166Sbostic 		(void)printf("%s: unmount from %s\n", name, mntpt);
24466166Sbostic 	if (fake)
24566166Sbostic 		return (0);
24666166Sbostic 
24766166Sbostic 	if (unmount(mntpt, fflag) < 0) {
24866166Sbostic 		warn("%s", mntpt);
24966153Spendry 		return (1);
25038640Smckusick 	}
25140062Smckusick 
25266166Sbostic 	if ((hp != NULL) && !(fflag & MNT_FORCE)) {
25338640Smckusick 		*delimp = '\0';
25466166Sbostic 		memset(&saddr, 0, sizeof(saddr));
25538640Smckusick 		saddr.sin_family = AF_INET;
25638640Smckusick 		saddr.sin_port = 0;
25766166Sbostic 		memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
25838640Smckusick 		pertry.tv_sec = 3;
25938640Smckusick 		pertry.tv_usec = 0;
26066166Sbostic 		so = RPC_ANYSOCK;
26166166Sbostic 		if ((clp = clntudp_create(&saddr,
26266166Sbostic 		    RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
26338640Smckusick 			clnt_pcreateerror("Cannot MNT PRC");
26438640Smckusick 			return (1);
26538446Smckusick 		}
26638640Smckusick 		clp->cl_auth = authunix_create_default();
26738640Smckusick 		try.tv_sec = 20;
26838640Smckusick 		try.tv_usec = 0;
26966166Sbostic 		clnt_stat = clnt_call(clp,
27066166Sbostic 		    RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
27138640Smckusick 		if (clnt_stat != RPC_SUCCESS) {
27238640Smckusick 			clnt_perror(clp, "Bad MNT RPC");
27338640Smckusick 			return (1);
27438446Smckusick 		}
27538640Smckusick 		auth_destroy(clp->cl_auth);
27638640Smckusick 		clnt_destroy(clp);
27738634Smckusick 	}
27866166Sbostic 	return (0);
2791141Sbill }
28038446Smckusick 
28138640Smckusick char *
getmntname(name,what,type)28240062Smckusick getmntname(name, what, type)
28338640Smckusick 	char *name;
28466153Spendry 	mntwhat what;
28569303Smckusick 	char **type;
28638640Smckusick {
287*69305Smckusick 	static struct statfs *mntbuf;
288*69305Smckusick 	static int mntsize;
289*69305Smckusick 	int i;
29038640Smckusick 
291*69305Smckusick 	if (mntbuf == NULL &&
292*69305Smckusick 	    (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
29366153Spendry 		warn("getmntinfo");
29466153Spendry 		return (NULL);
29538640Smckusick 	}
29638640Smckusick 	for (i = 0; i < mntsize; i++) {
29766166Sbostic 		if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
29840062Smckusick 			if (type)
29969303Smckusick 				*type = mntbuf[i].f_fstypename;
30038640Smckusick 			return (mntbuf[i].f_mntonname);
30140062Smckusick 		}
30266166Sbostic 		if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
30340062Smckusick 			if (type)
30469303Smckusick 				*type = mntbuf[i].f_fstypename;
30538640Smckusick 			return (mntbuf[i].f_mntfromname);
30640062Smckusick 		}
30738640Smckusick 	}
30866153Spendry 	return (NULL);
30938640Smckusick }
31038640Smckusick 
31166153Spendry int
namematch(hp)31266166Sbostic namematch(hp)
31340062Smckusick 	struct hostent *hp;
31440062Smckusick {
31566166Sbostic 	char *cp, **np;
31640062Smckusick 
31766166Sbostic 	if ((hp == NULL) || (nfshost == NULL))
31866153Spendry 		return (1);
31966153Spendry 
32040062Smckusick 	if (strcasecmp(nfshost, hp->h_name) == 0)
32166153Spendry 		return (1);
32266153Spendry 
32366166Sbostic 	if ((cp = strchr(hp->h_name, '.')) != NULL) {
32440062Smckusick 		*cp = '\0';
32540062Smckusick 		if (strcasecmp(nfshost, hp->h_name) == 0)
32666153Spendry 			return (1);
32740062Smckusick 	}
32840062Smckusick 	for (np = hp->h_aliases; *np; np++) {
32940062Smckusick 		if (strcasecmp(nfshost, *np) == 0)
33066153Spendry 			return (1);
33166166Sbostic 		if ((cp = strchr(*np, '.')) != NULL) {
33240062Smckusick 			*cp = '\0';
33340062Smckusick 			if (strcasecmp(nfshost, *np) == 0)
33466153Spendry 				return (1);
33540062Smckusick 		}
33640062Smckusick 	}
33766153Spendry 	return (0);
33840062Smckusick }
33940062Smckusick 
34038446Smckusick /*
34138446Smckusick  * xdr routines for mount rpc's
34238446Smckusick  */
34366153Spendry int
xdr_dir(xdrsp,dirp)34438446Smckusick xdr_dir(xdrsp, dirp)
34538446Smckusick 	XDR *xdrsp;
34638446Smckusick 	char *dirp;
34738446Smckusick {
34838446Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
34938446Smckusick }
35066166Sbostic 
35166166Sbostic void
usage()35266166Sbostic usage()
35366166Sbostic {
35466166Sbostic 	(void)fprintf(stderr,
35566166Sbostic 	    "usage: %s\n       %s\n",
35666166Sbostic 	    "umount [-fv] [-t fstypelist] special | node",
35766166Sbostic 	    "umount -a[fv] [-h host] [-t fstypelist]");
35866166Sbostic 	exit(1);
35966166Sbostic }
360