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