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> 508fae3551SRodney W. Grimes 518fae3551SRodney W. Grimes #include <netdb.h> 528fae3551SRodney W. Grimes #include <rpc/rpc.h> 538fae3551SRodney W. Grimes #include <nfs/rpcv2.h> 548fae3551SRodney W. Grimes 558fae3551SRodney W. Grimes #include <err.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 62bc70c172SBrian Feldman #define ISDOT(x) ((x)[0] == '.' && (x)[1] == '\0') 63bc70c172SBrian Feldman #define ISDOTDOT(x) ((x)[0] == '.' && (x)[1] == '.' && (x)[2] == '\0') 648fae3551SRodney W. Grimes 65bc70c172SBrian Feldman typedef enum { MNTON, MNTFROM, NOTHING } mntwhat; 66bc70c172SBrian Feldman typedef enum { MARK, UNMARK, NAME, COUNT, FREE } dowhat; 67bc70c172SBrian Feldman 680fe9a7daSBrian Feldman int fflag, vflag; 698fae3551SRodney W. Grimes char *nfshost; 708fae3551SRodney W. Grimes 71bc70c172SBrian Feldman void checkmntlist (char *, char **, char **, char **); 72bc70c172SBrian Feldman int checkvfsname (const char *, char **); 73bc70c172SBrian Feldman char *getmntname (const char *, const char *, 74bc70c172SBrian Feldman mntwhat, char **, dowhat); 75bc70c172SBrian Feldman char *getrealname(char *, char *resolved_path); 76bc70c172SBrian Feldman char **makevfslist (const char *); 77bc70c172SBrian Feldman size_t mntinfo (struct statfs **); 78bc70c172SBrian Feldman int namematch (struct hostent *); 79bc70c172SBrian Feldman int selected (int); 80bc70c172SBrian Feldman int umountall (char **); 81bc70c172SBrian Feldman int umountfs (char *, char **); 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 { 88bc70c172SBrian Feldman int all, errs, ch, mntsize; 89bc70c172SBrian Feldman char **typelist = NULL, *mntonname, *mntfromname; 90bc70c172SBrian Feldman char *type, *mntfromnamerev, *mntonnamerev; 91d499a0efSBruce Evans struct statfs *mntbuf; 928fae3551SRodney W. Grimes 938fae3551SRodney W. Grimes /* Start disks transferring immediately. */ 948fae3551SRodney W. Grimes sync(); 958fae3551SRodney W. Grimes 960fe9a7daSBrian Feldman all = errs = 0; 97bc70c172SBrian Feldman while ((ch = getopt(argc, argv, "Aafh:t:v")) != -1) 988fae3551SRodney W. Grimes switch (ch) { 99d499a0efSBruce Evans case 'A': 100d499a0efSBruce Evans all = 2; 101d499a0efSBruce Evans break; 1028fae3551SRodney W. Grimes case 'a': 1038fae3551SRodney W. Grimes all = 1; 1048fae3551SRodney W. Grimes 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 127adb378ceSPhilippe Charnier if ((argc == 0 && !all) || (argc != 0 && all)) 1288fae3551SRodney W. Grimes usage(); 1298fae3551SRodney W. Grimes 1308fae3551SRodney W. Grimes /* -h implies "-t nfs" if no -t flag. */ 1318fae3551SRodney W. Grimes if ((nfshost != NULL) && (typelist == NULL)) 132d499a0efSBruce Evans typelist = makevfslist("nfs"); 1338fae3551SRodney W. Grimes 134d499a0efSBruce Evans switch (all) { 135d499a0efSBruce Evans case 2: 136bc70c172SBrian Feldman if ((mntsize = mntinfo(&mntbuf)) <= 0) 137d499a0efSBruce Evans break; 138bc70c172SBrian Feldman /* 139bc70c172SBrian Feldman * We unmount the nfs-mounts in the reverse order 140bc70c172SBrian Feldman * that they were mounted. 141bc70c172SBrian Feldman */ 142bc70c172SBrian Feldman for (errs = 0, mntsize--; mntsize > 0; mntsize--) { 143bc70c172SBrian Feldman if (checkvfsname(mntbuf[mntsize].f_fstypename, 144bc70c172SBrian Feldman typelist)) 145d499a0efSBruce Evans continue; 146bc70c172SBrian Feldman /* 147bc70c172SBrian Feldman * Check if a mountpoint is laid over by another mount. 148bc70c172SBrian Feldman * A warning will be printed to stderr if this is 149bc70c172SBrian Feldman * the case. The laid over mount remains unmounted. 150bc70c172SBrian Feldman */ 151bc70c172SBrian Feldman mntonname = mntbuf[mntsize].f_mntonname; 152bc70c172SBrian Feldman mntfromname = mntbuf[mntsize].f_mntfromname; 153bc70c172SBrian Feldman mntonnamerev = getmntname(getmntname(mntonname, 154bc70c172SBrian Feldman NULL, MNTFROM, &type, NAME), NULL, 155bc70c172SBrian Feldman MNTON, &type, NAME); 156bc70c172SBrian Feldman 157bc70c172SBrian Feldman mntfromnamerev = getmntname(mntonnamerev, 158bc70c172SBrian Feldman NULL, MNTFROM, &type, NAME); 159bc70c172SBrian Feldman 160bc70c172SBrian Feldman if (strcmp(mntonnamerev, mntonname) == 0 && 161bc70c172SBrian Feldman strcmp(mntfromnamerev, mntfromname ) != 0) 162bc70c172SBrian Feldman warnx("cannot umount %s, %s\n " 163bc70c172SBrian Feldman "is mounted there, umount it first", 164bc70c172SBrian Feldman mntonname, mntfromnamerev); 165bc70c172SBrian Feldman 166bc70c172SBrian Feldman if (umountfs(mntbuf[mntsize].f_mntonname, 167bc70c172SBrian Feldman typelist) != 0) 168d499a0efSBruce Evans errs = 1; 169d499a0efSBruce Evans } 170bc70c172SBrian Feldman free(mntbuf); 171d499a0efSBruce Evans break; 172d499a0efSBruce Evans case 1: 1738fae3551SRodney W. Grimes if (setfsent() == 0) 1748fae3551SRodney W. Grimes err(1, "%s", _PATH_FSTAB); 175d499a0efSBruce Evans errs = umountall(typelist); 176d499a0efSBruce Evans break; 177d499a0efSBruce Evans case 0: 1788fae3551SRodney W. Grimes for (errs = 0; *argv != NULL; ++argv) 179d499a0efSBruce Evans if (umountfs(*argv, typelist) != 0) 180d499a0efSBruce Evans errs = 1; 181d499a0efSBruce Evans break; 182d499a0efSBruce Evans } 183bc70c172SBrian Feldman (void)getmntname(NULL, NULL, NOTHING, NULL, FREE); 1848fae3551SRodney W. Grimes exit(errs); 1858fae3551SRodney W. Grimes } 1868fae3551SRodney W. Grimes 1878fae3551SRodney W. Grimes int 188bc70c172SBrian Feldman umountall(char **typelist) 1898fae3551SRodney W. Grimes { 1900602ee7cSBrian Feldman struct vfsconf vfc; 1918fae3551SRodney W. Grimes struct fstab *fs; 192adb378ceSPhilippe Charnier int rval; 1938fae3551SRodney W. Grimes char *cp; 1940602ee7cSBrian Feldman static int firstcall = 1; 1958fae3551SRodney W. Grimes 19691a81678SBrian Feldman if ((fs = getfsent()) != NULL) 1970602ee7cSBrian Feldman firstcall = 0; 19891a81678SBrian Feldman else if (firstcall) 19991a81678SBrian Feldman errx(1, "fstab reading failure"); 20091a81678SBrian Feldman else 20191a81678SBrian Feldman return (0); 202bc70c172SBrian Feldman do { 2038fae3551SRodney W. Grimes /* Ignore the root. */ 2048fae3551SRodney W. Grimes if (strcmp(fs->fs_file, "/") == 0) 2058fae3551SRodney W. Grimes continue; 2068fae3551SRodney W. Grimes /* 2078fae3551SRodney W. Grimes * !!! 2088fae3551SRodney W. Grimes * Historic practice: ignore unknown FSTAB_* fields. 2098fae3551SRodney W. Grimes */ 2108fae3551SRodney W. Grimes if (strcmp(fs->fs_type, FSTAB_RW) && 2118fae3551SRodney W. Grimes strcmp(fs->fs_type, FSTAB_RO) && 2128fae3551SRodney W. Grimes strcmp(fs->fs_type, FSTAB_RQ)) 2138fae3551SRodney W. Grimes continue; 2148fae3551SRodney W. Grimes /* If an unknown file system type, complain. */ 215bc70c172SBrian Feldman if (getvfsbyname(fs->fs_vfstype, &vfc) == -1) { 2168fae3551SRodney W. Grimes warnx("%s: unknown mount type", fs->fs_vfstype); 2178fae3551SRodney W. Grimes continue; 2188fae3551SRodney W. Grimes } 219d499a0efSBruce Evans if (checkvfsname(fs->fs_vfstype, typelist)) 2208fae3551SRodney W. Grimes continue; 2218fae3551SRodney W. Grimes 2228fae3551SRodney W. Grimes /* 2238fae3551SRodney W. Grimes * We want to unmount the file systems in the reverse order 2248fae3551SRodney W. Grimes * that they were mounted. So, we save off the file name 2258fae3551SRodney W. Grimes * in some allocated memory, and then call recursively. 2268fae3551SRodney W. Grimes */ 2278fae3551SRodney W. Grimes if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL) 228bc70c172SBrian Feldman err(1, "malloc failed"); 2298fae3551SRodney W. Grimes (void)strcpy(cp, fs->fs_file); 230d499a0efSBruce Evans rval = umountall(typelist); 2310602ee7cSBrian Feldman rval = umountfs(cp, typelist) || rval; 232bc70c172SBrian Feldman free(cp); 2330602ee7cSBrian Feldman return (rval); 2340602ee7cSBrian Feldman } while ((fs = getfsent()) != NULL); 2358fae3551SRodney W. Grimes return (0); 2368fae3551SRodney W. Grimes } 2378fae3551SRodney W. Grimes 2388fae3551SRodney W. Grimes int 239bc70c172SBrian Feldman umountfs(char *name, char **typelist) 2408fae3551SRodney W. Grimes { 2418fae3551SRodney W. Grimes enum clnt_stat clnt_stat; 2428fae3551SRodney W. Grimes struct hostent *hp; 2438fae3551SRodney W. Grimes struct sockaddr_in saddr; 2448fae3551SRodney W. Grimes struct timeval pertry, try; 2458fae3551SRodney W. Grimes CLIENT *clp; 246bc70c172SBrian Feldman size_t len; 2470fe9a7daSBrian Feldman int so, speclen, do_rpc; 248bc70c172SBrian Feldman char *mntonname, *mntfromname; 2490602ee7cSBrian Feldman char *mntfromnamerev; 250bc70c172SBrian Feldman char *nfsdirname, *orignfsdirname; 2510fe9a7daSBrian Feldman char *resolved, realname[MAXPATHLEN]; 252bc70c172SBrian Feldman char *type, *delimp, *hostp, *origname; 2538fae3551SRodney W. Grimes 2540602ee7cSBrian Feldman len = 0; 255bc70c172SBrian Feldman mntfromname = mntonname = delimp = hostp = orignfsdirname = NULL; 2568fae3551SRodney W. Grimes 257bc70c172SBrian Feldman /* 258bc70c172SBrian Feldman * 1. Check if the name exists in the mounttable. 259bc70c172SBrian Feldman */ 260bc70c172SBrian Feldman (void)checkmntlist(name, &mntfromname, &mntonname, &type); 261bc70c172SBrian Feldman /* 262bc70c172SBrian Feldman * 2. Remove trailing slashes if there are any. After that 263bc70c172SBrian Feldman * we look up the name in the mounttable again. 264bc70c172SBrian Feldman */ 265bc70c172SBrian Feldman if (mntfromname == NULL && mntonname == NULL) { 266bc70c172SBrian Feldman speclen = strlen(name); 267bc70c172SBrian Feldman for (speclen = strlen(name); 268bc70c172SBrian Feldman speclen > 1 && name[speclen - 1] == '/'; 269bc70c172SBrian Feldman speclen--) 270bc70c172SBrian Feldman name[speclen - 1] = '\0'; 271bc70c172SBrian Feldman (void)checkmntlist(name, &mntfromname, &mntonname, &type); 272bc70c172SBrian Feldman resolved = name; 273bc70c172SBrian Feldman /* Save off original name in origname */ 274bc70c172SBrian Feldman if ((origname = strdup(name)) == NULL) 275bc70c172SBrian Feldman err(1, "strdup"); 276bc70c172SBrian Feldman /* 277bc70c172SBrian Feldman * 3. Check if the deprecated nfs-syntax with an '@' 278bc70c172SBrian Feldman * has been used and translate it to the ':' syntax. 279bc70c172SBrian Feldman * Look up the name in the mounttable again. 280bc70c172SBrian Feldman */ 281bc70c172SBrian Feldman if (mntfromname == NULL && mntonname == NULL) { 282bc70c172SBrian Feldman if ((delimp = strrchr(name, '@')) != NULL) { 283bc70c172SBrian Feldman hostp = delimp + 1; 284bc70c172SBrian Feldman if (*hostp != '\0') { 285bc70c172SBrian Feldman /* 286bc70c172SBrian Feldman * Make both '@' and ':' 287bc70c172SBrian Feldman * notations equal 288bc70c172SBrian Feldman */ 289bc70c172SBrian Feldman char *host = strdup(hostp); 290bc70c172SBrian Feldman len = strlen(hostp); 291bc70c172SBrian Feldman if (host == NULL) 292bc70c172SBrian Feldman err(1, "strdup"); 293bc70c172SBrian Feldman memmove(name + len + 1, name, 294bc70c172SBrian Feldman (size_t)(delimp - name)); 295bc70c172SBrian Feldman name[len] = ':'; 296bc70c172SBrian Feldman memmove(name, host, len); 297bc70c172SBrian Feldman free(host); 298bc70c172SBrian Feldman } 299bc70c172SBrian Feldman for (speclen = strlen(name); 300bc70c172SBrian Feldman speclen > 1 && name[speclen - 1] == '/'; 301bc70c172SBrian Feldman speclen--) 302bc70c172SBrian Feldman name[speclen - 1] = '\0'; 303bc70c172SBrian Feldman name[len + speclen + 1] = '\0'; 304bc70c172SBrian Feldman (void)checkmntlist(name, &mntfromname, 305bc70c172SBrian Feldman &mntonname, &type); 306bc70c172SBrian Feldman resolved = name; 307bc70c172SBrian Feldman } 308bc70c172SBrian Feldman /* 309bc70c172SBrian Feldman * 4. Check if a relative mountpoint has been 310bc70c172SBrian Feldman * specified. This should happen as last check, 311bc70c172SBrian Feldman * the order is important. To prevent possible 312bc70c172SBrian Feldman * nfs-hangs, we just call realpath(3) on the 313bc70c172SBrian Feldman * basedir of mountpoint and add the dirname again. 314bc70c172SBrian Feldman * Check the name in mounttable one last time. 315bc70c172SBrian Feldman */ 316bc70c172SBrian Feldman if (mntfromname == NULL && mntonname == NULL) { 317bc70c172SBrian Feldman (void)strcpy(name, origname); 318bc70c172SBrian Feldman if ((getrealname(name, realname)) != NULL) { 319bc70c172SBrian Feldman (void)checkmntlist(realname, 320bc70c172SBrian Feldman &mntfromname, &mntonname, &type); 321bc70c172SBrian Feldman resolved = realname; 322bc70c172SBrian Feldman } 323bc70c172SBrian Feldman /* 324bc70c172SBrian Feldman * All tests failed, return to main() 325bc70c172SBrian Feldman */ 326bc70c172SBrian Feldman if (mntfromname == NULL && mntonname == NULL) { 327bc70c172SBrian Feldman (void)strcpy(name, origname); 328bc70c172SBrian Feldman warnx("%s: not currently mounted", 329bc70c172SBrian Feldman origname); 330bc70c172SBrian Feldman free(origname); 3318fae3551SRodney W. Grimes return (1); 3328fae3551SRodney W. Grimes } 3338fae3551SRodney W. Grimes } 3348fae3551SRodney W. Grimes } 335bc70c172SBrian Feldman free(origname); 336bc70c172SBrian Feldman } else 337bc70c172SBrian Feldman resolved = name; 3388fae3551SRodney W. Grimes 339d499a0efSBruce Evans if (checkvfsname(type, typelist)) 340d499a0efSBruce Evans return (1); 3418fae3551SRodney W. Grimes 342d499a0efSBruce Evans hp = NULL; 343bc70c172SBrian Feldman nfsdirname = NULL; 344d499a0efSBruce Evans if (!strcmp(type, "nfs")) { 345bc70c172SBrian Feldman if ((nfsdirname = strdup(mntfromname)) == NULL) 346bc70c172SBrian Feldman err(1, "strdup"); 347bc70c172SBrian Feldman orignfsdirname = nfsdirname; 348bc70c172SBrian Feldman if ((delimp = strchr(nfsdirname, ':')) != NULL) { 3498fae3551SRodney W. Grimes *delimp = '\0'; 350bc70c172SBrian Feldman hostp = nfsdirname; 351bc70c172SBrian Feldman if ((hp = gethostbyname(hostp)) == NULL) { 352bc70c172SBrian Feldman warnx("can't get net id for host"); 353bc70c172SBrian Feldman } 354bc70c172SBrian Feldman nfsdirname = delimp + 1; 355d499a0efSBruce Evans } 356d499a0efSBruce Evans } 357bc70c172SBrian Feldman /* 358bc70c172SBrian Feldman * Check if the reverse entrys of the mounttable are really the 359bc70c172SBrian Feldman * same as the normal ones. 360bc70c172SBrian Feldman */ 361bc70c172SBrian Feldman if ((mntfromnamerev = strdup(getmntname(getmntname(mntfromname, 3620602ee7cSBrian Feldman NULL, MNTON, &type, NAME), NULL, MNTFROM, &type, NAME))) == NULL) 363bc70c172SBrian Feldman err(1, "strdup"); 364bc70c172SBrian Feldman /* 365bc70c172SBrian Feldman * Mark the uppermost mount as unmounted. 366bc70c172SBrian Feldman */ 3670602ee7cSBrian Feldman (void)getmntname(mntfromname, mntonname, NOTHING, &type, MARK); 368bc70c172SBrian Feldman /* 369bc70c172SBrian Feldman * If several equal mounts are in the mounttable, check the order 370bc70c172SBrian Feldman * and warn the user if necessary. 371bc70c172SBrian Feldman */ 372bc70c172SBrian Feldman if (strcmp(mntfromnamerev, mntfromname ) != 0 && 373bc70c172SBrian Feldman strcmp(resolved, mntonname) != 0) { 374bc70c172SBrian Feldman warnx("cannot umount %s, %s\n " 375bc70c172SBrian Feldman "is mounted there, umount it first", 376bc70c172SBrian Feldman mntonname, mntfromnamerev); 377d499a0efSBruce Evans 378bc70c172SBrian Feldman /* call getmntname again to set mntcheck[i] to 0 */ 3790602ee7cSBrian Feldman (void)getmntname(mntfromname, mntonname, 380bc70c172SBrian Feldman NOTHING, &type, UNMARK); 381bc70c172SBrian Feldman return (1); 382bc70c172SBrian Feldman } 383bc70c172SBrian Feldman free(mntfromnamerev); 384bc70c172SBrian Feldman /* 385bc70c172SBrian Feldman * Check if we have to start the rpc-call later. 386bc70c172SBrian Feldman * If there are still identical nfs-names mounted, 387bc70c172SBrian Feldman * we skip the rpc-call. Obviously this has to 388bc70c172SBrian Feldman * happen before unmount(2), but it should happen 389bc70c172SBrian Feldman * after the previous namecheck. 390bc70c172SBrian Feldman */ 3910fe9a7daSBrian Feldman if (strcmp(type, "nfs") == 0 && getmntname(mntfromname, NULL, NOTHING, 3920fe9a7daSBrian Feldman &type, COUNT) != NULL) 3930fe9a7daSBrian Feldman do_rpc = 1; 394bc70c172SBrian Feldman else 3950fe9a7daSBrian Feldman do_rpc = 0; 3968fae3551SRodney W. Grimes if (!namematch(hp)) 397d499a0efSBruce Evans return (1); 398bc70c172SBrian Feldman if (unmount(mntonname, fflag) != 0 ) { 399bc70c172SBrian Feldman warn("unmount of %s failed", mntonname); 4008fae3551SRodney W. Grimes return (1); 4018fae3551SRodney W. Grimes } 402bc70c172SBrian Feldman if (vflag) 403bc70c172SBrian Feldman (void)printf("%s: unmount from %s\n", mntfromname, mntonname); 404bc70c172SBrian Feldman /* 405bc70c172SBrian Feldman * Report to mountd-server which nfsname 406bc70c172SBrian Feldman * has been unmounted. 407bc70c172SBrian Feldman */ 4080fe9a7daSBrian Feldman if (hp != NULL && !(fflag & MNT_FORCE) && do_rpc) { 4098fae3551SRodney W. Grimes memset(&saddr, 0, sizeof(saddr)); 4108fae3551SRodney W. Grimes saddr.sin_family = AF_INET; 4118fae3551SRodney W. Grimes saddr.sin_port = 0; 412b1a3bc5eSWarner Losh memmove(&saddr.sin_addr, hp->h_addr, 413b1a3bc5eSWarner Losh MIN(hp->h_length, sizeof(saddr.sin_addr))); 4148fae3551SRodney W. Grimes pertry.tv_sec = 3; 4158fae3551SRodney W. Grimes pertry.tv_usec = 0; 4168fae3551SRodney W. Grimes so = RPC_ANYSOCK; 4178fae3551SRodney W. Grimes if ((clp = clntudp_create(&saddr, 4188fae3551SRodney W. Grimes RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) { 4198fae3551SRodney W. Grimes clnt_pcreateerror("Cannot MNT PRC"); 4208fae3551SRodney W. Grimes return (1); 4218fae3551SRodney W. Grimes } 4228fae3551SRodney W. Grimes clp->cl_auth = authunix_create_default(); 4238fae3551SRodney W. Grimes try.tv_sec = 20; 4248fae3551SRodney W. Grimes try.tv_usec = 0; 425bc70c172SBrian Feldman clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, 426bc70c172SBrian Feldman nfsdirname, xdr_void, (caddr_t)0, try); 4278fae3551SRodney W. Grimes if (clnt_stat != RPC_SUCCESS) { 4288fae3551SRodney W. Grimes clnt_perror(clp, "Bad MNT RPC"); 4298fae3551SRodney W. Grimes return (1); 4308fae3551SRodney W. Grimes } 431bc70c172SBrian Feldman free(orignfsdirname); 4328fae3551SRodney W. Grimes auth_destroy(clp->cl_auth); 4338fae3551SRodney W. Grimes clnt_destroy(clp); 4348fae3551SRodney W. Grimes } 4358fae3551SRodney W. Grimes return (0); 4368fae3551SRodney W. Grimes } 4378fae3551SRodney W. Grimes 4388fae3551SRodney W. Grimes char * 439bc70c172SBrian Feldman getmntname(const char *fromname, const char *onname, 440bc70c172SBrian Feldman mntwhat what, char **type, dowhat mark) 4418fae3551SRodney W. Grimes { 442d499a0efSBruce Evans static struct statfs *mntbuf; 443bc70c172SBrian Feldman static size_t mntsize = 0; 444bc70c172SBrian Feldman static char *mntcheck = NULL; 445bc70c172SBrian Feldman static char *mntcount = NULL; 446bc70c172SBrian Feldman int i, count; 4478fae3551SRodney W. Grimes 448bc70c172SBrian Feldman if (mntsize <= 0) { 449bc70c172SBrian Feldman if ((mntsize = mntinfo(&mntbuf)) <= 0) 4508fae3551SRodney W. Grimes return (NULL); 4518fae3551SRodney W. Grimes } 452bc70c172SBrian Feldman if (mntcheck == NULL) { 453bc70c172SBrian Feldman if ((mntcheck = calloc(mntsize + 1, sizeof(int))) == NULL || 454bc70c172SBrian Feldman (mntcount = calloc(mntsize + 1, sizeof(int))) == NULL) 455bc70c172SBrian Feldman err(1, "calloc"); 456bc70c172SBrian Feldman } 457bc70c172SBrian Feldman /* 458bc70c172SBrian Feldman * We want to get the file systems in the reverse order 459bc70c172SBrian Feldman * that they were mounted. Mounted and unmounted filesystems 460bc70c172SBrian Feldman * are marked or unmarked in a table called 'mntcheck'. 461bc70c172SBrian Feldman * Unmount(const char *dir, int flags) does only take the 462bc70c172SBrian Feldman * mountpoint as argument, not the destination. If we don't pay 463bc70c172SBrian Feldman * attention to the order, it can happen that a overlaying 464bc70c172SBrian Feldman * filesystem get's unmounted instead of the one the user 465bc70c172SBrian Feldman * has choosen. 466bc70c172SBrian Feldman */ 467bc70c172SBrian Feldman switch (mark) { 468bc70c172SBrian Feldman case NAME: 469bc70c172SBrian Feldman /* Return only the specific name */ 470bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 471bc70c172SBrian Feldman if (fromname != NULL && what == MNTON && 472bc70c172SBrian Feldman !strcmp(mntbuf[i].f_mntfromname, fromname) && 473bc70c172SBrian Feldman mntcheck[i] != 1) { 4748fae3551SRodney W. Grimes if (type) 475d499a0efSBruce Evans *type = mntbuf[i].f_fstypename; 4768fae3551SRodney W. Grimes return (mntbuf[i].f_mntonname); 4778fae3551SRodney W. Grimes } 478bc70c172SBrian Feldman if (fromname != NULL && what == MNTFROM && 479bc70c172SBrian Feldman !strcmp(mntbuf[i].f_mntonname, fromname) && 480bc70c172SBrian Feldman mntcheck[i] != 1) { 4818fae3551SRodney W. Grimes if (type) 482d499a0efSBruce Evans *type = mntbuf[i].f_fstypename; 4838fae3551SRodney W. Grimes return (mntbuf[i].f_mntfromname); 4848fae3551SRodney W. Grimes } 4858fae3551SRodney W. Grimes } 4868fae3551SRodney W. Grimes return (NULL); 487bc70c172SBrian Feldman case MARK: 488bc70c172SBrian Feldman /* Mark current mount with '1' and return name */ 489bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 490bc70c172SBrian Feldman if (mntcheck[i] == 0 && 491bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntonname, onname) == 0) && 492bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) { 493bc70c172SBrian Feldman mntcheck[i] = 1; 494bc70c172SBrian Feldman return (mntbuf[i].f_mntonname); 495bc70c172SBrian Feldman } 496bc70c172SBrian Feldman } 497bc70c172SBrian Feldman return (NULL); 498bc70c172SBrian Feldman case UNMARK: 499bc70c172SBrian Feldman /* Unmark current mount with '0' and return name */ 500bc70c172SBrian Feldman for (i = 0; i < mntsize; i++) { 501bc70c172SBrian Feldman if (mntcheck[i] == 1 && 502bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntonname, onname) == 0) && 503bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) { 504bc70c172SBrian Feldman mntcheck[i] = 0; 505bc70c172SBrian Feldman return (mntbuf[i].f_mntonname); 506bc70c172SBrian Feldman } 507bc70c172SBrian Feldman } 508bc70c172SBrian Feldman return (NULL); 509bc70c172SBrian Feldman case COUNT: 510bc70c172SBrian Feldman /* Count the equal mntfromnames */ 511bc70c172SBrian Feldman count = 0; 512bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 513bc70c172SBrian Feldman if (strcmp(mntbuf[i].f_mntfromname, fromname) == 0) 514bc70c172SBrian Feldman count++; 515bc70c172SBrian Feldman } 516bc70c172SBrian Feldman /* Mark the already unmounted mounts and return 5170602ee7cSBrian Feldman * mntfromname if count <= 1. Else return NULL. 518bc70c172SBrian Feldman */ 519bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 520bc70c172SBrian Feldman if (strcmp(mntbuf[i].f_mntfromname, fromname) == 0) { 521bc70c172SBrian Feldman if (mntcount[i] == 1) 522bc70c172SBrian Feldman count--; 5230fe9a7daSBrian Feldman else { 524bc70c172SBrian Feldman mntcount[i] = 1; 5250fe9a7daSBrian Feldman break; 5260fe9a7daSBrian Feldman } 5270602ee7cSBrian Feldman } 5280602ee7cSBrian Feldman } 5290602ee7cSBrian Feldman if (count <= 1) 530bc70c172SBrian Feldman return (mntbuf[i].f_mntonname); 531bc70c172SBrian Feldman else 532bc70c172SBrian Feldman return (NULL); 533bc70c172SBrian Feldman case FREE: 534bc70c172SBrian Feldman free(mntbuf); 535bc70c172SBrian Feldman free(mntcheck); 536bc70c172SBrian Feldman return (NULL); 537bc70c172SBrian Feldman default: 538bc70c172SBrian Feldman return (NULL); 539bc70c172SBrian Feldman } 5408fae3551SRodney W. Grimes } 5418fae3551SRodney W. Grimes 5428fae3551SRodney W. Grimes int 543bc70c172SBrian Feldman namematch(struct hostent *hp) 5448fae3551SRodney W. Grimes { 5458fae3551SRodney W. Grimes char *cp, **np; 5468fae3551SRodney W. Grimes 5478fae3551SRodney W. Grimes if ((hp == NULL) || (nfshost == NULL)) 5488fae3551SRodney W. Grimes return (1); 5498fae3551SRodney W. Grimes 5508fae3551SRodney W. Grimes if (strcasecmp(nfshost, hp->h_name) == 0) 5518fae3551SRodney W. Grimes return (1); 5528fae3551SRodney W. Grimes 5538fae3551SRodney W. Grimes if ((cp = strchr(hp->h_name, '.')) != NULL) { 5548fae3551SRodney W. Grimes *cp = '\0'; 5558fae3551SRodney W. Grimes if (strcasecmp(nfshost, hp->h_name) == 0) 5568fae3551SRodney W. Grimes return (1); 5578fae3551SRodney W. Grimes } 5588fae3551SRodney W. Grimes for (np = hp->h_aliases; *np; np++) { 5598fae3551SRodney W. Grimes if (strcasecmp(nfshost, *np) == 0) 5608fae3551SRodney W. Grimes return (1); 5618fae3551SRodney W. Grimes if ((cp = strchr(*np, '.')) != NULL) { 5628fae3551SRodney W. Grimes *cp = '\0'; 5638fae3551SRodney W. Grimes if (strcasecmp(nfshost, *np) == 0) 5648fae3551SRodney W. Grimes return (1); 5658fae3551SRodney W. Grimes } 5668fae3551SRodney W. Grimes } 5678fae3551SRodney W. Grimes return (0); 5688fae3551SRodney W. Grimes } 5698fae3551SRodney W. Grimes 570bc70c172SBrian Feldman void 571bc70c172SBrian Feldman checkmntlist(char *name, char **fromname, char **onname, char **type) 572bc70c172SBrian Feldman { 573bc70c172SBrian Feldman 574bc70c172SBrian Feldman *fromname = getmntname(name, NULL, MNTFROM, type, NAME); 575bc70c172SBrian Feldman if (*fromname == NULL) { 576bc70c172SBrian Feldman *onname = getmntname(name, NULL, MNTON, type, NAME); 577bc70c172SBrian Feldman if (*onname != NULL) 578bc70c172SBrian Feldman *fromname = name; 579bc70c172SBrian Feldman } else 580bc70c172SBrian Feldman *onname = name; 581bc70c172SBrian Feldman } 582bc70c172SBrian Feldman 583bc70c172SBrian Feldman size_t 584bc70c172SBrian Feldman mntinfo(struct statfs **mntbuf) 585bc70c172SBrian Feldman { 586bc70c172SBrian Feldman static struct statfs *origbuf; 587bc70c172SBrian Feldman size_t bufsize; 588bc70c172SBrian Feldman int mntsize; 589bc70c172SBrian Feldman 590bc70c172SBrian Feldman mntsize = getfsstat(NULL, 0l, MNT_NOWAIT); 591bc70c172SBrian Feldman if (mntsize <= 0) 592bc70c172SBrian Feldman return (0); 593bc70c172SBrian Feldman bufsize = (mntsize + 1) * sizeof(struct statfs); 594bc70c172SBrian Feldman if ((origbuf = malloc(bufsize)) == NULL) 595bc70c172SBrian Feldman err(1, "malloc"); 596bc70c172SBrian Feldman mntsize = getfsstat(origbuf, (long)bufsize, MNT_NOWAIT); 597bc70c172SBrian Feldman *mntbuf = origbuf; 598bc70c172SBrian Feldman return (mntsize); 599bc70c172SBrian Feldman } 600bc70c172SBrian Feldman 601bc70c172SBrian Feldman char * 602bc70c172SBrian Feldman getrealname(char *name, char *realname) 603bc70c172SBrian Feldman { 604bc70c172SBrian Feldman char *dirname; 605bc70c172SBrian Feldman int havedir; 606bc70c172SBrian Feldman size_t baselen; 607bc70c172SBrian Feldman size_t dirlen; 608bc70c172SBrian Feldman 609bc70c172SBrian Feldman dirname = '\0'; 610bc70c172SBrian Feldman havedir = 0; 611bc70c172SBrian Feldman if (*name == '/') { 612bc70c172SBrian Feldman if (ISDOT(name + 1) || ISDOTDOT(name + 1)) 613bc70c172SBrian Feldman strcpy(realname, "/"); 614bc70c172SBrian Feldman else { 615bc70c172SBrian Feldman if ((dirname = strrchr(name + 1, '/')) == NULL) 6160fe9a7daSBrian Feldman snprintf(realname, MAXPATHLEN, "%s", name); 617bc70c172SBrian Feldman else 618bc70c172SBrian Feldman havedir = 1; 619bc70c172SBrian Feldman } 620bc70c172SBrian Feldman } else { 621bc70c172SBrian Feldman if (ISDOT(name) || ISDOTDOT(name)) 622bc70c172SBrian Feldman (void)realpath(name, realname); 623bc70c172SBrian Feldman else { 624bc70c172SBrian Feldman if ((dirname = strrchr(name, '/')) == NULL) { 625bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 626bc70c172SBrian Feldman return (NULL); 627bc70c172SBrian Feldman } else 628bc70c172SBrian Feldman havedir = 1; 629bc70c172SBrian Feldman } 630bc70c172SBrian Feldman } 631bc70c172SBrian Feldman if (havedir) { 632bc70c172SBrian Feldman *dirname++ = '\0'; 633bc70c172SBrian Feldman if (ISDOT(dirname)) { 634bc70c172SBrian Feldman *dirname = '\0'; 635bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 636bc70c172SBrian Feldman return (NULL); 637bc70c172SBrian Feldman } else if (ISDOTDOT(dirname)) { 638bc70c172SBrian Feldman *--dirname = '/'; 639bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 640bc70c172SBrian Feldman return (NULL); 641bc70c172SBrian Feldman } else { 642bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 643bc70c172SBrian Feldman return (NULL); 644bc70c172SBrian Feldman baselen = strlen(realname); 645bc70c172SBrian Feldman dirlen = strlen(dirname); 646bc70c172SBrian Feldman if (baselen + dirlen + 1 > MAXPATHLEN) 647bc70c172SBrian Feldman return (NULL); 648bc70c172SBrian Feldman if (realname[1] == '\0') { 649bc70c172SBrian Feldman memmove(realname + 1, dirname, dirlen); 650bc70c172SBrian Feldman realname[dirlen + 1] = '\0'; 651bc70c172SBrian Feldman } else { 652bc70c172SBrian Feldman realname[baselen] = '/'; 653bc70c172SBrian Feldman memmove(realname + baselen + 1, 654bc70c172SBrian Feldman dirname, dirlen); 655bc70c172SBrian Feldman realname[baselen + dirlen + 1] = '\0'; 656bc70c172SBrian Feldman } 657bc70c172SBrian Feldman } 658bc70c172SBrian Feldman } 659bc70c172SBrian Feldman return (realname); 660bc70c172SBrian Feldman } 661bc70c172SBrian Feldman 6628fae3551SRodney W. Grimes /* 6638fae3551SRodney W. Grimes * xdr routines for mount rpc's 6648fae3551SRodney W. Grimes */ 6658fae3551SRodney W. Grimes int 666bc70c172SBrian Feldman xdr_dir(XDR *xdrsp, char *dirp) 6678fae3551SRodney W. Grimes { 668bc70c172SBrian Feldman 6698fae3551SRodney W. Grimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 6708fae3551SRodney W. Grimes } 6718fae3551SRodney W. Grimes 6728fae3551SRodney W. Grimes void 6738fae3551SRodney W. Grimes usage() 6748fae3551SRodney W. Grimes { 675bc70c172SBrian Feldman 676210a5dc8SPhilippe Charnier (void)fprintf(stderr, "%s\n%s\n", 677210a5dc8SPhilippe Charnier "usage: umount [-fv] special | node", 678210a5dc8SPhilippe Charnier " umount -a | -A [-fv] [-h host] [-t type]"); 6798fae3551SRodney W. Grimes exit(1); 6808fae3551SRodney W. Grimes } 681