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 * 3. All advertising materials mentioning features or use of this software 148fae3551SRodney W. Grimes * must display the following acknowledgement: 158fae3551SRodney W. Grimes * This product includes software developed by the University of 168fae3551SRodney W. Grimes * California, Berkeley and its contributors. 178fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 188fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 198fae3551SRodney W. Grimes * without specific prior written permission. 208fae3551SRodney W. Grimes * 218fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 228fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 238fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 248fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 258fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 268fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 278fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 288fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 298fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 308fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 318fae3551SRodney W. Grimes * SUCH DAMAGE. 328fae3551SRodney W. Grimes */ 338fae3551SRodney W. Grimes 348fae3551SRodney W. Grimes #ifndef lint 35adb378ceSPhilippe Charnier static const char copyright[] = 368fae3551SRodney W. Grimes "@(#) Copyright (c) 1980, 1989, 1993\n\ 378fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 388fae3551SRodney W. Grimes #endif /* not lint */ 398fae3551SRodney W. Grimes 408fae3551SRodney W. Grimes #ifndef lint 41adb378ceSPhilippe Charnier #if 0 42d499a0efSBruce Evans static char sccsid[] = "@(#)umount.c 8.8 (Berkeley) 5/8/95"; 43adb378ceSPhilippe Charnier #endif 44adb378ceSPhilippe Charnier static const char rcsid[] = 457f3dea24SPeter Wemm "$FreeBSD$"; 468fae3551SRodney W. Grimes #endif /* not lint */ 478fae3551SRodney W. Grimes 488fae3551SRodney W. Grimes #include <sys/param.h> 498fae3551SRodney W. Grimes #include <sys/mount.h> 508360efbdSAlfred Perlstein #include <sys/socket.h> 518fae3551SRodney W. Grimes 528fae3551SRodney W. Grimes #include <netdb.h> 538fae3551SRodney W. Grimes #include <rpc/rpc.h> 548fae3551SRodney W. Grimes #include <nfs/rpcv2.h> 558fae3551SRodney W. Grimes 568fae3551SRodney W. Grimes #include <err.h> 57318f2fb4SIan Dowse #include <errno.h> 588fae3551SRodney W. Grimes #include <fstab.h> 598fae3551SRodney W. Grimes #include <stdio.h> 608fae3551SRodney W. Grimes #include <stdlib.h> 618fae3551SRodney W. Grimes #include <string.h> 628fae3551SRodney W. Grimes #include <unistd.h> 638fae3551SRodney W. Grimes 64a69497d7SMatthew Dillon #include "mounttab.h" 65a69497d7SMatthew Dillon 66bc70c172SBrian Feldman #define ISDOT(x) ((x)[0] == '.' && (x)[1] == '\0') 67bc70c172SBrian Feldman #define ISDOTDOT(x) ((x)[0] == '.' && (x)[1] == '.' && (x)[2] == '\0') 688fae3551SRodney W. Grimes 69bc70c172SBrian Feldman typedef enum { MNTON, MNTFROM, NOTHING } mntwhat; 70bc70c172SBrian Feldman typedef enum { MARK, UNMARK, NAME, COUNT, FREE } dowhat; 71bc70c172SBrian Feldman 728360efbdSAlfred Perlstein struct addrinfo *nfshost_ai = NULL; 730fe9a7daSBrian Feldman int fflag, vflag; 748fae3551SRodney W. Grimes char *nfshost; 758fae3551SRodney W. Grimes 76318f2fb4SIan Dowse struct statfs *checkmntlist (char *, char **); 77bc70c172SBrian Feldman int checkvfsname (const char *, char **); 78318f2fb4SIan Dowse struct statfs *getmntentry (const char *, const char *, mntwhat, char **, 79318f2fb4SIan Dowse dowhat); 80bc70c172SBrian Feldman char *getrealname(char *, char *resolved_path); 81bc70c172SBrian Feldman char **makevfslist (const char *); 82bc70c172SBrian Feldman size_t mntinfo (struct statfs **); 838360efbdSAlfred Perlstein int namematch (struct addrinfo *); 848360efbdSAlfred Perlstein int sacmp (struct sockaddr *, struct sockaddr *); 85bc70c172SBrian Feldman int umountall (char **); 868360efbdSAlfred Perlstein int checkname (char *, char **); 87318f2fb4SIan Dowse int umountfs (char *, char *, fsid_t *, char *); 88bc70c172SBrian Feldman void usage (void); 89bc70c172SBrian Feldman int xdr_dir (XDR *, char *); 908fae3551SRodney W. Grimes 918fae3551SRodney W. Grimes int 92bc70c172SBrian Feldman main(int argc, char *argv[]) 938fae3551SRodney W. Grimes { 948360efbdSAlfred Perlstein int all, errs, ch, mntsize, error; 95f73d495fSIan Dowse char **typelist = NULL; 96f73d495fSIan Dowse struct statfs *mntbuf, *sfs; 978360efbdSAlfred Perlstein struct addrinfo hints; 988fae3551SRodney W. Grimes 998fae3551SRodney W. Grimes /* Start disks transferring immediately. */ 1008fae3551SRodney W. Grimes sync(); 1018fae3551SRodney W. Grimes 1020fe9a7daSBrian Feldman all = errs = 0; 103ef258dd9SMatthew N. Dodd while ((ch = getopt(argc, argv, "AaF:fh:t:v")) != -1) 1048fae3551SRodney W. Grimes switch (ch) { 105d499a0efSBruce Evans case 'A': 106d499a0efSBruce Evans all = 2; 107d499a0efSBruce Evans break; 1088fae3551SRodney W. Grimes case 'a': 1098fae3551SRodney W. Grimes all = 1; 1108fae3551SRodney W. Grimes break; 111ef258dd9SMatthew N. Dodd case 'F': 112ef258dd9SMatthew N. Dodd setfstab(optarg); 113ef258dd9SMatthew N. Dodd break; 1148fae3551SRodney W. Grimes case 'f': 1158fae3551SRodney W. Grimes fflag = MNT_FORCE; 1168fae3551SRodney W. Grimes break; 117d499a0efSBruce Evans case 'h': /* -h implies -A. */ 118d499a0efSBruce Evans all = 2; 1198fae3551SRodney W. Grimes nfshost = optarg; 1208fae3551SRodney W. Grimes break; 1218fae3551SRodney W. Grimes case 't': 122d499a0efSBruce Evans if (typelist != NULL) 123bc70c172SBrian Feldman err(1, "only one -t option may be specified"); 124d499a0efSBruce Evans typelist = makevfslist(optarg); 1258fae3551SRodney W. Grimes break; 1268fae3551SRodney W. Grimes case 'v': 1278fae3551SRodney W. Grimes vflag = 1; 1288fae3551SRodney W. Grimes break; 1298fae3551SRodney W. Grimes default: 1308fae3551SRodney W. Grimes usage(); 1318fae3551SRodney W. Grimes /* NOTREACHED */ 1328fae3551SRodney W. Grimes } 1338fae3551SRodney W. Grimes argc -= optind; 1348fae3551SRodney W. Grimes argv += optind; 1358fae3551SRodney W. Grimes 136adb378ceSPhilippe Charnier if ((argc == 0 && !all) || (argc != 0 && all)) 1378fae3551SRodney W. Grimes usage(); 1388fae3551SRodney W. Grimes 1398fae3551SRodney W. Grimes /* -h implies "-t nfs" if no -t flag. */ 1408fae3551SRodney W. Grimes if ((nfshost != NULL) && (typelist == NULL)) 141d499a0efSBruce Evans typelist = makevfslist("nfs"); 1428fae3551SRodney W. Grimes 1438360efbdSAlfred Perlstein if (nfshost != NULL) { 1448360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 1458360efbdSAlfred Perlstein error = getaddrinfo(nfshost, NULL, &hints, &nfshost_ai); 14621eff82fSIan Dowse if (error) 14713e2e1afSIan Dowse errx(1, "%s: %s", nfshost, gai_strerror(error)); 1488360efbdSAlfred Perlstein } 1498360efbdSAlfred Perlstein 150d499a0efSBruce Evans switch (all) { 151d499a0efSBruce Evans case 2: 152bc70c172SBrian Feldman if ((mntsize = mntinfo(&mntbuf)) <= 0) 153d499a0efSBruce Evans break; 154bc70c172SBrian Feldman /* 155bc70c172SBrian Feldman * We unmount the nfs-mounts in the reverse order 156bc70c172SBrian Feldman * that they were mounted. 157bc70c172SBrian Feldman */ 158bc70c172SBrian Feldman for (errs = 0, mntsize--; mntsize > 0; mntsize--) { 159f73d495fSIan Dowse sfs = &mntbuf[mntsize]; 160f73d495fSIan Dowse if (checkvfsname(sfs->f_fstypename, typelist)) 161d499a0efSBruce Evans continue; 162f73d495fSIan Dowse if (umountfs(sfs->f_mntfromname, sfs->f_mntonname, 163f73d495fSIan Dowse &sfs->f_fsid, sfs->f_fstypename) != 0) 164d499a0efSBruce Evans errs = 1; 165d499a0efSBruce Evans } 166bc70c172SBrian Feldman free(mntbuf); 167d499a0efSBruce Evans break; 168d499a0efSBruce Evans case 1: 1698fae3551SRodney W. Grimes if (setfsent() == 0) 170ef258dd9SMatthew N. Dodd err(1, "%s", getfstab()); 171d499a0efSBruce Evans errs = umountall(typelist); 172d499a0efSBruce Evans break; 173d499a0efSBruce Evans case 0: 1748fae3551SRodney W. Grimes for (errs = 0; *argv != NULL; ++argv) 1758360efbdSAlfred Perlstein if (checkname(*argv, typelist) != 0) 176d499a0efSBruce Evans errs = 1; 177d499a0efSBruce Evans break; 178d499a0efSBruce Evans } 179318f2fb4SIan Dowse (void)getmntentry(NULL, NULL, NOTHING, NULL, FREE); 1808fae3551SRodney W. Grimes exit(errs); 1818fae3551SRodney W. Grimes } 1828fae3551SRodney W. Grimes 1838fae3551SRodney W. Grimes int 184bc70c172SBrian Feldman umountall(char **typelist) 1858fae3551SRodney W. Grimes { 1865965373eSMaxime Henrion struct xvfsconf vfc; 1878fae3551SRodney W. Grimes struct fstab *fs; 188adb378ceSPhilippe Charnier int rval; 1898fae3551SRodney W. Grimes char *cp; 1900602ee7cSBrian Feldman static int firstcall = 1; 1918fae3551SRodney W. Grimes 19291a81678SBrian Feldman if ((fs = getfsent()) != NULL) 1930602ee7cSBrian Feldman firstcall = 0; 19491a81678SBrian Feldman else if (firstcall) 19591a81678SBrian Feldman errx(1, "fstab reading failure"); 19691a81678SBrian Feldman else 19791a81678SBrian Feldman return (0); 198bc70c172SBrian Feldman do { 1998fae3551SRodney W. Grimes /* Ignore the root. */ 2008fae3551SRodney W. Grimes if (strcmp(fs->fs_file, "/") == 0) 2018fae3551SRodney W. Grimes continue; 2028fae3551SRodney W. Grimes /* 2038fae3551SRodney W. Grimes * !!! 2048fae3551SRodney W. Grimes * Historic practice: ignore unknown FSTAB_* fields. 2058fae3551SRodney W. Grimes */ 2068fae3551SRodney W. Grimes if (strcmp(fs->fs_type, FSTAB_RW) && 2078fae3551SRodney W. Grimes strcmp(fs->fs_type, FSTAB_RO) && 2088fae3551SRodney W. Grimes strcmp(fs->fs_type, FSTAB_RQ)) 2098fae3551SRodney W. Grimes continue; 210b6e55a05SDag-Erling Smørgrav /* Ignore unknown file system types. */ 21181667275SDag-Erling Smørgrav if (getvfsbyname(fs->fs_vfstype, &vfc) == -1) 2128fae3551SRodney W. Grimes continue; 213d499a0efSBruce Evans if (checkvfsname(fs->fs_vfstype, typelist)) 2148fae3551SRodney W. Grimes continue; 2158fae3551SRodney W. Grimes 2168fae3551SRodney W. Grimes /* 2178fae3551SRodney W. Grimes * We want to unmount the file systems in the reverse order 2188fae3551SRodney W. Grimes * that they were mounted. So, we save off the file name 2198fae3551SRodney W. Grimes * in some allocated memory, and then call recursively. 2208fae3551SRodney W. Grimes */ 2218fae3551SRodney W. Grimes if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL) 222bc70c172SBrian Feldman err(1, "malloc failed"); 2238fae3551SRodney W. Grimes (void)strcpy(cp, fs->fs_file); 224d499a0efSBruce Evans rval = umountall(typelist); 2258360efbdSAlfred Perlstein rval = checkname(cp, typelist) || rval; 226bc70c172SBrian Feldman free(cp); 2270602ee7cSBrian Feldman return (rval); 2280602ee7cSBrian Feldman } while ((fs = getfsent()) != NULL); 2298fae3551SRodney W. Grimes return (0); 2308fae3551SRodney W. Grimes } 2318fae3551SRodney W. Grimes 2328360efbdSAlfred Perlstein /* 2338360efbdSAlfred Perlstein * Do magic checks on mountpoint and device or hand over 2348360efbdSAlfred Perlstein * it to unmount(2) if everything fails. 2358360efbdSAlfred Perlstein */ 2368fae3551SRodney W. Grimes int 2378360efbdSAlfred Perlstein checkname(char *name, char **typelist) 2388fae3551SRodney W. Grimes { 239bc70c172SBrian Feldman size_t len; 2408360efbdSAlfred Perlstein int speclen; 2410fe9a7daSBrian Feldman char *resolved, realname[MAXPATHLEN]; 2428360efbdSAlfred Perlstein char *type, *hostp, *delimp, *origname; 243f73d495fSIan Dowse struct statfs *sfs; 2448fae3551SRodney W. Grimes 2450602ee7cSBrian Feldman len = 0; 246318f2fb4SIan Dowse delimp = hostp = NULL; 247318f2fb4SIan Dowse sfs = NULL; 2488fae3551SRodney W. Grimes 249bc70c172SBrian Feldman /* 250bc70c172SBrian Feldman * 1. Check if the name exists in the mounttable. 251bc70c172SBrian Feldman */ 252318f2fb4SIan Dowse sfs = checkmntlist(name, &type); 253bc70c172SBrian Feldman /* 254bc70c172SBrian Feldman * 2. Remove trailing slashes if there are any. After that 255bc70c172SBrian Feldman * we look up the name in the mounttable again. 256bc70c172SBrian Feldman */ 257318f2fb4SIan Dowse if (sfs == NULL) { 258bc70c172SBrian Feldman speclen = strlen(name); 259bc70c172SBrian Feldman for (speclen = strlen(name); 260bc70c172SBrian Feldman speclen > 1 && name[speclen - 1] == '/'; 261bc70c172SBrian Feldman speclen--) 262bc70c172SBrian Feldman name[speclen - 1] = '\0'; 263318f2fb4SIan Dowse sfs = checkmntlist(name, &type); 264bc70c172SBrian Feldman resolved = name; 265bc70c172SBrian Feldman /* Save off original name in origname */ 266bc70c172SBrian Feldman if ((origname = strdup(name)) == NULL) 267bc70c172SBrian Feldman err(1, "strdup"); 268bc70c172SBrian Feldman /* 269bc70c172SBrian Feldman * 3. Check if the deprecated nfs-syntax with an '@' 270bc70c172SBrian Feldman * has been used and translate it to the ':' syntax. 271bc70c172SBrian Feldman * Look up the name in the mounttable again. 272bc70c172SBrian Feldman */ 273318f2fb4SIan Dowse if (sfs == NULL) { 274bc70c172SBrian Feldman if ((delimp = strrchr(name, '@')) != NULL) { 275bc70c172SBrian Feldman hostp = delimp + 1; 276bc70c172SBrian Feldman if (*hostp != '\0') { 277bc70c172SBrian Feldman /* 278bc70c172SBrian Feldman * Make both '@' and ':' 279bc70c172SBrian Feldman * notations equal 280bc70c172SBrian Feldman */ 281bc70c172SBrian Feldman char *host = strdup(hostp); 282bc70c172SBrian Feldman len = strlen(hostp); 283bc70c172SBrian Feldman if (host == NULL) 284bc70c172SBrian Feldman err(1, "strdup"); 285bc70c172SBrian Feldman memmove(name + len + 1, name, 286bc70c172SBrian Feldman (size_t)(delimp - name)); 287bc70c172SBrian Feldman name[len] = ':'; 288bc70c172SBrian Feldman memmove(name, host, len); 289bc70c172SBrian Feldman free(host); 290bc70c172SBrian Feldman } 291bc70c172SBrian Feldman for (speclen = strlen(name); 292bc70c172SBrian Feldman speclen > 1 && name[speclen - 1] == '/'; 293bc70c172SBrian Feldman speclen--) 294bc70c172SBrian Feldman name[speclen - 1] = '\0'; 295bc70c172SBrian Feldman name[len + speclen + 1] = '\0'; 296318f2fb4SIan Dowse sfs = checkmntlist(name, &type); 297bc70c172SBrian Feldman resolved = name; 298bc70c172SBrian Feldman } 299bc70c172SBrian Feldman /* 300bc70c172SBrian Feldman * 4. Check if a relative mountpoint has been 301bc70c172SBrian Feldman * specified. This should happen as last check, 302bc70c172SBrian Feldman * the order is important. To prevent possible 303bc70c172SBrian Feldman * nfs-hangs, we just call realpath(3) on the 304bc70c172SBrian Feldman * basedir of mountpoint and add the dirname again. 305bc70c172SBrian Feldman * Check the name in mounttable one last time. 306bc70c172SBrian Feldman */ 307318f2fb4SIan Dowse if (sfs == NULL) { 308bc70c172SBrian Feldman (void)strcpy(name, origname); 309bc70c172SBrian Feldman if ((getrealname(name, realname)) != NULL) { 310318f2fb4SIan Dowse sfs = checkmntlist(realname, &type); 311bc70c172SBrian Feldman resolved = realname; 312bc70c172SBrian Feldman } 313bc70c172SBrian Feldman /* 3148360efbdSAlfred Perlstein * 5. All tests failed, just hand over the 3158360efbdSAlfred Perlstein * mountpoint to the kernel, maybe the statfs 3168360efbdSAlfred Perlstein * structure has been truncated or is not 3178360efbdSAlfred Perlstein * useful anymore because of a chroot(2). 3188360efbdSAlfred Perlstein * Please note that nfs will not be able to 3198360efbdSAlfred Perlstein * notify the nfs-server about unmounting. 3208360efbdSAlfred Perlstein * These things can change in future when the 3218360efbdSAlfred Perlstein * fstat structure get's more reliable, 3228360efbdSAlfred Perlstein * but at the moment we cannot thrust it. 323bc70c172SBrian Feldman */ 324318f2fb4SIan Dowse if (sfs == NULL) { 325bc70c172SBrian Feldman (void)strcpy(name, origname); 326318f2fb4SIan Dowse if (umountfs(NULL, origname, NULL, 3278360efbdSAlfred Perlstein "none") == 0) {; 3288360efbdSAlfred Perlstein warnx("%s not found in " 3298360efbdSAlfred Perlstein "mount table, " 3308360efbdSAlfred Perlstein "unmounted it anyway", 331bc70c172SBrian Feldman origname); 332bc70c172SBrian Feldman free(origname); 3338360efbdSAlfred Perlstein return (0); 3348360efbdSAlfred Perlstein } else 3358360efbdSAlfred Perlstein free(origname); 3368fae3551SRodney W. Grimes return (1); 3378fae3551SRodney W. Grimes } 3388fae3551SRodney W. Grimes } 3398fae3551SRodney W. Grimes } 340bc70c172SBrian Feldman free(origname); 341bc70c172SBrian Feldman } else 342bc70c172SBrian Feldman resolved = name; 3438fae3551SRodney W. Grimes 344d499a0efSBruce Evans if (checkvfsname(type, typelist)) 345d499a0efSBruce Evans return (1); 3468fae3551SRodney W. Grimes 347bc70c172SBrian Feldman /* 348bc70c172SBrian Feldman * Mark the uppermost mount as unmounted. 349bc70c172SBrian Feldman */ 350318f2fb4SIan Dowse (void)getmntentry(sfs->f_mntfromname, sfs->f_mntonname, NOTHING, &type, 351318f2fb4SIan Dowse MARK); 352318f2fb4SIan Dowse return (umountfs(sfs->f_mntfromname, sfs->f_mntonname, &sfs->f_fsid, 353318f2fb4SIan Dowse type)); 3548360efbdSAlfred Perlstein } 3558360efbdSAlfred Perlstein 3568360efbdSAlfred Perlstein /* 3578360efbdSAlfred Perlstein * NFS stuff and unmount(2) call 3588360efbdSAlfred Perlstein */ 3598360efbdSAlfred Perlstein int 360318f2fb4SIan Dowse umountfs(char *mntfromname, char *mntonname, fsid_t *fsid, char *type) 3618360efbdSAlfred Perlstein { 362318f2fb4SIan Dowse char fsidbuf[64]; 3638360efbdSAlfred Perlstein enum clnt_stat clnt_stat; 3648360efbdSAlfred Perlstein struct timeval try; 3658360efbdSAlfred Perlstein struct addrinfo *ai, hints; 3668360efbdSAlfred Perlstein int do_rpc; 3678360efbdSAlfred Perlstein CLIENT *clp; 3688360efbdSAlfred Perlstein char *nfsdirname, *orignfsdirname; 3698360efbdSAlfred Perlstein char *hostp, *delimp; 3708360efbdSAlfred Perlstein 3718360efbdSAlfred Perlstein ai = NULL; 37213e2e1afSIan Dowse do_rpc = 0; 37313e2e1afSIan Dowse hostp = NULL; 3748360efbdSAlfred Perlstein nfsdirname = delimp = orignfsdirname = NULL; 3758360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 3768360efbdSAlfred Perlstein 37713e2e1afSIan Dowse if (strcmp(type, "nfs") == 0) { 3788360efbdSAlfred Perlstein if ((nfsdirname = strdup(mntfromname)) == NULL) 3798360efbdSAlfred Perlstein err(1, "strdup"); 3808360efbdSAlfred Perlstein orignfsdirname = nfsdirname; 3818360efbdSAlfred Perlstein if ((delimp = strrchr(nfsdirname, ':')) != NULL) { 3828360efbdSAlfred Perlstein *delimp = '\0'; 3838360efbdSAlfred Perlstein hostp = nfsdirname; 3848360efbdSAlfred Perlstein getaddrinfo(hostp, NULL, &hints, &ai); 3858360efbdSAlfred Perlstein if (ai == NULL) { 3868360efbdSAlfred Perlstein warnx("can't get net id for host"); 3878360efbdSAlfred Perlstein } 3888360efbdSAlfred Perlstein nfsdirname = delimp + 1; 3898360efbdSAlfred Perlstein } 39013e2e1afSIan Dowse 391bc70c172SBrian Feldman /* 392bc70c172SBrian Feldman * Check if we have to start the rpc-call later. 393bc70c172SBrian Feldman * If there are still identical nfs-names mounted, 394bc70c172SBrian Feldman * we skip the rpc-call. Obviously this has to 395bc70c172SBrian Feldman * happen before unmount(2), but it should happen 396bc70c172SBrian Feldman * after the previous namecheck. 39713e2e1afSIan Dowse * A non-NULL return means that this is the last 39813e2e1afSIan Dowse * mount from mntfromname that is still mounted. 399bc70c172SBrian Feldman */ 400318f2fb4SIan Dowse if (getmntentry(mntfromname, NULL, NOTHING, &type, COUNT) 40113e2e1afSIan Dowse != NULL) 4020fe9a7daSBrian Feldman do_rpc = 1; 40313e2e1afSIan Dowse } 4048360efbdSAlfred Perlstein 4058360efbdSAlfred Perlstein if (!namematch(ai)) 406d499a0efSBruce Evans return (1); 407318f2fb4SIan Dowse /* First try to unmount using the specified file system ID. */ 408318f2fb4SIan Dowse if (fsid != NULL) { 409318f2fb4SIan Dowse snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", fsid->val[0], 410318f2fb4SIan Dowse fsid->val[1]); 411318f2fb4SIan Dowse if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) { 412318f2fb4SIan Dowse warn("unmount of %s failed", mntonname); 413318f2fb4SIan Dowse if (errno != ENOENT) 414318f2fb4SIan Dowse return (1); 415318f2fb4SIan Dowse /* Compatability for old kernels. */ 416318f2fb4SIan Dowse warnx("retrying using path instead of file system ID"); 417318f2fb4SIan Dowse fsid = NULL; 418318f2fb4SIan Dowse } 419318f2fb4SIan Dowse } 420318f2fb4SIan Dowse if (fsid == NULL && unmount(mntonname, fflag) != 0) { 421bc70c172SBrian Feldman warn("unmount of %s failed", mntonname); 4228fae3551SRodney W. Grimes return (1); 4238fae3551SRodney W. Grimes } 424bc70c172SBrian Feldman if (vflag) 425bc70c172SBrian Feldman (void)printf("%s: unmount from %s\n", mntfromname, mntonname); 426bc70c172SBrian Feldman /* 427bc70c172SBrian Feldman * Report to mountd-server which nfsname 428bc70c172SBrian Feldman * has been unmounted. 429bc70c172SBrian Feldman */ 4308360efbdSAlfred Perlstein if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) { 4318360efbdSAlfred Perlstein clp = clnt_create(hostp, RPCPROG_MNT, RPCMNT_VER1, "udp"); 4328360efbdSAlfred Perlstein if (clp == NULL) { 43313e2e1afSIan Dowse warnx("%s: %s", hostp, 43413e2e1afSIan Dowse clnt_spcreateerror("RPCPROG_MNT")); 4358fae3551SRodney W. Grimes return (1); 4368fae3551SRodney W. Grimes } 4378360efbdSAlfred Perlstein clp->cl_auth = authsys_create_default(); 4388fae3551SRodney W. Grimes try.tv_sec = 20; 4398fae3551SRodney W. Grimes try.tv_usec = 0; 4405c514aeeSMatthew N. Dodd clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, (xdrproc_t)xdr_dir, 4415c514aeeSMatthew N. Dodd nfsdirname, (xdrproc_t)xdr_void, (caddr_t)0, try); 4428fae3551SRodney W. Grimes if (clnt_stat != RPC_SUCCESS) { 44313e2e1afSIan Dowse warnx("%s: %s", hostp, 44413e2e1afSIan Dowse clnt_sperror(clp, "RPCMNT_UMOUNT")); 4458fae3551SRodney W. Grimes return (1); 4468fae3551SRodney W. Grimes } 447a69497d7SMatthew Dillon /* 448a69497d7SMatthew Dillon * Remove the unmounted entry from /var/db/mounttab. 449a69497d7SMatthew Dillon */ 450afe1ef24SIan Dowse if (read_mtab()) { 451afe1ef24SIan Dowse clean_mtab(hostp, nfsdirname, vflag); 452afe1ef24SIan Dowse if(!write_mtab(vflag)) 45313e2e1afSIan Dowse warnx("cannot remove mounttab entry %s:%s", 454a69497d7SMatthew Dillon hostp, nfsdirname); 455a69497d7SMatthew Dillon free_mtab(); 456a69497d7SMatthew Dillon } 457bc70c172SBrian Feldman free(orignfsdirname); 4588fae3551SRodney W. Grimes auth_destroy(clp->cl_auth); 4598fae3551SRodney W. Grimes clnt_destroy(clp); 4608fae3551SRodney W. Grimes } 4618fae3551SRodney W. Grimes return (0); 4628fae3551SRodney W. Grimes } 4638fae3551SRodney W. Grimes 464318f2fb4SIan Dowse struct statfs * 465318f2fb4SIan Dowse getmntentry(const char *fromname, const char *onname, mntwhat what, 466318f2fb4SIan Dowse char **type, dowhat mark) 4678fae3551SRodney W. Grimes { 468d499a0efSBruce Evans static struct statfs *mntbuf; 469bc70c172SBrian Feldman static size_t mntsize = 0; 470bc70c172SBrian Feldman static char *mntcheck = NULL; 471bc70c172SBrian Feldman static char *mntcount = NULL; 472bc70c172SBrian Feldman int i, count; 4738fae3551SRodney W. Grimes 474bc70c172SBrian Feldman if (mntsize <= 0) { 475bc70c172SBrian Feldman if ((mntsize = mntinfo(&mntbuf)) <= 0) 4768fae3551SRodney W. Grimes return (NULL); 4778fae3551SRodney W. Grimes } 478bc70c172SBrian Feldman if (mntcheck == NULL) { 479bc70c172SBrian Feldman if ((mntcheck = calloc(mntsize + 1, sizeof(int))) == NULL || 480bc70c172SBrian Feldman (mntcount = calloc(mntsize + 1, sizeof(int))) == NULL) 481bc70c172SBrian Feldman err(1, "calloc"); 482bc70c172SBrian Feldman } 483bc70c172SBrian Feldman /* 484bc70c172SBrian Feldman * We want to get the file systems in the reverse order 485bc70c172SBrian Feldman * that they were mounted. Mounted and unmounted file systems 486bc70c172SBrian Feldman * are marked or unmarked in a table called 'mntcheck'. 487bc70c172SBrian Feldman * Unmount(const char *dir, int flags) does only take the 488bc70c172SBrian Feldman * mountpoint as argument, not the destination. If we don't pay 4899d5abbddSJens Schweikhardt * attention to the order, it can happen that an overlaying 4909d5abbddSJens Schweikhardt * file system gets unmounted instead of the one the user 491bc70c172SBrian Feldman * has choosen. 492bc70c172SBrian Feldman */ 493bc70c172SBrian Feldman switch (mark) { 494bc70c172SBrian Feldman case NAME: 495bc70c172SBrian Feldman /* Return only the specific name */ 496bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 497318f2fb4SIan Dowse if (fromname != NULL && !strcmp((what == MNTFROM) ? 498318f2fb4SIan Dowse mntbuf[i].f_mntfromname : mntbuf[i].f_mntonname, 499318f2fb4SIan Dowse fromname) && mntcheck[i] != 1) { 5008fae3551SRodney W. Grimes if (type) 501d499a0efSBruce Evans *type = mntbuf[i].f_fstypename; 502318f2fb4SIan Dowse return (&mntbuf[i]); 5038fae3551SRodney W. Grimes } 5048fae3551SRodney W. Grimes } 505318f2fb4SIan Dowse 5068fae3551SRodney W. Grimes return (NULL); 507bc70c172SBrian Feldman case MARK: 508bc70c172SBrian Feldman /* Mark current mount with '1' and return name */ 509bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 510bc70c172SBrian Feldman if (mntcheck[i] == 0 && 511bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntonname, onname) == 0) && 512bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) { 513bc70c172SBrian Feldman mntcheck[i] = 1; 514318f2fb4SIan Dowse return (&mntbuf[i]); 515bc70c172SBrian Feldman } 516bc70c172SBrian Feldman } 517bc70c172SBrian Feldman return (NULL); 518bc70c172SBrian Feldman case UNMARK: 519bc70c172SBrian Feldman /* Unmark current mount with '0' and return name */ 520bc70c172SBrian Feldman for (i = 0; i < mntsize; i++) { 521bc70c172SBrian Feldman if (mntcheck[i] == 1 && 522bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntonname, onname) == 0) && 523bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) { 524bc70c172SBrian Feldman mntcheck[i] = 0; 525318f2fb4SIan Dowse return (&mntbuf[i]); 526bc70c172SBrian Feldman } 527bc70c172SBrian Feldman } 528bc70c172SBrian Feldman return (NULL); 529bc70c172SBrian Feldman case COUNT: 530bc70c172SBrian Feldman /* Count the equal mntfromnames */ 531bc70c172SBrian Feldman count = 0; 532bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 533bc70c172SBrian Feldman if (strcmp(mntbuf[i].f_mntfromname, fromname) == 0) 534bc70c172SBrian Feldman count++; 535bc70c172SBrian Feldman } 536bc70c172SBrian Feldman /* Mark the already unmounted mounts and return 5370602ee7cSBrian Feldman * mntfromname if count <= 1. Else return NULL. 538bc70c172SBrian Feldman */ 539bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 540bc70c172SBrian Feldman if (strcmp(mntbuf[i].f_mntfromname, fromname) == 0) { 541bc70c172SBrian Feldman if (mntcount[i] == 1) 542bc70c172SBrian Feldman count--; 5430fe9a7daSBrian Feldman else { 544bc70c172SBrian Feldman mntcount[i] = 1; 5450fe9a7daSBrian Feldman break; 5460fe9a7daSBrian Feldman } 5470602ee7cSBrian Feldman } 5480602ee7cSBrian Feldman } 5490602ee7cSBrian Feldman if (count <= 1) 550318f2fb4SIan Dowse return (&mntbuf[i]); 551bc70c172SBrian Feldman else 552bc70c172SBrian Feldman return (NULL); 553bc70c172SBrian Feldman case FREE: 554bc70c172SBrian Feldman free(mntbuf); 555bc70c172SBrian Feldman free(mntcheck); 556a69497d7SMatthew Dillon free(mntcount); 557bc70c172SBrian Feldman return (NULL); 558bc70c172SBrian Feldman default: 559bc70c172SBrian Feldman return (NULL); 560bc70c172SBrian Feldman } 5618fae3551SRodney W. Grimes } 5628fae3551SRodney W. Grimes 5638fae3551SRodney W. Grimes int 5648360efbdSAlfred Perlstein sacmp(struct sockaddr *sa1, struct sockaddr *sa2) 5658fae3551SRodney W. Grimes { 5668360efbdSAlfred Perlstein void *p1, *p2; 5678360efbdSAlfred Perlstein int len; 5688fae3551SRodney W. Grimes 5698360efbdSAlfred Perlstein if (sa1->sa_family != sa2->sa_family) 5708fae3551SRodney W. Grimes return (1); 5718fae3551SRodney W. Grimes 5728360efbdSAlfred Perlstein switch (sa1->sa_family) { 5738360efbdSAlfred Perlstein case AF_INET: 5748360efbdSAlfred Perlstein p1 = &((struct sockaddr_in *)sa1)->sin_addr; 5758360efbdSAlfred Perlstein p2 = &((struct sockaddr_in *)sa2)->sin_addr; 5768360efbdSAlfred Perlstein len = 4; 5778360efbdSAlfred Perlstein break; 5788360efbdSAlfred Perlstein case AF_INET6: 5798360efbdSAlfred Perlstein p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr; 5808360efbdSAlfred Perlstein p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr; 5818360efbdSAlfred Perlstein len = 16; 5828360efbdSAlfred Perlstein if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 5838360efbdSAlfred Perlstein ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 5848360efbdSAlfred Perlstein return (1); 5858360efbdSAlfred Perlstein break; 5868360efbdSAlfred Perlstein default: 5878360efbdSAlfred Perlstein return (1); 5888360efbdSAlfred Perlstein } 5898360efbdSAlfred Perlstein 5908360efbdSAlfred Perlstein return memcmp(p1, p2, len); 5918360efbdSAlfred Perlstein } 5928360efbdSAlfred Perlstein 5938360efbdSAlfred Perlstein int 5948360efbdSAlfred Perlstein namematch(struct addrinfo *ai) 5958360efbdSAlfred Perlstein { 5968360efbdSAlfred Perlstein struct addrinfo *aip; 5978360efbdSAlfred Perlstein 5988360efbdSAlfred Perlstein if (nfshost == NULL || nfshost_ai == NULL) 5998fae3551SRodney W. Grimes return (1); 6008fae3551SRodney W. Grimes 6018360efbdSAlfred Perlstein while (ai != NULL) { 6028360efbdSAlfred Perlstein aip = nfshost_ai; 6038360efbdSAlfred Perlstein while (aip != NULL) { 6048360efbdSAlfred Perlstein if (sacmp(ai->ai_addr, aip->ai_addr) == 0) 6058fae3551SRodney W. Grimes return (1); 6068360efbdSAlfred Perlstein aip = aip->ai_next; 6078fae3551SRodney W. Grimes } 6088360efbdSAlfred Perlstein ai = ai->ai_next; 6098fae3551SRodney W. Grimes } 6108360efbdSAlfred Perlstein 6118fae3551SRodney W. Grimes return (0); 6128fae3551SRodney W. Grimes } 6138fae3551SRodney W. Grimes 614318f2fb4SIan Dowse struct statfs * 615318f2fb4SIan Dowse checkmntlist(char *name, char **type) 616bc70c172SBrian Feldman { 617318f2fb4SIan Dowse struct statfs *sfs; 618bc70c172SBrian Feldman 619318f2fb4SIan Dowse sfs = getmntentry(name, NULL, MNTON, type, NAME); 620318f2fb4SIan Dowse if (sfs == NULL) 621318f2fb4SIan Dowse sfs = getmntentry(name, NULL, MNTFROM, type, NAME); 622318f2fb4SIan Dowse return (sfs); 623bc70c172SBrian Feldman } 624bc70c172SBrian Feldman 625bc70c172SBrian Feldman size_t 626bc70c172SBrian Feldman mntinfo(struct statfs **mntbuf) 627bc70c172SBrian Feldman { 628bc70c172SBrian Feldman static struct statfs *origbuf; 629bc70c172SBrian Feldman size_t bufsize; 630bc70c172SBrian Feldman int mntsize; 631bc70c172SBrian Feldman 632a69497d7SMatthew Dillon mntsize = getfsstat(NULL, 0, MNT_NOWAIT); 633bc70c172SBrian Feldman if (mntsize <= 0) 634bc70c172SBrian Feldman return (0); 635bc70c172SBrian Feldman bufsize = (mntsize + 1) * sizeof(struct statfs); 636bc70c172SBrian Feldman if ((origbuf = malloc(bufsize)) == NULL) 637bc70c172SBrian Feldman err(1, "malloc"); 638bc70c172SBrian Feldman mntsize = getfsstat(origbuf, (long)bufsize, MNT_NOWAIT); 639bc70c172SBrian Feldman *mntbuf = origbuf; 640bc70c172SBrian Feldman return (mntsize); 641bc70c172SBrian Feldman } 642bc70c172SBrian Feldman 643bc70c172SBrian Feldman char * 644bc70c172SBrian Feldman getrealname(char *name, char *realname) 645bc70c172SBrian Feldman { 646bc70c172SBrian Feldman char *dirname; 647bc70c172SBrian Feldman int havedir; 648bc70c172SBrian Feldman size_t baselen; 649bc70c172SBrian Feldman size_t dirlen; 650bc70c172SBrian Feldman 651bc70c172SBrian Feldman dirname = '\0'; 652bc70c172SBrian Feldman havedir = 0; 653bc70c172SBrian Feldman if (*name == '/') { 654bc70c172SBrian Feldman if (ISDOT(name + 1) || ISDOTDOT(name + 1)) 655bc70c172SBrian Feldman strcpy(realname, "/"); 656bc70c172SBrian Feldman else { 657bc70c172SBrian Feldman if ((dirname = strrchr(name + 1, '/')) == NULL) 6580fe9a7daSBrian Feldman snprintf(realname, MAXPATHLEN, "%s", name); 659bc70c172SBrian Feldman else 660bc70c172SBrian Feldman havedir = 1; 661bc70c172SBrian Feldman } 662bc70c172SBrian Feldman } else { 663bc70c172SBrian Feldman if (ISDOT(name) || ISDOTDOT(name)) 664bc70c172SBrian Feldman (void)realpath(name, realname); 665bc70c172SBrian Feldman else { 666bc70c172SBrian Feldman if ((dirname = strrchr(name, '/')) == NULL) { 667bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 668bc70c172SBrian Feldman return (NULL); 669bc70c172SBrian Feldman } else 670bc70c172SBrian Feldman havedir = 1; 671bc70c172SBrian Feldman } 672bc70c172SBrian Feldman } 673bc70c172SBrian Feldman if (havedir) { 674bc70c172SBrian Feldman *dirname++ = '\0'; 675bc70c172SBrian Feldman if (ISDOT(dirname)) { 676bc70c172SBrian Feldman *dirname = '\0'; 677bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 678bc70c172SBrian Feldman return (NULL); 679bc70c172SBrian Feldman } else if (ISDOTDOT(dirname)) { 680bc70c172SBrian Feldman *--dirname = '/'; 681bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 682bc70c172SBrian Feldman return (NULL); 683bc70c172SBrian Feldman } else { 684bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 685bc70c172SBrian Feldman return (NULL); 686bc70c172SBrian Feldman baselen = strlen(realname); 687bc70c172SBrian Feldman dirlen = strlen(dirname); 688bc70c172SBrian Feldman if (baselen + dirlen + 1 > MAXPATHLEN) 689bc70c172SBrian Feldman return (NULL); 690bc70c172SBrian Feldman if (realname[1] == '\0') { 691bc70c172SBrian Feldman memmove(realname + 1, dirname, dirlen); 692bc70c172SBrian Feldman realname[dirlen + 1] = '\0'; 693bc70c172SBrian Feldman } else { 694bc70c172SBrian Feldman realname[baselen] = '/'; 695bc70c172SBrian Feldman memmove(realname + baselen + 1, 696bc70c172SBrian Feldman dirname, dirlen); 697bc70c172SBrian Feldman realname[baselen + dirlen + 1] = '\0'; 698bc70c172SBrian Feldman } 699bc70c172SBrian Feldman } 700bc70c172SBrian Feldman } 701bc70c172SBrian Feldman return (realname); 702bc70c172SBrian Feldman } 703bc70c172SBrian Feldman 7048fae3551SRodney W. Grimes /* 7058fae3551SRodney W. Grimes * xdr routines for mount rpc's 7068fae3551SRodney W. Grimes */ 7078fae3551SRodney W. Grimes int 708bc70c172SBrian Feldman xdr_dir(XDR *xdrsp, char *dirp) 7098fae3551SRodney W. Grimes { 710bc70c172SBrian Feldman 7118fae3551SRodney W. Grimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 7128fae3551SRodney W. Grimes } 7138fae3551SRodney W. Grimes 7148fae3551SRodney W. Grimes void 7158fae3551SRodney W. Grimes usage() 7168fae3551SRodney W. Grimes { 717bc70c172SBrian Feldman 718210a5dc8SPhilippe Charnier (void)fprintf(stderr, "%s\n%s\n", 719210a5dc8SPhilippe Charnier "usage: umount [-fv] special | node", 720ef258dd9SMatthew N. Dodd " umount -a | -A [ -F fstab] [-fv] [-h host] [-t type]"); 7218fae3551SRodney W. Grimes exit(1); 7228fae3551SRodney W. Grimes } 723