X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/724216f454604901cd6c2307cb0248aefcd4fe13..24c290cf29a0fe6c3b8ee988879bd44c7fd80a6e:/usr/src/sbin/umount/umount.c diff --git a/usr/src/sbin/umount/umount.c b/usr/src/sbin/umount/umount.c index d9ffc401d5..25b7eb267e 100644 --- a/usr/src/sbin/umount/umount.c +++ b/usr/src/sbin/umount/umount.c @@ -1,221 +1,246 @@ -/* - * Copyright (c) 1980, 1989 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms is permitted - * provided that all copyright information, including this notice, - * is retained in all such forms, and that any documentation, - * advertising or other materials related to such distribution and - * use acknowledge that the software was - * developed by the University of California, Berkeley. The name - * of the University may not be used to endorse or promote products - * derived from this software without specific prior written permission. +/*- + * Copyright (c) 1980, 1989, 1993 + * The Regents of the University of California. All rights reserved. * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * %sccs.include.redist.c% */ #ifndef lint -char copyright[] = -"@(#) Copyright (c) 1980, 1989 The Regents of the University of California.\n\ - All rights reserved.\n"; +static char copyright[] = +"@(#) Copyright (c) 1980, 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)umount.c 5.11 (Berkeley) %G%"; +static char sccsid[] = "@(#)umount.c 8.6 (Berkeley) %G%"; #endif /* not lint */ -/* - * umount - */ #include -#include -#include #include #include -#ifdef NFS #include #include #include + #include #include #include #include #include -#endif - -#ifdef NFS -extern int errno; -int xdr_dir(); -char *index(); -#endif -int vflag, all, errs; -int fflag = MNT_NOFORCE; -char *rindex(), *getmntname(); -#define MNTON 1 -#define MNTFROM 2 +#include +#include +#include +#include +#include +#include + +typedef enum { MNTON, MNTFROM } mntwhat; + +int fake, fflag, vflag, *typelist; +char *nfshost; + +int fsnametotype __P((char *)); +char *getmntname __P((char *, mntwhat, int *)); +void maketypelist __P((char *)); +int selected __P((int)); +int namematch __P((struct hostent *)); +int umountall __P((void)); +int umountfs __P((char *)); +void usage __P((void)); +int xdr_dir __P((XDR *, char *)); + +int main(argc, argv) int argc; - char **argv; + char *argv[]; { + int all, ch, errs; - argc--, argv++; + /* Start disks transferring immediately. */ sync(); -again: - if (argc > 0 && !strcmp(*argv, "-v")) { - vflag++; - argc--, argv++; - goto again; - } - if (argc > 0 && !strcmp(*argv, "-f")) { - fflag = MNT_FORCE; - argc--, argv++; - goto again; - } - if (argc > 0 && !strcmp(*argv, "-a")) { - all++; - argc--, argv++; - goto again; - } - if (argc == 0 && !all) { - fprintf(stderr, - "Usage: umount [ -a ] [ -f ] [ -v ] [ dev ... ]\n"); - exit(1); - } + + all = 0; + while ((ch = getopt(argc, argv, "aFfh:t:v")) != EOF) + switch (ch) { + case 'a': + all = 1; + break; + case 'F': + fake = 1; + break; + case 'f': + fflag = MNT_FORCE; + break; + case 'h': /* -h implies -a. */ + all = 1; + nfshost = optarg; + break; + case 't': + maketypelist(optarg); + break; + case 'v': + vflag = 1; + break; + default: + usage(); + /* NOTREACHED */ + } + argc -= optind; + argv += optind; + + if (argc == 0 && !all || argc != 0 && all) + usage(); + + /* -h implies "-t nfs" if no -t flag. */ + if ((nfshost != NULL) && (typelist == NULL)) + maketypelist("nfs"); + if (all) { if (setfsent() == 0) - perror(FSTAB), exit(1); - umountall(); - exit(0); + err(1, "%s", _PATH_FSTAB); + errs = umountall(); } else - setfsent(); - while (argc > 0) { - if (umountfs(*argv++) == 0) - errs++; - argc--; - } + for (errs = 0; *argv != NULL; ++argv) + if (umountfs(*argv) != 0) + errs = 1; exit(errs); } +int umountall() { - struct fstab *fs, *allocfsent(); - - if ((fs = getfsent()) == (struct fstab *)0) - return; - fs = allocfsent(fs); - umountall(); - if (strcmp(fs->fs_file, "/") == 0) { - freefsent(fs); - return; - } - if (strcmp(fs->fs_type, FSTAB_RW) && - strcmp(fs->fs_type, FSTAB_RO) && - strcmp(fs->fs_type, FSTAB_RQ)) { - freefsent(fs); - return; - } - (void) umountfs(fs->fs_file); - freefsent(fs); -} - -struct fstab * -allocfsent(fs) - register struct fstab *fs; -{ - register struct fstab *new; - register char *cp; - char *malloc(); - - new = (struct fstab *)malloc((unsigned)sizeof (*fs)); - cp = malloc((unsigned)strlen(fs->fs_file) + 1); - strcpy(cp, fs->fs_file); - new->fs_file = cp; - cp = malloc((unsigned)strlen(fs->fs_type) + 1); - strcpy(cp, fs->fs_type); - new->fs_type = cp; - cp = malloc((unsigned)strlen(fs->fs_spec) + 1); - strcpy(cp, fs->fs_spec); - new->fs_spec = cp; - new->fs_passno = fs->fs_passno; - new->fs_freq = fs->fs_freq; - return (new); -} + struct fstab *fs; + int rval, type; + char *cp; -freefsent(fs) - register struct fstab *fs; -{ + while ((fs = getfsent()) != NULL) { + /* Ignore the root. */ + if (strcmp(fs->fs_file, "/") == 0) + continue; + /* + * !!! + * Historic practice: ignore unknown FSTAB_* fields. + */ + if (strcmp(fs->fs_type, FSTAB_RW) && + strcmp(fs->fs_type, FSTAB_RO) && + strcmp(fs->fs_type, FSTAB_RQ)) + continue; + /* If an unknown file system type, complain. */ + if ((type = fsnametotype(fs->fs_vfstype)) == MOUNT_NONE) { + warnx("%s: unknown mount type", fs->fs_vfstype); + continue; + } + if (!selected(type)) + continue; - if (fs->fs_file) - free(fs->fs_file); - if (fs->fs_spec) - free(fs->fs_spec); - if (fs->fs_type) - free(fs->fs_type); - free((char *)fs); + /* + * We want to unmount the file systems in the reverse order + * that they were mounted. So, we save off the file name + * in some allocated memory, and then call recursively. + */ + if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL) + err(1, NULL); + (void)strcpy(cp, fs->fs_file); + rval = umountall(); + return (umountfs(cp) || rval); + } + return (0); } +int umountfs(name) char *name; { - char *mntpt; - struct stat stbuf; -#ifdef NFS - register CLIENT *clp; + enum clnt_stat clnt_stat; struct hostent *hp; struct sockaddr_in saddr; + struct stat sb; struct timeval pertry, try; - enum clnt_stat clnt_stat; - int so = RPC_ANYSOCK; - char *hostp, *delimp; -#endif - - if (stat(name, &stbuf) < 0) { - if ((mntpt = getmntname(name, MNTON)) == 0) - return (0); - } else if ((stbuf.st_mode & S_IFMT) == S_IFBLK) { - if ((mntpt = getmntname(name, MNTON)) == 0) - return (0); - } else if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { + CLIENT *clp; + int so, type; + char *delimp, *hostp, *mntpt, rname[MAXPATHLEN]; + + if (realpath(name, rname) == NULL) { + warn("%s", rname); + return (1); + } + + name = rname; + + if (stat(name, &sb) < 0) { + if (((mntpt = getmntname(name, MNTFROM, &type)) == NULL) && + ((mntpt = getmntname(name, MNTON, &type)) == NULL)) { + warnx("%s: not currently mounted", name); + return (1); + } + } else if (S_ISBLK(sb.st_mode)) { + if ((mntpt = getmntname(name, MNTON, &type)) == NULL) { + warnx("%s: not currently mounted", name); + return (1); + } + } else if (S_ISDIR(sb.st_mode)) { mntpt = name; - if ((name = getmntname(mntpt, MNTFROM)) == 0) - return (0); + if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) { + warnx("%s: not currently mounted", mntpt); + return (1); + } } else { - fprintf(stderr, "%s: not a directory or special device\n", - name); - return (0); + warnx("%s: not a directory or special device", name); + return (1); } - if (unmount(mntpt, fflag) < 0) { - perror(mntpt); - return (0); + + if (!selected(type)) + return (1); + + hp = NULL; + if (type == MOUNT_NFS) { + if ((delimp = strchr(name, '@')) != NULL) { + hostp = delimp + 1; + *delimp = '\0'; + hp = gethostbyname(hostp); + *delimp = '@'; + } else if ((delimp = strchr(name, ':')) != NULL) { + *delimp = '\0'; + hostp = name; + hp = gethostbyname(hostp); + name = delimp + 1; + *delimp = ':'; + } } + + if (!namematch(hp)) + return (1); + if (vflag) - fprintf(stderr, "%s: Unmounted from %s\n", name, mntpt); -#ifdef NFS - if ((delimp = index(name, '@')) != NULL) { - hostp = delimp + 1; - *delimp = '\0'; - } else { + (void)printf("%s: unmount from %s\n", name, mntpt); + if (fake) + return (0); + + if (unmount(mntpt, fflag) < 0) { + warn("%s", mntpt); return (1); } - if ((hp = gethostbyname(hostp)) != NULL) { - bcopy(hp->h_addr,(caddr_t)&saddr.sin_addr,hp->h_length); + + if ((hp != NULL) && !(fflag & MNT_FORCE)) { + *delimp = '\0'; + memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = 0; + memmove(&saddr.sin_addr, hp->h_addr, hp->h_length); pertry.tv_sec = 3; pertry.tv_usec = 0; - if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, - pertry, &so)) == NULL) { + so = RPC_ANYSOCK; + if ((clp = clntudp_create(&saddr, + RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) { clnt_pcreateerror("Cannot MNT PRC"); return (1); } clp->cl_auth = authunix_create_default(); try.tv_sec = 20; try.tv_usec = 0; - clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, name, - xdr_void, (caddr_t)0, try); + clnt_stat = clnt_call(clp, + RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try); if (clnt_stat != RPC_SUCCESS) { clnt_perror(clp, "Bad MNT RPC"); return (1); @@ -223,40 +248,153 @@ umountfs(name) auth_destroy(clp->cl_auth); clnt_destroy(clp); } -#endif NFS - return (1); + return (0); } char * -getmntname(name, what) +getmntname(name, what, type) char *name; - int what; + mntwhat what; + int *type; { - int mntsize, i; struct statfs *mntbuf; + int i, mntsize; - if ((mntsize = getmntinfo(&mntbuf)) == 0) { - perror("umount"); - return (0); + if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { + warn("getmntinfo"); + return (NULL); } for (i = 0; i < mntsize; i++) { - if (what == MNTON && !strcmp(mntbuf[i].f_mntfromname, name)) + if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) { + if (type) + *type = mntbuf[i].f_type; return (mntbuf[i].f_mntonname); - if (what == MNTFROM && !strcmp(mntbuf[i].f_mntonname, name)) + } + if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) { + if (type) + *type = mntbuf[i].f_type; return (mntbuf[i].f_mntfromname); + } + } + return (NULL); +} + +static enum { IN_LIST, NOT_IN_LIST } which; + +int +selected(type) + int type; +{ + int *av; + + /* If no type specified, it's always selected. */ + if (typelist == NULL) + return (1); + for (av = typelist; *av != NULL; ++av) + if (type == *typelist) + return (which == IN_LIST ? 1 : 0); + return (which == IN_LIST ? 0 : 1); +} + +void +maketypelist(fslist) + char *fslist; +{ + int *av, i; + char *nextcp; + + if ((fslist == NULL) || (fslist[0] == '\0')) + errx(1, "empty type list"); + + /* + * XXX + * Note: the syntax is "noxxx,yyy" for no xxx's and + * no yyy's, not the more intuitive "noyyy,noyyy". + */ + if (fslist[0] == 'n' && fslist[1] == 'o') { + fslist += 2; + which = NOT_IN_LIST; + } else + which = IN_LIST; + + /* Count the number of types. */ + for (i = 0, nextcp = fslist; *nextcp != NULL; ++nextcp) + if (*nextcp == ',') + i++; + + /* Build an array of that many types. */ + if ((av = typelist = malloc((i + 2) * sizeof(int))) == NULL) + err(1, NULL); + for (i = 0; fslist != NULL; fslist = nextcp, ++i) { + if ((nextcp = strchr(fslist, ',')) != NULL) + *nextcp++ = '\0'; + av[i] = fsnametotype(fslist); + if (av[i] == MOUNT_NONE) + errx(1, "%s: unknown mount type", fslist); + } + /* Terminate the array. */ + av[i++] = MOUNT_NONE; +} + +int +fsnametotype(name) + char *name; +{ + static char const *namelist[] = INITMOUNTNAMES; + char const **cp; + + for (cp = namelist; *cp; ++cp) + if (strcmp(name, *cp) == 0) + return (cp - namelist); + return (MOUNT_NONE); +} + +int +namematch(hp) + struct hostent *hp; +{ + char *cp, **np; + + if ((hp == NULL) || (nfshost == NULL)) + return (1); + + if (strcasecmp(nfshost, hp->h_name) == 0) + return (1); + + if ((cp = strchr(hp->h_name, '.')) != NULL) { + *cp = '\0'; + if (strcasecmp(nfshost, hp->h_name) == 0) + return (1); + } + for (np = hp->h_aliases; *np; np++) { + if (strcasecmp(nfshost, *np) == 0) + return (1); + if ((cp = strchr(*np, '.')) != NULL) { + *cp = '\0'; + if (strcasecmp(nfshost, *np) == 0) + return (1); + } } - fprintf(stderr, "%s: not currently mounted\n", name); return (0); } -#ifdef NFS /* * xdr routines for mount rpc's */ +int xdr_dir(xdrsp, dirp) XDR *xdrsp; char *dirp; { return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); } -#endif NFS + +void +usage() +{ + (void)fprintf(stderr, + "usage: %s\n %s\n", + "umount [-fv] [-t fstypelist] special | node", + "umount -a[fv] [-h host] [-t fstypelist]"); + exit(1); +}