Index: stable/4/sbin/umount/umount.c =================================================================== --- stable/4/sbin/umount/umount.c (revision 87771) +++ stable/4/sbin/umount/umount.c (revision 87772) @@ -1,696 +1,694 @@ /*- * Copyright (c) 1980, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)umount.c 8.8 (Berkeley) 5/8/95"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include "mounttab.h" #define ISDOT(x) ((x)[0] == '.' && (x)[1] == '\0') #define ISDOTDOT(x) ((x)[0] == '.' && (x)[1] == '.' && (x)[2] == '\0') typedef enum { MNTON, MNTFROM, NOTHING } mntwhat; typedef enum { MARK, UNMARK, NAME, COUNT, FREE } dowhat; -struct mtablist *mtabhead; int fflag, vflag; char *nfshost; void checkmntlist (char *, char **, char **, char **); int checkvfsname (const char *, char **); char *getmntname (const char *, const char *, mntwhat, char **, dowhat); char *getrealname(char *, char *resolved_path); char **makevfslist (const char *); size_t mntinfo (struct statfs **); int namematch (struct hostent *); int umountall (char **); int umountfs (char *, char **); void usage (void); int xdr_dir (XDR *, char *); int main(int argc, char *argv[]) { int all, errs, ch, mntsize; char **typelist = NULL, *mntonname, *mntfromname; char *type, *mntfromnamerev, *mntonnamerev; struct statfs *mntbuf; /* Start disks transferring immediately. */ sync(); all = errs = 0; while ((ch = getopt(argc, argv, "Aafh:t:v")) != -1) switch (ch) { case 'A': all = 2; break; case 'a': all = 1; break; case 'f': fflag = MNT_FORCE; break; case 'h': /* -h implies -A. */ all = 2; nfshost = optarg; break; case 't': if (typelist != NULL) err(1, "only one -t option may be specified"); typelist = makevfslist(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)) typelist = makevfslist("nfs"); switch (all) { case 2: if ((mntsize = mntinfo(&mntbuf)) <= 0) break; /* * We unmount the nfs-mounts in the reverse order * that they were mounted. */ for (errs = 0, mntsize--; mntsize > 0; mntsize--) { if (checkvfsname(mntbuf[mntsize].f_fstypename, typelist)) continue; /* * Check if a mountpoint is laid over by another mount. * A warning will be printed to stderr if this is * the case. The laid over mount remains unmounted. */ mntonname = mntbuf[mntsize].f_mntonname; mntfromname = mntbuf[mntsize].f_mntfromname; mntonnamerev = getmntname(getmntname(mntonname, NULL, MNTFROM, &type, NAME), NULL, MNTON, &type, NAME); mntfromnamerev = getmntname(mntonnamerev, NULL, MNTFROM, &type, NAME); if (strcmp(mntonnamerev, mntonname) == 0 && strcmp(mntfromnamerev, mntfromname ) != 0) warnx("cannot umount %s, %s\n " "is mounted there, umount it first", mntonname, mntfromnamerev); if (umountfs(mntbuf[mntsize].f_mntonname, typelist) != 0) errs = 1; } free(mntbuf); break; case 1: if (setfsent() == 0) err(1, "%s", _PATH_FSTAB); errs = umountall(typelist); break; case 0: for (errs = 0; *argv != NULL; ++argv) if (umountfs(*argv, typelist) != 0) errs = 1; break; } (void)getmntname(NULL, NULL, NOTHING, NULL, FREE); exit(errs); } int umountall(char **typelist) { struct vfsconf vfc; struct fstab *fs; int rval; char *cp; static int firstcall = 1; if ((fs = getfsent()) != NULL) firstcall = 0; else if (firstcall) errx(1, "fstab reading failure"); else return (0); do { /* 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 (getvfsbyname(fs->fs_vfstype, &vfc) == -1) { warnx("%s: unknown mount type", fs->fs_vfstype); continue; } if (checkvfsname(fs->fs_vfstype, typelist)) continue; /* * 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, "malloc failed"); (void)strcpy(cp, fs->fs_file); rval = umountall(typelist); rval = umountfs(cp, typelist) || rval; free(cp); return (rval); } while ((fs = getfsent()) != NULL); return (0); } int umountfs(char *name, char **typelist) { enum clnt_stat clnt_stat; struct hostent *hp; struct mtablist *mtab; struct sockaddr_in saddr; struct timeval pertry, try; CLIENT *clp; size_t len; int so, speclen, do_rpc; char *mntonname, *mntfromname; char *mntfromnamerev; char *nfsdirname, *orignfsdirname; char *resolved, realname[MAXPATHLEN]; char *type, *delimp, *hostp, *origname; len = 0; mtab = NULL; mntfromname = mntonname = delimp = hostp = orignfsdirname = NULL; /* * 1. Check if the name exists in the mounttable. */ (void)checkmntlist(name, &mntfromname, &mntonname, &type); /* * 2. Remove trailing slashes if there are any. After that * we look up the name in the mounttable again. */ if (mntfromname == NULL && mntonname == NULL) { speclen = strlen(name); for (speclen = strlen(name); speclen > 1 && name[speclen - 1] == '/'; speclen--) name[speclen - 1] = '\0'; (void)checkmntlist(name, &mntfromname, &mntonname, &type); resolved = name; /* Save off original name in origname */ if ((origname = strdup(name)) == NULL) err(1, "strdup"); /* * 3. Check if the deprecated nfs-syntax with an '@' * has been used and translate it to the ':' syntax. * Look up the name in the mounttable again. */ if (mntfromname == NULL && mntonname == NULL) { if ((delimp = strrchr(name, '@')) != NULL) { hostp = delimp + 1; if (*hostp != '\0') { /* * Make both '@' and ':' * notations equal */ char *host = strdup(hostp); len = strlen(hostp); if (host == NULL) err(1, "strdup"); memmove(name + len + 1, name, (size_t)(delimp - name)); name[len] = ':'; memmove(name, host, len); free(host); } for (speclen = strlen(name); speclen > 1 && name[speclen - 1] == '/'; speclen--) name[speclen - 1] = '\0'; name[len + speclen + 1] = '\0'; (void)checkmntlist(name, &mntfromname, &mntonname, &type); resolved = name; } /* * 4. Check if a relative mountpoint has been * specified. This should happen as last check, * the order is important. To prevent possible * nfs-hangs, we just call realpath(3) on the * basedir of mountpoint and add the dirname again. * Check the name in mounttable one last time. */ if (mntfromname == NULL && mntonname == NULL) { (void)strcpy(name, origname); if ((getrealname(name, realname)) != NULL) { (void)checkmntlist(realname, &mntfromname, &mntonname, &type); resolved = realname; } /* * All tests failed, return to main() */ if (mntfromname == NULL && mntonname == NULL) { (void)strcpy(name, origname); warnx("%s: not currently mounted", origname); free(origname); return (1); } } } free(origname); } else resolved = name; if (checkvfsname(type, typelist)) return (1); hp = NULL; nfsdirname = NULL; if (!strcmp(type, "nfs")) { if ((nfsdirname = strdup(mntfromname)) == NULL) err(1, "strdup"); orignfsdirname = nfsdirname; if ((delimp = strchr(nfsdirname, ':')) != NULL) { *delimp = '\0'; hostp = nfsdirname; if ((hp = gethostbyname(hostp)) == NULL) { warnx("can't get net id for host"); } nfsdirname = delimp + 1; } } /* * Check if the reverse entrys of the mounttable are really the * same as the normal ones. */ if ((mntfromnamerev = strdup(getmntname(getmntname(mntfromname, NULL, MNTON, &type, NAME), NULL, MNTFROM, &type, NAME))) == NULL) err(1, "strdup"); /* * Mark the uppermost mount as unmounted. */ (void)getmntname(mntfromname, mntonname, NOTHING, &type, MARK); /* * If several equal mounts are in the mounttable, check the order * and warn the user if necessary. */ if (strcmp(mntfromnamerev, mntfromname ) != 0 && strcmp(resolved, mntonname) != 0) { warnx("cannot umount %s, %s\n " "is mounted there, umount it first", mntonname, mntfromnamerev); /* call getmntname again to set mntcheck[i] to 0 */ (void)getmntname(mntfromname, mntonname, NOTHING, &type, UNMARK); return (1); } free(mntfromnamerev); /* * Check if we have to start the rpc-call later. * If there are still identical nfs-names mounted, * we skip the rpc-call. Obviously this has to * happen before unmount(2), but it should happen * after the previous namecheck. */ if (strcmp(type, "nfs") == 0 && getmntname(mntfromname, NULL, NOTHING, &type, COUNT) != NULL) do_rpc = 1; else do_rpc = 0; if (!namematch(hp)) return (1); if (unmount(mntonname, fflag) != 0 ) { warn("unmount of %s failed", mntonname); return (1); } if (vflag) (void)printf("%s: unmount from %s\n", mntfromname, mntonname); /* * Report to mountd-server which nfsname * has been unmounted. */ if (hp != NULL && !(fflag & MNT_FORCE) && do_rpc) { memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = 0; memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, sizeof(saddr.sin_addr))); pertry.tv_sec = 3; pertry.tv_usec = 0; 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, nfsdirname, xdr_void, (caddr_t)0, try); if (clnt_stat != RPC_SUCCESS) { clnt_perror(clp, "Bad MNT RPC"); return (1); } /* * Remove the unmounted entry from /var/db/mounttab. */ - if (read_mtab(mtab)) { - mtab = mtabhead; - clean_mtab(hostp, nfsdirname); - if(!write_mtab()) - warnx("cannot remove entry %s:%s", + if (read_mtab()) { + clean_mtab(hostp, nfsdirname, vflag); + if(!write_mtab(vflag)) + warnx("cannot remove mounttab entry %s:%s", hostp, nfsdirname); free_mtab(); } free(orignfsdirname); auth_destroy(clp->cl_auth); clnt_destroy(clp); } return (0); } char * getmntname(const char *fromname, const char *onname, mntwhat what, char **type, dowhat mark) { static struct statfs *mntbuf; static size_t mntsize = 0; static char *mntcheck = NULL; static char *mntcount = NULL; int i, count; if (mntsize <= 0) { if ((mntsize = mntinfo(&mntbuf)) <= 0) return (NULL); } if (mntcheck == NULL) { if ((mntcheck = calloc(mntsize + 1, sizeof(int))) == NULL || (mntcount = calloc(mntsize + 1, sizeof(int))) == NULL) err(1, "calloc"); } /* * We want to get the file systems in the reverse order * that they were mounted. Mounted and unmounted filesystems * are marked or unmarked in a table called 'mntcheck'. * Unmount(const char *dir, int flags) does only take the * mountpoint as argument, not the destination. If we don't pay * attention to the order, it can happen that a overlaying * filesystem get's unmounted instead of the one the user * has choosen. */ switch (mark) { case NAME: /* Return only the specific name */ for (i = mntsize - 1; i >= 0; i--) { if (fromname != NULL && what == MNTON && !strcmp(mntbuf[i].f_mntfromname, fromname) && mntcheck[i] != 1) { if (type) *type = mntbuf[i].f_fstypename; return (mntbuf[i].f_mntonname); } if (fromname != NULL && what == MNTFROM && !strcmp(mntbuf[i].f_mntonname, fromname) && mntcheck[i] != 1) { if (type) *type = mntbuf[i].f_fstypename; return (mntbuf[i].f_mntfromname); } } return (NULL); case MARK: /* Mark current mount with '1' and return name */ for (i = mntsize - 1; i >= 0; i--) { if (mntcheck[i] == 0 && (strcmp(mntbuf[i].f_mntonname, onname) == 0) && (strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) { mntcheck[i] = 1; return (mntbuf[i].f_mntonname); } } return (NULL); case UNMARK: /* Unmark current mount with '0' and return name */ for (i = 0; i < mntsize; i++) { if (mntcheck[i] == 1 && (strcmp(mntbuf[i].f_mntonname, onname) == 0) && (strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) { mntcheck[i] = 0; return (mntbuf[i].f_mntonname); } } return (NULL); case COUNT: /* Count the equal mntfromnames */ count = 0; for (i = mntsize - 1; i >= 0; i--) { if (strcmp(mntbuf[i].f_mntfromname, fromname) == 0) count++; } /* Mark the already unmounted mounts and return * mntfromname if count <= 1. Else return NULL. */ for (i = mntsize - 1; i >= 0; i--) { if (strcmp(mntbuf[i].f_mntfromname, fromname) == 0) { if (mntcount[i] == 1) count--; else { mntcount[i] = 1; break; } } } if (count <= 1) return (mntbuf[i].f_mntonname); else return (NULL); case FREE: free(mntbuf); free(mntcheck); free(mntcount); return (NULL); default: return (NULL); } } int namematch(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); } } return (0); } void checkmntlist(char *name, char **fromname, char **onname, char **type) { *fromname = getmntname(name, NULL, MNTFROM, type, NAME); if (*fromname == NULL) { *onname = getmntname(name, NULL, MNTON, type, NAME); if (*onname != NULL) *fromname = name; } else *onname = name; } size_t mntinfo(struct statfs **mntbuf) { static struct statfs *origbuf; size_t bufsize; int mntsize; mntsize = getfsstat(NULL, 0, MNT_NOWAIT); if (mntsize <= 0) return (0); bufsize = (mntsize + 1) * sizeof(struct statfs); if ((origbuf = malloc(bufsize)) == NULL) err(1, "malloc"); mntsize = getfsstat(origbuf, (long)bufsize, MNT_NOWAIT); *mntbuf = origbuf; return (mntsize); } char * getrealname(char *name, char *realname) { char *dirname; int havedir; size_t baselen; size_t dirlen; dirname = '\0'; havedir = 0; if (*name == '/') { if (ISDOT(name + 1) || ISDOTDOT(name + 1)) strcpy(realname, "/"); else { if ((dirname = strrchr(name + 1, '/')) == NULL) snprintf(realname, MAXPATHLEN, "%s", name); else havedir = 1; } } else { if (ISDOT(name) || ISDOTDOT(name)) (void)realpath(name, realname); else { if ((dirname = strrchr(name, '/')) == NULL) { if ((realpath(name, realname)) == NULL) return (NULL); } else havedir = 1; } } if (havedir) { *dirname++ = '\0'; if (ISDOT(dirname)) { *dirname = '\0'; if ((realpath(name, realname)) == NULL) return (NULL); } else if (ISDOTDOT(dirname)) { *--dirname = '/'; if ((realpath(name, realname)) == NULL) return (NULL); } else { if ((realpath(name, realname)) == NULL) return (NULL); baselen = strlen(realname); dirlen = strlen(dirname); if (baselen + dirlen + 1 > MAXPATHLEN) return (NULL); if (realname[1] == '\0') { memmove(realname + 1, dirname, dirlen); realname[dirlen + 1] = '\0'; } else { realname[baselen] = '/'; memmove(realname + baselen + 1, dirname, dirlen); realname[baselen + dirlen + 1] = '\0'; } } } return (realname); } /* * xdr routines for mount rpc's */ int xdr_dir(XDR *xdrsp, char *dirp) { return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); } void usage() { (void)fprintf(stderr, "%s\n%s\n", "usage: umount [-fv] special | node", " umount -a | -A [-fv] [-h host] [-t type]"); exit(1); } Index: stable/4/usr.sbin/rpc.umntall/mounttab.c =================================================================== --- stable/4/usr.sbin/rpc.umntall/mounttab.c (revision 87771) +++ stable/4/usr.sbin/rpc.umntall/mounttab.c (revision 87772) @@ -1,226 +1,226 @@ /* * Copyright (c) 1999 Martin Blapp * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include +#include #include #include #include #include #include "mounttab.h" -int verbose; struct mtablist *mtabhead; +static void badline(char *field, char *bad); + /* * Add an entry to PATH_MOUNTTAB for each mounted NFS filesystem, * so the client can notify the NFS server even after reboot. */ int add_mtab(char *hostp, char *dirp) { FILE *mtabfile; - time_t *now; - now = NULL; if ((mtabfile = fopen(PATH_MOUNTTAB, "a")) == NULL) return (0); else { - fprintf(mtabfile, "%ld\t%s\t%s\n", time(now), hostp, dirp); + fprintf(mtabfile, "%ld\t%s\t%s\n", + (long)time(NULL), hostp, dirp); fclose(mtabfile); return (1); } } /* * Read mounttab line for line and return struct mtablist. */ int -read_mtab(struct mtablist *mtabp) { - struct mtablist **mtabpp; +read_mtab() { + struct mtablist **mtabpp, *mtabp; char *hostp, *dirp, *cp; char str[STRSIZ]; - char *timep; + char *timep, *endp; time_t time; + u_long ultmp; FILE *mtabfile; if ((mtabfile = fopen(PATH_MOUNTTAB, "r")) == NULL) { if (errno == ENOENT) return (0); else { syslog(LOG_ERR, "can't open %s", PATH_MOUNTTAB); return (0); } } time = 0; mtabpp = &mtabhead; while (fgets(str, STRSIZ, mtabfile) != NULL) { cp = str; errno = 0; if (*cp == '#' || *cp == ' ' || *cp == '\n') continue; timep = strsep(&cp, " \t\n"); - if (timep == NULL || *timep == ' ' || *timep == '\n') { - badline(timep); + if (timep == NULL || *timep == '\0') { + badline("time", timep); continue; } hostp = strsep(&cp, " \t\n"); - if (hostp == NULL || *hostp == ' ' || *hostp == '\n') { - badline(hostp); + if (hostp == NULL || *hostp == '\0') { + badline("host", hostp); continue; } dirp = strsep(&cp, " \t\n"); - if (dirp == NULL || *dirp == ' ' || *dirp == '\n') { - badline(dirp); + if (dirp == NULL || *dirp == '\0') { + badline("dir", dirp); continue; } - time = strtoul(timep, (char **)NULL, 10); - if (errno == ERANGE) { - badline(timep); + ultmp = strtoul(timep, &endp, 10); + if (ultmp == ULONG_MAX || *endp != '\0') { + badline("time", timep); continue; } + time = ultmp; if ((mtabp = malloc(sizeof (struct mtablist))) == NULL) { syslog(LOG_ERR, "malloc"); fclose(mtabfile); return (0); } mtabp->mtab_time = time; memmove(mtabp->mtab_host, hostp, RPCMNT_NAMELEN); mtabp->mtab_host[RPCMNT_NAMELEN - 1] = '\0'; memmove(mtabp->mtab_dirp, dirp, RPCMNT_PATHLEN); mtabp->mtab_dirp[RPCMNT_PATHLEN - 1] = '\0'; mtabp->mtab_next = (struct mtablist *)NULL; *mtabpp = mtabp; mtabpp = &mtabp->mtab_next; } fclose(mtabfile); return (1); } /* * Rewrite PATH_MOUNTTAB from scratch and skip bad entries. * Unlink PATH_MOUNTAB if no entry is left. */ int -write_mtab() { - struct mtablist *mtabp; +write_mtab(int verbose) { + struct mtablist *mtabp, *mp; FILE *mtabfile; int line; if ((mtabfile = fopen(PATH_MOUNTTAB, "w")) == NULL) { syslog(LOG_ERR, "can't write to %s", PATH_MOUNTTAB); return (0); } line = 0; for (mtabp = mtabhead; mtabp != NULL; mtabp = mtabp->mtab_next) { - if (mtabp->mtab_host != NULL && - strlen(mtabp->mtab_host) > 0) { - fprintf(mtabfile, "%ld\t%s\t%s\n", mtabp->mtab_time, + if (mtabp->mtab_host[0] == '\0') + continue; + /* Skip if a later (hence more recent) entry is identical. */ + for (mp = mtabp->mtab_next; mp != NULL; mp = mp->mtab_next) + if (strcmp(mtabp->mtab_host, mp->mtab_host) == 0 && + strcmp(mtabp->mtab_dirp, mp->mtab_dirp) == 0) + break; + if (mp != NULL) + continue; + + fprintf(mtabfile, "%ld\t%s\t%s\n", + (long)mtabp->mtab_time, mtabp->mtab_host, + mtabp->mtab_dirp); + if (verbose) + warnx("write mounttab entry %s:%s", mtabp->mtab_host, mtabp->mtab_dirp); - if (verbose) { - warnx("write entry " "%s:%s", - mtabp->mtab_host, mtabp->mtab_dirp); - } - clean_mtab(mtabp->mtab_host, mtabp->mtab_dirp); - line++; - } + line++; } fclose(mtabfile); if (line == 0) { if (unlink(PATH_MOUNTTAB) == -1) { syslog(LOG_ERR, "can't remove %s", PATH_MOUNTTAB); return (0); } } return (1); } /* * Mark the entries as clean where RPC calls have been done successfully. */ void -clean_mtab(char *hostp, char *dirp) { +clean_mtab(char *hostp, char *dirp, int verbose) { struct mtablist *mtabp; char *host; + /* Copy hostp in case it points to an entry that we are zeroing out. */ host = strdup(hostp); for (mtabp = mtabhead; mtabp != NULL; mtabp = mtabp->mtab_next) { - if (mtabp->mtab_host != NULL && - strcmp(mtabp->mtab_host, host) == 0) { - if (dirp == NULL) { - if (verbose) { - warnx("delete entries " - "host %s", host); - } - bzero(mtabp->mtab_host, RPCMNT_NAMELEN); - } else { - if (strcmp(mtabp->mtab_dirp, dirp) == 0) { - if (verbose) { - warnx("delete entry " - "%s:%s", host, dirp); - } - bzero(mtabp->mtab_host, RPCMNT_NAMELEN); - } - } - } + if (strcmp(mtabp->mtab_host, host) != 0) + continue; + if (dirp != NULL && strcmp(mtabp->mtab_dirp, dirp) != 0) + continue; + + if (verbose) + warnx("delete mounttab entry%s %s:%s", + (dirp == NULL) ? " by host" : "", + mtabp->mtab_host, mtabp->mtab_dirp); + bzero(mtabp->mtab_host, RPCMNT_NAMELEN); } free(host); } /* * Free struct mtablist mtab. */ void free_mtab() { struct mtablist *mtabp; - struct mtablist *mtab_next; - for (mtabp = mtabhead; mtabp != NULL; mtabp = mtab_next) { - mtab_next = mtabp->mtab_next; + while ((mtabp = mtabhead) != NULL) { + mtabhead = mtabhead->mtab_next; free(mtabp); - mtabp = mtab_next; } } /* * Print bad lines to syslog. */ -void -badline(char *bad) { - - syslog(LOG_ERR, "skip bad line in mounttab with entry %s", bad); +static void +badline(char *field, char *bad) { + syslog(LOG_ERR, "bad mounttab %s field '%s'", field, + (bad == NULL) ? "" : bad); } Index: stable/4/usr.sbin/rpc.umntall/mounttab.h =================================================================== --- stable/4/usr.sbin/rpc.umntall/mounttab.h (revision 87771) +++ stable/4/usr.sbin/rpc.umntall/mounttab.h (revision 87772) @@ -1,45 +1,46 @@ /* * Copyright (c) 1999 Martin Blapp * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+100) #define PATH_MOUNTTAB "/var/db/mounttab" /* Structure for /var/db/mounttab */ struct mtablist { time_t mtab_time; char mtab_host[RPCMNT_NAMELEN]; char mtab_dirp[RPCMNT_PATHLEN]; struct mtablist *mtab_next; }; +extern struct mtablist *mtabhead; + int add_mtab(char *, char *); -void badline (char *); -void clean_mtab (char *, char *); -int read_mtab (struct mtablist *); -int write_mtab (void); -void free_mtab (void); +void clean_mtab(char *, char *, int); +int read_mtab(void); +int write_mtab(int); +void free_mtab(void); Index: stable/4/usr.sbin/rpc.umntall/rpc.umntall.c =================================================================== --- stable/4/usr.sbin/rpc.umntall/rpc.umntall.c (revision 87771) +++ stable/4/usr.sbin/rpc.umntall/rpc.umntall.c (revision 87772) @@ -1,300 +1,292 @@ /* * Copyright (c) 1999 Martin Blapp * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include "mounttab.h" int verbose; static int do_umount (char *, char *); static int do_umntall (char *); static int is_mounted (char *, char *); static void usage (void); int xdr_dir (XDR *, char *); -struct mtablist *mtabhead; - int main(int argc, char **argv) { int ch, keep, success, pathlen; - time_t expire, *now; + time_t expire, now; char *host, *path; struct mtablist *mtab; - mtab = NULL; - now = NULL; expire = 0; - host = path = '\0'; + host = path = NULL; success = keep = verbose = 0; while ((ch = getopt(argc, argv, "h:kp:ve:")) != -1) switch (ch) { case 'h': host = optarg; break; case 'e': - expire = (time_t)optarg; + expire = atoi(optarg); break; case 'k': keep = 1; break; case 'p': path = optarg; break; case 'v': verbose = 1; break; case '?': usage(); default: } argc -= optind; argv += optind; - /* Ignore SIGINT and SIGQUIT during shutdown */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - /* Default expiretime is one day */ if (expire == 0) expire = 86400; - /* - * Read PATH_MOUNTTAB and check each entry - * and do finally the unmounts. - */ + time(&now); + + /* Read PATH_MOUNTTAB. */ + if (!read_mtab()) { + if (verbose) + warnx("no mounttab entries (%s does not exist)", + PATH_MOUNTTAB); + mtabhead = NULL; + } + if (host == NULL && path == NULL) { - if (!read_mtab(mtab)) { - if (verbose) - warnx("nothing to do, %s does not exist", - PATH_MOUNTTAB); - } + /* Check each entry and do any necessary unmount RPCs. */ for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) { - if (*mtab->mtab_host != '\0' || - mtab->mtab_time <= (time(now) - expire)) { - if (keep && is_mounted(mtab->mtab_host, - mtab->mtab_dirp)) { - if (verbose) { - warnx("skip entry %s:%s", - mtab->mtab_host, - mtab->mtab_dirp); - } - } else if (do_umount(mtab->mtab_host, - mtab->mtab_dirp) || - mtab->mtab_time <= (time(now) - expire)) { - clean_mtab(mtab->mtab_host, - mtab->mtab_dirp); - } + if (*mtab->mtab_host == '\0') + continue; + if (mtab->mtab_time + expire < now) { + /* Clear expired entry. */ + if (verbose) + warnx("remove expired entry %s:%s", + mtab->mtab_host, mtab->mtab_dirp); + bzero(mtab->mtab_host, + sizeof(mtab->mtab_host)); + continue; } + if (keep && is_mounted(mtab->mtab_host, + mtab->mtab_dirp)) { + if (verbose) + warnx("skip entry %s:%s", + mtab->mtab_host, mtab->mtab_dirp); + continue; + } + if (do_umount(mtab->mtab_host, mtab->mtab_dirp)) { + if (verbose) + warnx("umount RPC for %s:%s succeeded", + mtab->mtab_host, mtab->mtab_dirp); + /* Remove all entries for this host + path. */ + clean_mtab(mtab->mtab_host, mtab->mtab_dirp, + verbose); + } } - /* Only do a RPC UMNTALL for this specific host */ - } else if (host != NULL && path == NULL) { - if (!do_umntall(host)) - exit(1); - else - success = 1; - /* Someone forgot to enter a hostname */ - } else if (host == NULL && path != NULL) - usage(); - /* Only do a RPC UMOUNT for this specific mount */ - else { - for (pathlen = strlen(path); - pathlen > 1 && path[pathlen - 1] == '/'; pathlen--) - path[pathlen - 1] = '\0'; - if (!do_umount(host, path)) - exit(1); - else - success = 1; - } - /* Write and unlink PATH_MOUNTTAB if necessary */ - if (success) { - if (verbose) - warnx("UMOUNT RPC successfully sent to %s", host); - if (read_mtab(mtab)) { - mtab = mtabhead; - clean_mtab(host, path); + success = 1; + } else { + if (host == NULL && path != NULL) + /* Missing hostname. */ + usage(); + if (path == NULL) { + /* Do a RPC UMNTALL for this specific host */ + success = do_umntall(host); + if (verbose && success) + warnx("umntall RPC for %s succeeded", host); + } else { + /* Do a RPC UMNTALL for this specific mount */ + for (pathlen = strlen(path); + pathlen > 1 && path[pathlen - 1] == '/'; pathlen--) + path[pathlen - 1] = '\0'; + success = do_umount(host, path); + if (verbose && success) + warnx("umount RPC for %s:%s succeeded", host, + path); } + /* If successful, remove any corresponding mounttab entries. */ + if (success) + clean_mtab(host, path, verbose); } - if (!write_mtab()) { - free_mtab(); - exit(1); - } + /* Write and unlink PATH_MOUNTTAB if necessary */ + if (success) + success = write_mtab(verbose); free_mtab(); - exit(0); + exit (success ? 0 : 1); } /* * Send a RPC_MNT UMNTALL request to hostname. * XXX This works for all mountd implementations, * but produces a RPC IOERR on non FreeBSD systems. */ int do_umntall(char *hostname) { enum clnt_stat clnt_stat; struct hostent *hp; struct sockaddr_in saddr; struct timeval pertry, try; int so; CLIENT *clp; if ((hp = gethostbyname(hostname)) == NULL) { warnx("gethostbyname(%s) failed", hostname); return (0); } memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = 0; memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, sizeof(saddr.sin_addr))); pertry.tv_sec = 3; pertry.tv_usec = 0; so = RPC_ANYSOCK; - if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, - pertry, &so)) == NULL) { - clnt_pcreateerror("Cannot send MNT PRC"); + clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, pertry, &so); + if (clp == NULL) { + warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT")); return (0); } clp->cl_auth = authunix_create_default(); try.tv_sec = 3; try.tv_usec = 0; clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, try); - if (clnt_stat != RPC_SUCCESS) { - clnt_perror(clp, "Bad MNT RPC"); - return (0); - } else - return (1); + if (clnt_stat != RPC_SUCCESS) + warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMNTALL")); + auth_destroy(clp->cl_auth); + clnt_destroy(clp); + return (clnt_stat == RPC_SUCCESS); } /* * Send a RPC_MNT UMOUNT request for dirp to hostname. */ int do_umount(char *hostname, char *dirp) { enum clnt_stat clnt_stat; struct hostent *hp; struct sockaddr_in saddr; struct timeval pertry, try; CLIENT *clp; int so; if ((hp = gethostbyname(hostname)) == NULL) { warnx("gethostbyname(%s) failed", hostname); return (0); } memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = 0; memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, sizeof(saddr.sin_addr))); pertry.tv_sec = 3; pertry.tv_usec = 0; so = RPC_ANYSOCK; - if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, - pertry, &so)) == NULL) { - clnt_pcreateerror("Cannot send MNT PRC"); + clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, pertry, &so); + if (clp == NULL) { + warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT")); return (0); } clp->cl_auth = authunix_create_default(); try.tv_sec = 3; try.tv_usec = 0; clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp, xdr_void, (caddr_t)0, try); - if (clnt_stat != RPC_SUCCESS) { - clnt_perror(clp, "Bad MNT RPC"); - return (0); - } - return (1); + if (clnt_stat != RPC_SUCCESS) + warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMOUNT")); + auth_destroy(clp->cl_auth); + clnt_destroy(clp); + return (clnt_stat == RPC_SUCCESS); } /* * Check if the entry is still/already mounted. */ int is_mounted(char *hostname, char *dirp) { struct statfs *mntbuf; char name[MNAMELEN + 1]; - size_t bufsize, hostlen, dirlen; + size_t bufsize; int mntsize, i; - hostlen = strlen(hostname); - dirlen = strlen(dirp); - if ((hostlen + dirlen) >= MNAMELEN) + if (strlen(hostname) + strlen(dirp) >= MNAMELEN) return (0); - memmove(name, hostname, hostlen); - name[hostlen] = ':'; - memmove(name + hostlen + 1, dirp, dirlen); - name[hostlen + dirlen + 1] = '\0'; + snprintf(name, sizeof(name), "%s:%s", hostname, dirp); mntsize = getfsstat(NULL, 0, MNT_NOWAIT); if (mntsize <= 0) return (0); bufsize = (mntsize + 1) * sizeof(struct statfs); if ((mntbuf = malloc(bufsize)) == NULL) err(1, "malloc"); mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT); for (i = mntsize - 1; i >= 0; i--) { if (strcmp(mntbuf[i].f_mntfromname, name) == 0) { free(mntbuf); return (1); } } free(mntbuf); return (0); } /* * xdr routines for mount rpc's */ int xdr_dir(XDR *xdrsp, char *dirp) { - return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); } static void usage() { - (void)fprintf(stderr, "%s\n", - "usage: rpc.umntall [-h host] [-k] [-p path] [-t expire] [-v]"); + "usage: rpc.umntall [-kv] [-e expire] [-h host] [-p path]"); exit(1); }