18fae3551SRodney W. Grimes /*- 28fae3551SRodney W. Grimes * Copyright (c) 1980, 1989, 1993 38fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 48fae3551SRodney W. Grimes * 58fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 68fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 78fae3551SRodney W. Grimes * are met: 88fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 98fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 108fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 128fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 138fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 148fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 158fae3551SRodney W. Grimes * without specific prior written permission. 168fae3551SRodney W. Grimes * 178fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 188fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 218fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278fae3551SRodney W. Grimes * SUCH DAMAGE. 288fae3551SRodney W. Grimes */ 298fae3551SRodney W. Grimes 308fae3551SRodney W. Grimes #ifndef lint 31adb378ceSPhilippe Charnier static const char copyright[] = 328fae3551SRodney W. Grimes "@(#) Copyright (c) 1980, 1989, 1993\n\ 338fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 348fae3551SRodney W. Grimes #endif /* not lint */ 358fae3551SRodney W. Grimes 368fae3551SRodney W. Grimes #ifndef lint 37adb378ceSPhilippe Charnier #if 0 38d499a0efSBruce Evans static char sccsid[] = "@(#)umount.c 8.8 (Berkeley) 5/8/95"; 39adb378ceSPhilippe Charnier #endif 40adb378ceSPhilippe Charnier static const char rcsid[] = 417f3dea24SPeter Wemm "$FreeBSD$"; 428fae3551SRodney W. Grimes #endif /* not lint */ 438fae3551SRodney W. Grimes 448fae3551SRodney W. Grimes #include <sys/param.h> 458fae3551SRodney W. Grimes #include <sys/mount.h> 468360efbdSAlfred Perlstein #include <sys/socket.h> 47eddb4805SIan Dowse #include <sys/stat.h> 488fae3551SRodney W. Grimes 498fae3551SRodney W. Grimes #include <netdb.h> 508fae3551SRodney W. Grimes #include <rpc/rpc.h> 510775314bSDoug Rabson #include <rpcsvc/mount.h> 528fae3551SRodney W. Grimes 5338f102c2SIan Dowse #include <ctype.h> 548fae3551SRodney W. Grimes #include <err.h> 55318f2fb4SIan Dowse #include <errno.h> 568fae3551SRodney W. Grimes #include <fstab.h> 578fae3551SRodney W. Grimes #include <stdio.h> 588fae3551SRodney W. Grimes #include <stdlib.h> 598fae3551SRodney W. Grimes #include <string.h> 608fae3551SRodney W. Grimes #include <unistd.h> 618fae3551SRodney W. Grimes 62a69497d7SMatthew Dillon #include "mounttab.h" 63a69497d7SMatthew Dillon 64eddb4805SIan Dowse typedef enum { FIND, REMOVE, CHECKUNIQUE } dowhat; 65bc70c172SBrian Feldman 66*1efe3c6bSEd Schouten static struct addrinfo *nfshost_ai = NULL; 67*1efe3c6bSEd Schouten static int fflag, vflag; 68*1efe3c6bSEd Schouten static char *nfshost; 698fae3551SRodney W. Grimes 701add162cSIan Dowse struct statfs *checkmntlist(char *); 71bc70c172SBrian Feldman int checkvfsname (const char *, char **); 72eddb4805SIan Dowse struct statfs *getmntentry(const char *fromname, const char *onname, 73eddb4805SIan Dowse fsid_t *fsid, dowhat what); 74bc70c172SBrian Feldman char **makevfslist (const char *); 75bc70c172SBrian Feldman size_t mntinfo (struct statfs **); 768360efbdSAlfred Perlstein int namematch (struct addrinfo *); 77eddb4805SIan Dowse int parsehexfsid(const char *hex, fsid_t *fsid); 787f471a32SXin LI int sacmp (void *, void *); 79bc70c172SBrian Feldman int umountall (char **); 808360efbdSAlfred Perlstein int checkname (char *, char **); 81eddb4805SIan Dowse int umountfs(struct statfs *sfs); 82bc70c172SBrian Feldman void usage (void); 83bc70c172SBrian Feldman int xdr_dir (XDR *, char *); 848fae3551SRodney W. Grimes 858fae3551SRodney W. Grimes int 86bc70c172SBrian Feldman main(int argc, char *argv[]) 878fae3551SRodney W. Grimes { 888360efbdSAlfred Perlstein int all, errs, ch, mntsize, error; 89f73d495fSIan Dowse char **typelist = NULL; 90f73d495fSIan Dowse struct statfs *mntbuf, *sfs; 918360efbdSAlfred Perlstein struct addrinfo hints; 928fae3551SRodney W. Grimes 930fe9a7daSBrian Feldman all = errs = 0; 94ef258dd9SMatthew N. Dodd while ((ch = getopt(argc, argv, "AaF:fh:t:v")) != -1) 958fae3551SRodney W. Grimes switch (ch) { 96d499a0efSBruce Evans case 'A': 97d499a0efSBruce Evans all = 2; 98d499a0efSBruce Evans break; 998fae3551SRodney W. Grimes case 'a': 1008fae3551SRodney W. Grimes all = 1; 1018fae3551SRodney W. Grimes break; 102ef258dd9SMatthew N. Dodd case 'F': 103ef258dd9SMatthew N. Dodd setfstab(optarg); 104ef258dd9SMatthew N. Dodd break; 1058fae3551SRodney W. Grimes case 'f': 1068fae3551SRodney W. Grimes fflag = MNT_FORCE; 1078fae3551SRodney W. Grimes break; 108d499a0efSBruce Evans case 'h': /* -h implies -A. */ 109d499a0efSBruce Evans all = 2; 1108fae3551SRodney W. Grimes nfshost = optarg; 1118fae3551SRodney W. Grimes break; 1128fae3551SRodney W. Grimes case 't': 113d499a0efSBruce Evans if (typelist != NULL) 114bc70c172SBrian Feldman err(1, "only one -t option may be specified"); 115d499a0efSBruce Evans typelist = makevfslist(optarg); 1168fae3551SRodney W. Grimes break; 1178fae3551SRodney W. Grimes case 'v': 1188fae3551SRodney W. Grimes vflag = 1; 1198fae3551SRodney W. Grimes break; 1208fae3551SRodney W. Grimes default: 1218fae3551SRodney W. Grimes usage(); 1228fae3551SRodney W. Grimes /* NOTREACHED */ 1238fae3551SRodney W. Grimes } 1248fae3551SRodney W. Grimes argc -= optind; 1258fae3551SRodney W. Grimes argv += optind; 1268fae3551SRodney W. Grimes 127b37ce154SRick Macklem /* Start disks transferring immediately. */ 128b37ce154SRick Macklem if ((fflag & MNT_FORCE) == 0) 129b37ce154SRick Macklem sync(); 130b37ce154SRick Macklem 131adb378ceSPhilippe Charnier if ((argc == 0 && !all) || (argc != 0 && all)) 1328fae3551SRodney W. Grimes usage(); 1338fae3551SRodney W. Grimes 1348fae3551SRodney W. Grimes /* -h implies "-t nfs" if no -t flag. */ 1358fae3551SRodney W. Grimes if ((nfshost != NULL) && (typelist == NULL)) 136d499a0efSBruce Evans typelist = makevfslist("nfs"); 1378fae3551SRodney W. Grimes 1388360efbdSAlfred Perlstein if (nfshost != NULL) { 1398360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 1408360efbdSAlfred Perlstein error = getaddrinfo(nfshost, NULL, &hints, &nfshost_ai); 14121eff82fSIan Dowse if (error) 14213e2e1afSIan Dowse errx(1, "%s: %s", nfshost, gai_strerror(error)); 1438360efbdSAlfred Perlstein } 1448360efbdSAlfred Perlstein 145d499a0efSBruce Evans switch (all) { 146d499a0efSBruce Evans case 2: 147bc70c172SBrian Feldman if ((mntsize = mntinfo(&mntbuf)) <= 0) 148d499a0efSBruce Evans break; 149bc70c172SBrian Feldman /* 150bc70c172SBrian Feldman * We unmount the nfs-mounts in the reverse order 151bc70c172SBrian Feldman * that they were mounted. 152bc70c172SBrian Feldman */ 153bc70c172SBrian Feldman for (errs = 0, mntsize--; mntsize > 0; mntsize--) { 154f73d495fSIan Dowse sfs = &mntbuf[mntsize]; 155f73d495fSIan Dowse if (checkvfsname(sfs->f_fstypename, typelist)) 156d499a0efSBruce Evans continue; 15780bbaeb5SKirk McKusick if (strcmp(sfs->f_mntonname, "/dev") == 0) 15880bbaeb5SKirk McKusick continue; 159eddb4805SIan Dowse if (umountfs(sfs) != 0) 160d499a0efSBruce Evans errs = 1; 161d499a0efSBruce Evans } 162bc70c172SBrian Feldman free(mntbuf); 163d499a0efSBruce Evans break; 164d499a0efSBruce Evans case 1: 1658fae3551SRodney W. Grimes if (setfsent() == 0) 166ef258dd9SMatthew N. Dodd err(1, "%s", getfstab()); 167d499a0efSBruce Evans errs = umountall(typelist); 168d499a0efSBruce Evans break; 169d499a0efSBruce Evans case 0: 1708fae3551SRodney W. Grimes for (errs = 0; *argv != NULL; ++argv) 1718360efbdSAlfred Perlstein if (checkname(*argv, typelist) != 0) 172d499a0efSBruce Evans errs = 1; 173d499a0efSBruce Evans break; 174d499a0efSBruce Evans } 1758fae3551SRodney W. Grimes exit(errs); 1768fae3551SRodney W. Grimes } 1778fae3551SRodney W. Grimes 1788fae3551SRodney W. Grimes int 179bc70c172SBrian Feldman umountall(char **typelist) 1808fae3551SRodney W. Grimes { 1815965373eSMaxime Henrion struct xvfsconf vfc; 1828fae3551SRodney W. Grimes struct fstab *fs; 183adb378ceSPhilippe Charnier int rval; 1848fae3551SRodney W. Grimes char *cp; 1850602ee7cSBrian Feldman static int firstcall = 1; 1868fae3551SRodney W. Grimes 18791a81678SBrian Feldman if ((fs = getfsent()) != NULL) 1880602ee7cSBrian Feldman firstcall = 0; 18991a81678SBrian Feldman else if (firstcall) 19091a81678SBrian Feldman errx(1, "fstab reading failure"); 19191a81678SBrian Feldman else 19291a81678SBrian Feldman return (0); 193bc70c172SBrian Feldman do { 1948fae3551SRodney W. Grimes /* Ignore the root. */ 1958fae3551SRodney W. Grimes if (strcmp(fs->fs_file, "/") == 0) 1968fae3551SRodney W. Grimes continue; 1978fae3551SRodney W. Grimes /* 1988fae3551SRodney W. Grimes * !!! 1998fae3551SRodney W. Grimes * Historic practice: ignore unknown FSTAB_* fields. 2008fae3551SRodney W. Grimes */ 2018fae3551SRodney W. Grimes if (strcmp(fs->fs_type, FSTAB_RW) && 2028fae3551SRodney W. Grimes strcmp(fs->fs_type, FSTAB_RO) && 2038fae3551SRodney W. Grimes strcmp(fs->fs_type, FSTAB_RQ)) 2048fae3551SRodney W. Grimes continue; 205b6e55a05SDag-Erling Smørgrav /* Ignore unknown file system types. */ 20681667275SDag-Erling Smørgrav if (getvfsbyname(fs->fs_vfstype, &vfc) == -1) 2078fae3551SRodney W. Grimes continue; 208d499a0efSBruce Evans if (checkvfsname(fs->fs_vfstype, typelist)) 2098fae3551SRodney W. Grimes continue; 2108fae3551SRodney W. Grimes 2118fae3551SRodney W. Grimes /* 2128fae3551SRodney W. Grimes * We want to unmount the file systems in the reverse order 2138fae3551SRodney W. Grimes * that they were mounted. So, we save off the file name 2148fae3551SRodney W. Grimes * in some allocated memory, and then call recursively. 2158fae3551SRodney W. Grimes */ 2168fae3551SRodney W. Grimes if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL) 217bc70c172SBrian Feldman err(1, "malloc failed"); 2188fae3551SRodney W. Grimes (void)strcpy(cp, fs->fs_file); 219d499a0efSBruce Evans rval = umountall(typelist); 2208360efbdSAlfred Perlstein rval = checkname(cp, typelist) || rval; 221bc70c172SBrian Feldman free(cp); 2220602ee7cSBrian Feldman return (rval); 2230602ee7cSBrian Feldman } while ((fs = getfsent()) != NULL); 2248fae3551SRodney W. Grimes return (0); 2258fae3551SRodney W. Grimes } 2268fae3551SRodney W. Grimes 2278360efbdSAlfred Perlstein /* 228eddb4805SIan Dowse * Do magic checks on mountpoint/device/fsid, and then call unmount(2). 2298360efbdSAlfred Perlstein */ 2308fae3551SRodney W. Grimes int 2317f471a32SXin LI checkname(char *mntname, char **typelist) 2328fae3551SRodney W. Grimes { 233eddb4805SIan Dowse char buf[MAXPATHLEN]; 234eddb4805SIan Dowse struct statfs sfsbuf; 235eddb4805SIan Dowse struct stat sb; 236f73d495fSIan Dowse struct statfs *sfs; 237eddb4805SIan Dowse char *delimp; 238eddb4805SIan Dowse dev_t dev; 239eddb4805SIan Dowse int len; 2408fae3551SRodney W. Grimes 241bc70c172SBrian Feldman /* 242bc70c172SBrian Feldman * 1. Check if the name exists in the mounttable. 243bc70c172SBrian Feldman */ 2447f471a32SXin LI sfs = checkmntlist(mntname); 245bc70c172SBrian Feldman /* 246bc70c172SBrian Feldman * 2. Remove trailing slashes if there are any. After that 247bc70c172SBrian Feldman * we look up the name in the mounttable again. 248bc70c172SBrian Feldman */ 249318f2fb4SIan Dowse if (sfs == NULL) { 2507f471a32SXin LI len = strlen(mntname); 2517f471a32SXin LI while (len > 1 && mntname[len - 1] == '/') 2527f471a32SXin LI mntname[--len] = '\0'; 2537f471a32SXin LI sfs = checkmntlist(mntname); 254bc70c172SBrian Feldman } 255bc70c172SBrian Feldman /* 256eddb4805SIan Dowse * 3. Check if the deprecated NFS syntax with an '@' has been used 257eddb4805SIan Dowse * and translate it to the ':' syntax. Look up the name in the 258eddb4805SIan Dowse * mount table again. 259bc70c172SBrian Feldman */ 2607f471a32SXin LI if (sfs == NULL && (delimp = strrchr(mntname, '@')) != NULL) { 2617f471a32SXin LI snprintf(buf, sizeof(buf), "%s:%.*s", delimp + 1, 2627f471a32SXin LI (int)(delimp - mntname), mntname); 263eddb4805SIan Dowse len = strlen(buf); 2645fff0914SIan Dowse while (len > 1 && buf[len - 1] == '/') 265eddb4805SIan Dowse buf[--len] = '\0'; 266eddb4805SIan Dowse sfs = checkmntlist(buf); 267bc70c172SBrian Feldman } 268bc70c172SBrian Feldman /* 269eddb4805SIan Dowse * 4. Resort to a statfs(2) call. This is the last check so that 270eddb4805SIan Dowse * hung NFS filesystems for example can be unmounted without 271eddb4805SIan Dowse * potentially blocking forever in statfs() as long as the 272eddb4805SIan Dowse * filesystem is specified unambiguously. This covers all the 273eddb4805SIan Dowse * hard cases such as symlinks and mismatches between the 274eddb4805SIan Dowse * mount list and reality. 275eddb4805SIan Dowse * We also do this if an ambiguous mount point was specified. 276bc70c172SBrian Feldman */ 2777f471a32SXin LI if (sfs == NULL || (getmntentry(NULL, mntname, NULL, FIND) != NULL && 2787f471a32SXin LI getmntentry(NULL, mntname, NULL, CHECKUNIQUE) == NULL)) { 2797f471a32SXin LI if (statfs(mntname, &sfsbuf) != 0) { 2807f471a32SXin LI warn("%s: statfs", mntname); 2817f471a32SXin LI } else if (stat(mntname, &sb) != 0) { 2827f471a32SXin LI warn("%s: stat", mntname); 283eddb4805SIan Dowse } else if (S_ISDIR(sb.st_mode)) { 2847f471a32SXin LI /* Check that `mntname' is the root directory. */ 285eddb4805SIan Dowse dev = sb.st_dev; 2867f471a32SXin LI snprintf(buf, sizeof(buf), "%s/..", mntname); 287eddb4805SIan Dowse if (stat(buf, &sb) != 0) { 288eddb4805SIan Dowse warn("%s: stat", buf); 289eddb4805SIan Dowse } else if (sb.st_dev == dev) { 290eddb4805SIan Dowse warnx("%s: not a file system root directory", 2917f471a32SXin LI mntname); 292eddb4805SIan Dowse return (1); 2938360efbdSAlfred Perlstein } else 294eddb4805SIan Dowse sfs = &sfsbuf; 295eddb4805SIan Dowse } 296eddb4805SIan Dowse } 297eddb4805SIan Dowse if (sfs == NULL) { 2987f471a32SXin LI warnx("%s: unknown file system", mntname); 2998fae3551SRodney W. Grimes return (1); 3008fae3551SRodney W. Grimes } 3011add162cSIan Dowse if (checkvfsname(sfs->f_fstypename, typelist)) 302d499a0efSBruce Evans return (1); 303eddb4805SIan Dowse return (umountfs(sfs)); 3048360efbdSAlfred Perlstein } 3058360efbdSAlfred Perlstein 3068360efbdSAlfred Perlstein /* 3078360efbdSAlfred Perlstein * NFS stuff and unmount(2) call 3088360efbdSAlfred Perlstein */ 3098360efbdSAlfred Perlstein int 310eddb4805SIan Dowse umountfs(struct statfs *sfs) 3118360efbdSAlfred Perlstein { 312318f2fb4SIan Dowse char fsidbuf[64]; 3138360efbdSAlfred Perlstein enum clnt_stat clnt_stat; 3148360efbdSAlfred Perlstein struct timeval try; 3158360efbdSAlfred Perlstein struct addrinfo *ai, hints; 3168360efbdSAlfred Perlstein int do_rpc; 3178360efbdSAlfred Perlstein CLIENT *clp; 3188360efbdSAlfred Perlstein char *nfsdirname, *orignfsdirname; 3198360efbdSAlfred Perlstein char *hostp, *delimp; 3208360efbdSAlfred Perlstein 3218360efbdSAlfred Perlstein ai = NULL; 32213e2e1afSIan Dowse do_rpc = 0; 32313e2e1afSIan Dowse hostp = NULL; 3248360efbdSAlfred Perlstein nfsdirname = delimp = orignfsdirname = NULL; 3258360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 3268360efbdSAlfred Perlstein 327eddb4805SIan Dowse if (strcmp(sfs->f_fstypename, "nfs") == 0) { 328eddb4805SIan Dowse if ((nfsdirname = strdup(sfs->f_mntfromname)) == NULL) 3298360efbdSAlfred Perlstein err(1, "strdup"); 3308360efbdSAlfred Perlstein orignfsdirname = nfsdirname; 331a505d435SHajimu UMEMOTO if (*nfsdirname == '[' && 332a505d435SHajimu UMEMOTO (delimp = strchr(nfsdirname + 1, ']')) != NULL && 333a505d435SHajimu UMEMOTO *(delimp + 1) == ':') { 334a505d435SHajimu UMEMOTO hostp = nfsdirname + 1; 335a505d435SHajimu UMEMOTO nfsdirname = delimp + 2; 336a505d435SHajimu UMEMOTO } else if ((delimp = strrchr(nfsdirname, ':')) != NULL) { 3378360efbdSAlfred Perlstein hostp = nfsdirname; 338a505d435SHajimu UMEMOTO nfsdirname = delimp + 1; 339a505d435SHajimu UMEMOTO } 340a505d435SHajimu UMEMOTO if (hostp != NULL) { 341a505d435SHajimu UMEMOTO *delimp = '\0'; 3428360efbdSAlfred Perlstein getaddrinfo(hostp, NULL, &hints, &ai); 3438360efbdSAlfred Perlstein if (ai == NULL) { 3448360efbdSAlfred Perlstein warnx("can't get net id for host"); 3458360efbdSAlfred Perlstein } 3468360efbdSAlfred Perlstein } 34713e2e1afSIan Dowse 348bc70c172SBrian Feldman /* 349bc70c172SBrian Feldman * Check if we have to start the rpc-call later. 350bc70c172SBrian Feldman * If there are still identical nfs-names mounted, 351bc70c172SBrian Feldman * we skip the rpc-call. Obviously this has to 352bc70c172SBrian Feldman * happen before unmount(2), but it should happen 353bc70c172SBrian Feldman * after the previous namecheck. 35413e2e1afSIan Dowse * A non-NULL return means that this is the last 35513e2e1afSIan Dowse * mount from mntfromname that is still mounted. 356bc70c172SBrian Feldman */ 357eddb4805SIan Dowse if (getmntentry(sfs->f_mntfromname, NULL, NULL, 358eddb4805SIan Dowse CHECKUNIQUE) != NULL) 3590fe9a7daSBrian Feldman do_rpc = 1; 36013e2e1afSIan Dowse } 3618360efbdSAlfred Perlstein 3628360efbdSAlfred Perlstein if (!namematch(ai)) 363d499a0efSBruce Evans return (1); 364eddb4805SIan Dowse /* First try to unmount using the file system ID. */ 365eddb4805SIan Dowse snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", sfs->f_fsid.val[0], 366eddb4805SIan Dowse sfs->f_fsid.val[1]); 367318f2fb4SIan Dowse if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) { 3680ed25a9aSIan Dowse /* XXX, non-root users get a zero fsid, so don't warn. */ 3690ed25a9aSIan Dowse if (errno != ENOENT || sfs->f_fsid.val[0] != 0 || 3700ed25a9aSIan Dowse sfs->f_fsid.val[1] != 0) 371eddb4805SIan Dowse warn("unmount of %s failed", sfs->f_mntonname); 372318f2fb4SIan Dowse if (errno != ENOENT) 373318f2fb4SIan Dowse return (1); 3748b918187SIan Dowse /* Compatibility for old kernels. */ 3758b918187SIan Dowse if (sfs->f_fsid.val[0] != 0 || sfs->f_fsid.val[1] != 0) 376318f2fb4SIan Dowse warnx("retrying using path instead of file system ID"); 377eddb4805SIan Dowse if (unmount(sfs->f_mntonname, fflag) != 0) { 378eddb4805SIan Dowse warn("unmount of %s failed", sfs->f_mntonname); 3798fae3551SRodney W. Grimes return (1); 3808fae3551SRodney W. Grimes } 381eddb4805SIan Dowse } 382eddb4805SIan Dowse /* Mark this this file system as unmounted. */ 383eddb4805SIan Dowse getmntentry(NULL, NULL, &sfs->f_fsid, REMOVE); 384bc70c172SBrian Feldman if (vflag) 385eddb4805SIan Dowse (void)printf("%s: unmount from %s\n", sfs->f_mntfromname, 386eddb4805SIan Dowse sfs->f_mntonname); 387bc70c172SBrian Feldman /* 388bc70c172SBrian Feldman * Report to mountd-server which nfsname 389bc70c172SBrian Feldman * has been unmounted. 390bc70c172SBrian Feldman */ 3918360efbdSAlfred Perlstein if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) { 3920775314bSDoug Rabson clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS, "udp"); 3938360efbdSAlfred Perlstein if (clp == NULL) { 39413e2e1afSIan Dowse warnx("%s: %s", hostp, 3950775314bSDoug Rabson clnt_spcreateerror("MOUNTPROG")); 3968fae3551SRodney W. Grimes return (1); 3978fae3551SRodney W. Grimes } 3988360efbdSAlfred Perlstein clp->cl_auth = authsys_create_default(); 3998fae3551SRodney W. Grimes try.tv_sec = 20; 4008fae3551SRodney W. Grimes try.tv_usec = 0; 4010775314bSDoug Rabson clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir, 4025c514aeeSMatthew N. Dodd nfsdirname, (xdrproc_t)xdr_void, (caddr_t)0, try); 4038fae3551SRodney W. Grimes if (clnt_stat != RPC_SUCCESS) { 40413e2e1afSIan Dowse warnx("%s: %s", hostp, 40513e2e1afSIan Dowse clnt_sperror(clp, "RPCMNT_UMOUNT")); 4068fae3551SRodney W. Grimes return (1); 4078fae3551SRodney W. Grimes } 408a69497d7SMatthew Dillon /* 409a69497d7SMatthew Dillon * Remove the unmounted entry from /var/db/mounttab. 410a69497d7SMatthew Dillon */ 411afe1ef24SIan Dowse if (read_mtab()) { 412afe1ef24SIan Dowse clean_mtab(hostp, nfsdirname, vflag); 413afe1ef24SIan Dowse if(!write_mtab(vflag)) 41413e2e1afSIan Dowse warnx("cannot remove mounttab entry %s:%s", 415a69497d7SMatthew Dillon hostp, nfsdirname); 416a69497d7SMatthew Dillon free_mtab(); 417a69497d7SMatthew Dillon } 418bc70c172SBrian Feldman free(orignfsdirname); 4198fae3551SRodney W. Grimes auth_destroy(clp->cl_auth); 4208fae3551SRodney W. Grimes clnt_destroy(clp); 4218fae3551SRodney W. Grimes } 4228fae3551SRodney W. Grimes return (0); 4238fae3551SRodney W. Grimes } 4248fae3551SRodney W. Grimes 425318f2fb4SIan Dowse struct statfs * 426eddb4805SIan Dowse getmntentry(const char *fromname, const char *onname, fsid_t *fsid, dowhat what) 4278fae3551SRodney W. Grimes { 428d499a0efSBruce Evans static struct statfs *mntbuf; 429bc70c172SBrian Feldman static size_t mntsize = 0; 430bc70c172SBrian Feldman static char *mntcheck = NULL; 431eddb4805SIan Dowse struct statfs *sfs, *foundsfs; 432bc70c172SBrian Feldman int i, count; 4338fae3551SRodney W. Grimes 434bc70c172SBrian Feldman if (mntsize <= 0) { 435bc70c172SBrian Feldman if ((mntsize = mntinfo(&mntbuf)) <= 0) 4368fae3551SRodney W. Grimes return (NULL); 4378fae3551SRodney W. Grimes } 438bc70c172SBrian Feldman if (mntcheck == NULL) { 439eddb4805SIan Dowse if ((mntcheck = calloc(mntsize + 1, sizeof(int))) == NULL) 440bc70c172SBrian Feldman err(1, "calloc"); 441bc70c172SBrian Feldman } 442bc70c172SBrian Feldman /* 443bc70c172SBrian Feldman * We want to get the file systems in the reverse order 444eddb4805SIan Dowse * that they were mounted. Unmounted file systems are marked 445eddb4805SIan Dowse * in a table called 'mntcheck'. 446bc70c172SBrian Feldman */ 447eddb4805SIan Dowse count = 0; 448eddb4805SIan Dowse foundsfs = NULL; 449bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 450eddb4805SIan Dowse if (mntcheck[i]) 451eddb4805SIan Dowse continue; 452eddb4805SIan Dowse sfs = &mntbuf[i]; 453eddb4805SIan Dowse if (fromname != NULL && strcmp(sfs->f_mntfromname, 454eddb4805SIan Dowse fromname) != 0) 455eddb4805SIan Dowse continue; 456eddb4805SIan Dowse if (onname != NULL && strcmp(sfs->f_mntonname, onname) != 0) 457eddb4805SIan Dowse continue; 458eddb4805SIan Dowse if (fsid != NULL && bcmp(&sfs->f_fsid, fsid, 459eddb4805SIan Dowse sizeof(*fsid)) != 0) 460eddb4805SIan Dowse continue; 461eddb4805SIan Dowse 46238f102c2SIan Dowse switch (what) { 463eddb4805SIan Dowse case CHECKUNIQUE: 464eddb4805SIan Dowse foundsfs = sfs; 465eddb4805SIan Dowse count++; 46638f102c2SIan Dowse continue; 467eddb4805SIan Dowse case REMOVE: 468eddb4805SIan Dowse mntcheck[i] = 1; 46938f102c2SIan Dowse break; 470eddb4805SIan Dowse default: 47138f102c2SIan Dowse break; 47238f102c2SIan Dowse } 473eddb4805SIan Dowse return (sfs); 4748fae3551SRodney W. Grimes } 475318f2fb4SIan Dowse 476eddb4805SIan Dowse if (what == CHECKUNIQUE && count == 1) 477eddb4805SIan Dowse return (foundsfs); 4788fae3551SRodney W. Grimes return (NULL); 4798fae3551SRodney W. Grimes } 4808fae3551SRodney W. Grimes 4818fae3551SRodney W. Grimes int 4827f471a32SXin LI sacmp(void *sa1, void *sa2) 4838fae3551SRodney W. Grimes { 4848360efbdSAlfred Perlstein void *p1, *p2; 4858360efbdSAlfred Perlstein int len; 4868fae3551SRodney W. Grimes 4877f471a32SXin LI if (((struct sockaddr *)sa1)->sa_family != 4887f471a32SXin LI ((struct sockaddr *)sa2)->sa_family) 4898fae3551SRodney W. Grimes return (1); 4908fae3551SRodney W. Grimes 4917f471a32SXin LI switch (((struct sockaddr *)sa1)->sa_family) { 4928360efbdSAlfred Perlstein case AF_INET: 4938360efbdSAlfred Perlstein p1 = &((struct sockaddr_in *)sa1)->sin_addr; 4948360efbdSAlfred Perlstein p2 = &((struct sockaddr_in *)sa2)->sin_addr; 4958360efbdSAlfred Perlstein len = 4; 4968360efbdSAlfred Perlstein break; 4978360efbdSAlfred Perlstein case AF_INET6: 4988360efbdSAlfred Perlstein p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr; 4998360efbdSAlfred Perlstein p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr; 5008360efbdSAlfred Perlstein len = 16; 5018360efbdSAlfred Perlstein if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 5028360efbdSAlfred Perlstein ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 5038360efbdSAlfred Perlstein return (1); 5048360efbdSAlfred Perlstein break; 5058360efbdSAlfred Perlstein default: 5068360efbdSAlfred Perlstein return (1); 5078360efbdSAlfred Perlstein } 5088360efbdSAlfred Perlstein 5098360efbdSAlfred Perlstein return memcmp(p1, p2, len); 5108360efbdSAlfred Perlstein } 5118360efbdSAlfred Perlstein 5128360efbdSAlfred Perlstein int 5138360efbdSAlfred Perlstein namematch(struct addrinfo *ai) 5148360efbdSAlfred Perlstein { 5158360efbdSAlfred Perlstein struct addrinfo *aip; 5168360efbdSAlfred Perlstein 5178360efbdSAlfred Perlstein if (nfshost == NULL || nfshost_ai == NULL) 5188fae3551SRodney W. Grimes return (1); 5198fae3551SRodney W. Grimes 5208360efbdSAlfred Perlstein while (ai != NULL) { 5218360efbdSAlfred Perlstein aip = nfshost_ai; 5228360efbdSAlfred Perlstein while (aip != NULL) { 5238360efbdSAlfred Perlstein if (sacmp(ai->ai_addr, aip->ai_addr) == 0) 5248fae3551SRodney W. Grimes return (1); 5258360efbdSAlfred Perlstein aip = aip->ai_next; 5268fae3551SRodney W. Grimes } 5278360efbdSAlfred Perlstein ai = ai->ai_next; 5288fae3551SRodney W. Grimes } 5298360efbdSAlfred Perlstein 5308fae3551SRodney W. Grimes return (0); 5318fae3551SRodney W. Grimes } 5328fae3551SRodney W. Grimes 533318f2fb4SIan Dowse struct statfs * 5347f471a32SXin LI checkmntlist(char *mntname) 535bc70c172SBrian Feldman { 536318f2fb4SIan Dowse struct statfs *sfs; 537eddb4805SIan Dowse fsid_t fsid; 538bc70c172SBrian Feldman 539eddb4805SIan Dowse sfs = NULL; 5407f471a32SXin LI if (parsehexfsid(mntname, &fsid) == 0) 541eddb4805SIan Dowse sfs = getmntentry(NULL, NULL, &fsid, FIND); 54238f102c2SIan Dowse if (sfs == NULL) 5437f471a32SXin LI sfs = getmntentry(NULL, mntname, NULL, FIND); 544318f2fb4SIan Dowse if (sfs == NULL) 5457f471a32SXin LI sfs = getmntentry(mntname, NULL, NULL, FIND); 546318f2fb4SIan Dowse return (sfs); 547bc70c172SBrian Feldman } 548bc70c172SBrian Feldman 549bc70c172SBrian Feldman size_t 550bc70c172SBrian Feldman mntinfo(struct statfs **mntbuf) 551bc70c172SBrian Feldman { 552bc70c172SBrian Feldman static struct statfs *origbuf; 553bc70c172SBrian Feldman size_t bufsize; 554bc70c172SBrian Feldman int mntsize; 555bc70c172SBrian Feldman 556a69497d7SMatthew Dillon mntsize = getfsstat(NULL, 0, MNT_NOWAIT); 557bc70c172SBrian Feldman if (mntsize <= 0) 558bc70c172SBrian Feldman return (0); 559bc70c172SBrian Feldman bufsize = (mntsize + 1) * sizeof(struct statfs); 560bc70c172SBrian Feldman if ((origbuf = malloc(bufsize)) == NULL) 561bc70c172SBrian Feldman err(1, "malloc"); 562bc70c172SBrian Feldman mntsize = getfsstat(origbuf, (long)bufsize, MNT_NOWAIT); 563bc70c172SBrian Feldman *mntbuf = origbuf; 564bc70c172SBrian Feldman return (mntsize); 565bc70c172SBrian Feldman } 566bc70c172SBrian Feldman 567eddb4805SIan Dowse /* 5688b918187SIan Dowse * Convert a hexadecimal filesystem ID to an fsid_t. 569eddb4805SIan Dowse * Returns 0 on success. 570eddb4805SIan Dowse */ 571eddb4805SIan Dowse int 572eddb4805SIan Dowse parsehexfsid(const char *hex, fsid_t *fsid) 573bc70c172SBrian Feldman { 574eddb4805SIan Dowse char hexbuf[3]; 575eddb4805SIan Dowse int i; 576bc70c172SBrian Feldman 577eddb4805SIan Dowse if (strlen(hex) != sizeof(*fsid) * 2) 578eddb4805SIan Dowse return (-1); 579eddb4805SIan Dowse hexbuf[2] = '\0'; 5805fff0914SIan Dowse for (i = 0; i < (int)sizeof(*fsid); i++) { 581eddb4805SIan Dowse hexbuf[0] = hex[i * 2]; 582eddb4805SIan Dowse hexbuf[1] = hex[i * 2 + 1]; 583eddb4805SIan Dowse if (!isxdigit(hexbuf[0]) || !isxdigit(hexbuf[1])) 584eddb4805SIan Dowse return (-1); 585eddb4805SIan Dowse ((u_char *)fsid)[i] = strtol(hexbuf, NULL, 16); 586bc70c172SBrian Feldman } 587eddb4805SIan Dowse return (0); 588bc70c172SBrian Feldman } 589bc70c172SBrian Feldman 5908fae3551SRodney W. Grimes /* 5918fae3551SRodney W. Grimes * xdr routines for mount rpc's 5928fae3551SRodney W. Grimes */ 5938fae3551SRodney W. Grimes int 594bc70c172SBrian Feldman xdr_dir(XDR *xdrsp, char *dirp) 5958fae3551SRodney W. Grimes { 596bc70c172SBrian Feldman 5970775314bSDoug Rabson return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 5988fae3551SRodney W. Grimes } 5998fae3551SRodney W. Grimes 6008fae3551SRodney W. Grimes void 601ca25fa25SEd Schouten usage(void) 6028fae3551SRodney W. Grimes { 603bc70c172SBrian Feldman 604210a5dc8SPhilippe Charnier (void)fprintf(stderr, "%s\n%s\n", 60534ae1bb6SRuslan Ermilov "usage: umount [-fv] special ... | node ... | fsid ...", 606ef258dd9SMatthew N. Dodd " umount -a | -A [-F fstab] [-fv] [-h host] [-t type]"); 6078fae3551SRodney W. Grimes exit(1); 6088fae3551SRodney W. Grimes } 609