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 62a69497d7SMatthew Dillon #include "mounttab.h" 63a69497d7SMatthew Dillon 64bc70c172SBrian Feldman #define ISDOT(x) ((x)[0] == '.' && (x)[1] == '\0') 65bc70c172SBrian Feldman #define ISDOTDOT(x) ((x)[0] == '.' && (x)[1] == '.' && (x)[2] == '\0') 668fae3551SRodney W. Grimes 67bc70c172SBrian Feldman typedef enum { MNTON, MNTFROM, NOTHING } mntwhat; 68bc70c172SBrian Feldman typedef enum { MARK, UNMARK, NAME, COUNT, FREE } dowhat; 69bc70c172SBrian Feldman 70a69497d7SMatthew Dillon struct mtablist *mtabhead; 710fe9a7daSBrian Feldman int fflag, vflag; 728fae3551SRodney W. Grimes char *nfshost; 738fae3551SRodney W. Grimes 74bc70c172SBrian Feldman void checkmntlist (char *, char **, char **, char **); 75bc70c172SBrian Feldman int checkvfsname (const char *, char **); 76bc70c172SBrian Feldman char *getmntname (const char *, const char *, 77bc70c172SBrian Feldman mntwhat, char **, dowhat); 78bc70c172SBrian Feldman char *getrealname(char *, char *resolved_path); 79bc70c172SBrian Feldman char **makevfslist (const char *); 80bc70c172SBrian Feldman size_t mntinfo (struct statfs **); 81bc70c172SBrian Feldman int namematch (struct hostent *); 82bc70c172SBrian Feldman int umountall (char **); 83bc70c172SBrian Feldman int umountfs (char *, char **); 84bc70c172SBrian Feldman void usage (void); 85bc70c172SBrian Feldman int xdr_dir (XDR *, char *); 868fae3551SRodney W. Grimes 878fae3551SRodney W. Grimes int 88bc70c172SBrian Feldman main(int argc, char *argv[]) 898fae3551SRodney W. Grimes { 90bc70c172SBrian Feldman int all, errs, ch, mntsize; 91bc70c172SBrian Feldman char **typelist = NULL, *mntonname, *mntfromname; 92bc70c172SBrian Feldman char *type, *mntfromnamerev, *mntonnamerev; 93d499a0efSBruce Evans struct statfs *mntbuf; 948fae3551SRodney W. Grimes 958fae3551SRodney W. Grimes /* Start disks transferring immediately. */ 968fae3551SRodney W. Grimes sync(); 978fae3551SRodney W. Grimes 980fe9a7daSBrian Feldman all = errs = 0; 99bc70c172SBrian Feldman while ((ch = getopt(argc, argv, "Aafh:t:v")) != -1) 1008fae3551SRodney W. Grimes switch (ch) { 101d499a0efSBruce Evans case 'A': 102d499a0efSBruce Evans all = 2; 103d499a0efSBruce Evans break; 1048fae3551SRodney W. Grimes case 'a': 1058fae3551SRodney W. Grimes all = 1; 1068fae3551SRodney W. Grimes break; 1078fae3551SRodney W. Grimes case 'f': 1088fae3551SRodney W. Grimes fflag = MNT_FORCE; 1098fae3551SRodney W. Grimes break; 110d499a0efSBruce Evans case 'h': /* -h implies -A. */ 111d499a0efSBruce Evans all = 2; 1128fae3551SRodney W. Grimes nfshost = optarg; 1138fae3551SRodney W. Grimes break; 1148fae3551SRodney W. Grimes case 't': 115d499a0efSBruce Evans if (typelist != NULL) 116bc70c172SBrian Feldman err(1, "only one -t option may be specified"); 117d499a0efSBruce Evans typelist = makevfslist(optarg); 1188fae3551SRodney W. Grimes break; 1198fae3551SRodney W. Grimes case 'v': 1208fae3551SRodney W. Grimes vflag = 1; 1218fae3551SRodney W. Grimes break; 1228fae3551SRodney W. Grimes default: 1238fae3551SRodney W. Grimes usage(); 1248fae3551SRodney W. Grimes /* NOTREACHED */ 1258fae3551SRodney W. Grimes } 1268fae3551SRodney W. Grimes argc -= optind; 1278fae3551SRodney W. Grimes argv += optind; 1288fae3551SRodney W. Grimes 129adb378ceSPhilippe Charnier if ((argc == 0 && !all) || (argc != 0 && all)) 1308fae3551SRodney W. Grimes usage(); 1318fae3551SRodney W. Grimes 1328fae3551SRodney W. Grimes /* -h implies "-t nfs" if no -t flag. */ 1338fae3551SRodney W. Grimes if ((nfshost != NULL) && (typelist == NULL)) 134d499a0efSBruce Evans typelist = makevfslist("nfs"); 1358fae3551SRodney W. Grimes 136d499a0efSBruce Evans switch (all) { 137d499a0efSBruce Evans case 2: 138bc70c172SBrian Feldman if ((mntsize = mntinfo(&mntbuf)) <= 0) 139d499a0efSBruce Evans break; 140bc70c172SBrian Feldman /* 141bc70c172SBrian Feldman * We unmount the nfs-mounts in the reverse order 142bc70c172SBrian Feldman * that they were mounted. 143bc70c172SBrian Feldman */ 144bc70c172SBrian Feldman for (errs = 0, mntsize--; mntsize > 0; mntsize--) { 145bc70c172SBrian Feldman if (checkvfsname(mntbuf[mntsize].f_fstypename, 146bc70c172SBrian Feldman typelist)) 147d499a0efSBruce Evans continue; 148bc70c172SBrian Feldman /* 149bc70c172SBrian Feldman * Check if a mountpoint is laid over by another mount. 150bc70c172SBrian Feldman * A warning will be printed to stderr if this is 151bc70c172SBrian Feldman * the case. The laid over mount remains unmounted. 152bc70c172SBrian Feldman */ 153bc70c172SBrian Feldman mntonname = mntbuf[mntsize].f_mntonname; 154bc70c172SBrian Feldman mntfromname = mntbuf[mntsize].f_mntfromname; 155bc70c172SBrian Feldman mntonnamerev = getmntname(getmntname(mntonname, 156bc70c172SBrian Feldman NULL, MNTFROM, &type, NAME), NULL, 157bc70c172SBrian Feldman MNTON, &type, NAME); 158bc70c172SBrian Feldman 159bc70c172SBrian Feldman mntfromnamerev = getmntname(mntonnamerev, 160bc70c172SBrian Feldman NULL, MNTFROM, &type, NAME); 161bc70c172SBrian Feldman 162bc70c172SBrian Feldman if (strcmp(mntonnamerev, mntonname) == 0 && 163bc70c172SBrian Feldman strcmp(mntfromnamerev, mntfromname ) != 0) 164bc70c172SBrian Feldman warnx("cannot umount %s, %s\n " 165bc70c172SBrian Feldman "is mounted there, umount it first", 166bc70c172SBrian Feldman mntonname, mntfromnamerev); 167bc70c172SBrian Feldman 168bc70c172SBrian Feldman if (umountfs(mntbuf[mntsize].f_mntonname, 169bc70c172SBrian Feldman typelist) != 0) 170d499a0efSBruce Evans errs = 1; 171d499a0efSBruce Evans } 172bc70c172SBrian Feldman free(mntbuf); 173d499a0efSBruce Evans break; 174d499a0efSBruce Evans case 1: 1758fae3551SRodney W. Grimes if (setfsent() == 0) 1768fae3551SRodney W. Grimes err(1, "%s", _PATH_FSTAB); 177d499a0efSBruce Evans errs = umountall(typelist); 178d499a0efSBruce Evans break; 179d499a0efSBruce Evans case 0: 1808fae3551SRodney W. Grimes for (errs = 0; *argv != NULL; ++argv) 181d499a0efSBruce Evans if (umountfs(*argv, typelist) != 0) 182d499a0efSBruce Evans errs = 1; 183d499a0efSBruce Evans break; 184d499a0efSBruce Evans } 185bc70c172SBrian Feldman (void)getmntname(NULL, NULL, NOTHING, NULL, FREE); 1868fae3551SRodney W. Grimes exit(errs); 1878fae3551SRodney W. Grimes } 1888fae3551SRodney W. Grimes 1898fae3551SRodney W. Grimes int 190bc70c172SBrian Feldman umountall(char **typelist) 1918fae3551SRodney W. Grimes { 1920602ee7cSBrian Feldman struct vfsconf vfc; 1938fae3551SRodney W. Grimes struct fstab *fs; 194adb378ceSPhilippe Charnier int rval; 1958fae3551SRodney W. Grimes char *cp; 1960602ee7cSBrian Feldman static int firstcall = 1; 1978fae3551SRodney W. Grimes 19891a81678SBrian Feldman if ((fs = getfsent()) != NULL) 1990602ee7cSBrian Feldman firstcall = 0; 20091a81678SBrian Feldman else if (firstcall) 20191a81678SBrian Feldman errx(1, "fstab reading failure"); 20291a81678SBrian Feldman else 20391a81678SBrian Feldman return (0); 204bc70c172SBrian Feldman do { 2058fae3551SRodney W. Grimes /* Ignore the root. */ 2068fae3551SRodney W. Grimes if (strcmp(fs->fs_file, "/") == 0) 2078fae3551SRodney W. Grimes continue; 2088fae3551SRodney W. Grimes /* 2098fae3551SRodney W. Grimes * !!! 2108fae3551SRodney W. Grimes * Historic practice: ignore unknown FSTAB_* fields. 2118fae3551SRodney W. Grimes */ 2128fae3551SRodney W. Grimes if (strcmp(fs->fs_type, FSTAB_RW) && 2138fae3551SRodney W. Grimes strcmp(fs->fs_type, FSTAB_RO) && 2148fae3551SRodney W. Grimes strcmp(fs->fs_type, FSTAB_RQ)) 2158fae3551SRodney W. Grimes continue; 2168fae3551SRodney W. Grimes /* If an unknown file system type, complain. */ 217bc70c172SBrian Feldman if (getvfsbyname(fs->fs_vfstype, &vfc) == -1) { 2188fae3551SRodney W. Grimes warnx("%s: unknown mount type", fs->fs_vfstype); 2198fae3551SRodney W. Grimes continue; 2208fae3551SRodney W. Grimes } 221d499a0efSBruce Evans if (checkvfsname(fs->fs_vfstype, typelist)) 2228fae3551SRodney W. Grimes continue; 2238fae3551SRodney W. Grimes 2248fae3551SRodney W. Grimes /* 2258fae3551SRodney W. Grimes * We want to unmount the file systems in the reverse order 2268fae3551SRodney W. Grimes * that they were mounted. So, we save off the file name 2278fae3551SRodney W. Grimes * in some allocated memory, and then call recursively. 2288fae3551SRodney W. Grimes */ 2298fae3551SRodney W. Grimes if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL) 230bc70c172SBrian Feldman err(1, "malloc failed"); 2318fae3551SRodney W. Grimes (void)strcpy(cp, fs->fs_file); 232d499a0efSBruce Evans rval = umountall(typelist); 2330602ee7cSBrian Feldman rval = umountfs(cp, typelist) || rval; 234bc70c172SBrian Feldman free(cp); 2350602ee7cSBrian Feldman return (rval); 2360602ee7cSBrian Feldman } while ((fs = getfsent()) != NULL); 2378fae3551SRodney W. Grimes return (0); 2388fae3551SRodney W. Grimes } 2398fae3551SRodney W. Grimes 2408fae3551SRodney W. Grimes int 241bc70c172SBrian Feldman umountfs(char *name, char **typelist) 2428fae3551SRodney W. Grimes { 2438fae3551SRodney W. Grimes enum clnt_stat clnt_stat; 2448fae3551SRodney W. Grimes struct hostent *hp; 245a69497d7SMatthew Dillon struct mtablist *mtab; 2468fae3551SRodney W. Grimes struct sockaddr_in saddr; 2478fae3551SRodney W. Grimes struct timeval pertry, try; 2488fae3551SRodney W. Grimes CLIENT *clp; 249bc70c172SBrian Feldman size_t len; 2500fe9a7daSBrian Feldman int so, speclen, do_rpc; 251bc70c172SBrian Feldman char *mntonname, *mntfromname; 2520602ee7cSBrian Feldman char *mntfromnamerev; 253bc70c172SBrian Feldman char *nfsdirname, *orignfsdirname; 2540fe9a7daSBrian Feldman char *resolved, realname[MAXPATHLEN]; 255bc70c172SBrian Feldman char *type, *delimp, *hostp, *origname; 2568fae3551SRodney W. Grimes 2570602ee7cSBrian Feldman len = 0; 258a69497d7SMatthew Dillon mtab = NULL; 259bc70c172SBrian Feldman mntfromname = mntonname = delimp = hostp = orignfsdirname = NULL; 2608fae3551SRodney W. Grimes 261bc70c172SBrian Feldman /* 262bc70c172SBrian Feldman * 1. Check if the name exists in the mounttable. 263bc70c172SBrian Feldman */ 264bc70c172SBrian Feldman (void)checkmntlist(name, &mntfromname, &mntonname, &type); 265bc70c172SBrian Feldman /* 266bc70c172SBrian Feldman * 2. Remove trailing slashes if there are any. After that 267bc70c172SBrian Feldman * we look up the name in the mounttable again. 268bc70c172SBrian Feldman */ 269bc70c172SBrian Feldman if (mntfromname == NULL && mntonname == NULL) { 270bc70c172SBrian Feldman speclen = strlen(name); 271bc70c172SBrian Feldman for (speclen = strlen(name); 272bc70c172SBrian Feldman speclen > 1 && name[speclen - 1] == '/'; 273bc70c172SBrian Feldman speclen--) 274bc70c172SBrian Feldman name[speclen - 1] = '\0'; 275bc70c172SBrian Feldman (void)checkmntlist(name, &mntfromname, &mntonname, &type); 276bc70c172SBrian Feldman resolved = name; 277bc70c172SBrian Feldman /* Save off original name in origname */ 278bc70c172SBrian Feldman if ((origname = strdup(name)) == NULL) 279bc70c172SBrian Feldman err(1, "strdup"); 280bc70c172SBrian Feldman /* 281bc70c172SBrian Feldman * 3. Check if the deprecated nfs-syntax with an '@' 282bc70c172SBrian Feldman * has been used and translate it to the ':' syntax. 283bc70c172SBrian Feldman * Look up the name in the mounttable again. 284bc70c172SBrian Feldman */ 285bc70c172SBrian Feldman if (mntfromname == NULL && mntonname == NULL) { 286bc70c172SBrian Feldman if ((delimp = strrchr(name, '@')) != NULL) { 287bc70c172SBrian Feldman hostp = delimp + 1; 288bc70c172SBrian Feldman if (*hostp != '\0') { 289bc70c172SBrian Feldman /* 290bc70c172SBrian Feldman * Make both '@' and ':' 291bc70c172SBrian Feldman * notations equal 292bc70c172SBrian Feldman */ 293bc70c172SBrian Feldman char *host = strdup(hostp); 294bc70c172SBrian Feldman len = strlen(hostp); 295bc70c172SBrian Feldman if (host == NULL) 296bc70c172SBrian Feldman err(1, "strdup"); 297bc70c172SBrian Feldman memmove(name + len + 1, name, 298bc70c172SBrian Feldman (size_t)(delimp - name)); 299bc70c172SBrian Feldman name[len] = ':'; 300bc70c172SBrian Feldman memmove(name, host, len); 301bc70c172SBrian Feldman free(host); 302bc70c172SBrian Feldman } 303bc70c172SBrian Feldman for (speclen = strlen(name); 304bc70c172SBrian Feldman speclen > 1 && name[speclen - 1] == '/'; 305bc70c172SBrian Feldman speclen--) 306bc70c172SBrian Feldman name[speclen - 1] = '\0'; 307bc70c172SBrian Feldman name[len + speclen + 1] = '\0'; 308bc70c172SBrian Feldman (void)checkmntlist(name, &mntfromname, 309bc70c172SBrian Feldman &mntonname, &type); 310bc70c172SBrian Feldman resolved = name; 311bc70c172SBrian Feldman } 312bc70c172SBrian Feldman /* 313bc70c172SBrian Feldman * 4. Check if a relative mountpoint has been 314bc70c172SBrian Feldman * specified. This should happen as last check, 315bc70c172SBrian Feldman * the order is important. To prevent possible 316bc70c172SBrian Feldman * nfs-hangs, we just call realpath(3) on the 317bc70c172SBrian Feldman * basedir of mountpoint and add the dirname again. 318bc70c172SBrian Feldman * Check the name in mounttable one last time. 319bc70c172SBrian Feldman */ 320bc70c172SBrian Feldman if (mntfromname == NULL && mntonname == NULL) { 321bc70c172SBrian Feldman (void)strcpy(name, origname); 322bc70c172SBrian Feldman if ((getrealname(name, realname)) != NULL) { 323bc70c172SBrian Feldman (void)checkmntlist(realname, 324bc70c172SBrian Feldman &mntfromname, &mntonname, &type); 325bc70c172SBrian Feldman resolved = realname; 326bc70c172SBrian Feldman } 327bc70c172SBrian Feldman /* 328bc70c172SBrian Feldman * All tests failed, return to main() 329bc70c172SBrian Feldman */ 330bc70c172SBrian Feldman if (mntfromname == NULL && mntonname == NULL) { 331bc70c172SBrian Feldman (void)strcpy(name, origname); 332bc70c172SBrian Feldman warnx("%s: not currently mounted", 333bc70c172SBrian Feldman origname); 334bc70c172SBrian Feldman free(origname); 3358fae3551SRodney W. Grimes return (1); 3368fae3551SRodney W. Grimes } 3378fae3551SRodney W. Grimes } 3388fae3551SRodney W. Grimes } 339bc70c172SBrian Feldman free(origname); 340bc70c172SBrian Feldman } else 341bc70c172SBrian Feldman resolved = name; 3428fae3551SRodney W. Grimes 343d499a0efSBruce Evans if (checkvfsname(type, typelist)) 344d499a0efSBruce Evans return (1); 3458fae3551SRodney W. Grimes 346d499a0efSBruce Evans hp = NULL; 347bc70c172SBrian Feldman nfsdirname = NULL; 348d499a0efSBruce Evans if (!strcmp(type, "nfs")) { 349bc70c172SBrian Feldman if ((nfsdirname = strdup(mntfromname)) == NULL) 350bc70c172SBrian Feldman err(1, "strdup"); 351bc70c172SBrian Feldman orignfsdirname = nfsdirname; 352bc70c172SBrian Feldman if ((delimp = strchr(nfsdirname, ':')) != NULL) { 3538fae3551SRodney W. Grimes *delimp = '\0'; 354bc70c172SBrian Feldman hostp = nfsdirname; 355bc70c172SBrian Feldman if ((hp = gethostbyname(hostp)) == NULL) { 356bc70c172SBrian Feldman warnx("can't get net id for host"); 357bc70c172SBrian Feldman } 358bc70c172SBrian Feldman nfsdirname = delimp + 1; 359d499a0efSBruce Evans } 360d499a0efSBruce Evans } 361bc70c172SBrian Feldman /* 362bc70c172SBrian Feldman * Check if the reverse entrys of the mounttable are really the 363bc70c172SBrian Feldman * same as the normal ones. 364bc70c172SBrian Feldman */ 365bc70c172SBrian Feldman if ((mntfromnamerev = strdup(getmntname(getmntname(mntfromname, 3660602ee7cSBrian Feldman NULL, MNTON, &type, NAME), NULL, MNTFROM, &type, NAME))) == NULL) 367bc70c172SBrian Feldman err(1, "strdup"); 368bc70c172SBrian Feldman /* 369bc70c172SBrian Feldman * Mark the uppermost mount as unmounted. 370bc70c172SBrian Feldman */ 3710602ee7cSBrian Feldman (void)getmntname(mntfromname, mntonname, NOTHING, &type, MARK); 372bc70c172SBrian Feldman /* 373bc70c172SBrian Feldman * If several equal mounts are in the mounttable, check the order 374bc70c172SBrian Feldman * and warn the user if necessary. 375bc70c172SBrian Feldman */ 376bc70c172SBrian Feldman if (strcmp(mntfromnamerev, mntfromname ) != 0 && 377bc70c172SBrian Feldman strcmp(resolved, mntonname) != 0) { 378bc70c172SBrian Feldman warnx("cannot umount %s, %s\n " 379bc70c172SBrian Feldman "is mounted there, umount it first", 380bc70c172SBrian Feldman mntonname, mntfromnamerev); 381d499a0efSBruce Evans 382bc70c172SBrian Feldman /* call getmntname again to set mntcheck[i] to 0 */ 3830602ee7cSBrian Feldman (void)getmntname(mntfromname, mntonname, 384bc70c172SBrian Feldman NOTHING, &type, UNMARK); 385bc70c172SBrian Feldman return (1); 386bc70c172SBrian Feldman } 387bc70c172SBrian Feldman free(mntfromnamerev); 388bc70c172SBrian Feldman /* 389bc70c172SBrian Feldman * Check if we have to start the rpc-call later. 390bc70c172SBrian Feldman * If there are still identical nfs-names mounted, 391bc70c172SBrian Feldman * we skip the rpc-call. Obviously this has to 392bc70c172SBrian Feldman * happen before unmount(2), but it should happen 393bc70c172SBrian Feldman * after the previous namecheck. 394bc70c172SBrian Feldman */ 3950fe9a7daSBrian Feldman if (strcmp(type, "nfs") == 0 && getmntname(mntfromname, NULL, NOTHING, 3960fe9a7daSBrian Feldman &type, COUNT) != NULL) 3970fe9a7daSBrian Feldman do_rpc = 1; 398bc70c172SBrian Feldman else 3990fe9a7daSBrian Feldman do_rpc = 0; 4008fae3551SRodney W. Grimes if (!namematch(hp)) 401d499a0efSBruce Evans return (1); 402bc70c172SBrian Feldman if (unmount(mntonname, fflag) != 0 ) { 403bc70c172SBrian Feldman warn("unmount of %s failed", mntonname); 4048fae3551SRodney W. Grimes return (1); 4058fae3551SRodney W. Grimes } 406bc70c172SBrian Feldman if (vflag) 407bc70c172SBrian Feldman (void)printf("%s: unmount from %s\n", mntfromname, mntonname); 408bc70c172SBrian Feldman /* 409bc70c172SBrian Feldman * Report to mountd-server which nfsname 410bc70c172SBrian Feldman * has been unmounted. 411bc70c172SBrian Feldman */ 4120fe9a7daSBrian Feldman if (hp != NULL && !(fflag & MNT_FORCE) && do_rpc) { 4138fae3551SRodney W. Grimes memset(&saddr, 0, sizeof(saddr)); 4148fae3551SRodney W. Grimes saddr.sin_family = AF_INET; 4158fae3551SRodney W. Grimes saddr.sin_port = 0; 416b1a3bc5eSWarner Losh memmove(&saddr.sin_addr, hp->h_addr, 417b1a3bc5eSWarner Losh MIN(hp->h_length, sizeof(saddr.sin_addr))); 4188fae3551SRodney W. Grimes pertry.tv_sec = 3; 4198fae3551SRodney W. Grimes pertry.tv_usec = 0; 4208fae3551SRodney W. Grimes so = RPC_ANYSOCK; 4218fae3551SRodney W. Grimes if ((clp = clntudp_create(&saddr, 4228fae3551SRodney W. Grimes RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) { 4238fae3551SRodney W. Grimes clnt_pcreateerror("Cannot MNT PRC"); 4248fae3551SRodney W. Grimes return (1); 4258fae3551SRodney W. Grimes } 4268fae3551SRodney W. Grimes clp->cl_auth = authunix_create_default(); 4278fae3551SRodney W. Grimes try.tv_sec = 20; 4288fae3551SRodney W. Grimes try.tv_usec = 0; 429bc70c172SBrian Feldman clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, 430bc70c172SBrian Feldman nfsdirname, xdr_void, (caddr_t)0, try); 4318fae3551SRodney W. Grimes if (clnt_stat != RPC_SUCCESS) { 4328fae3551SRodney W. Grimes clnt_perror(clp, "Bad MNT RPC"); 4338fae3551SRodney W. Grimes return (1); 4348fae3551SRodney W. Grimes } 435a69497d7SMatthew Dillon /* 436a69497d7SMatthew Dillon * Remove the unmounted entry from /var/db/mounttab. 437a69497d7SMatthew Dillon */ 438a69497d7SMatthew Dillon if (read_mtab(mtab)) { 439a69497d7SMatthew Dillon mtab = mtabhead; 440a69497d7SMatthew Dillon clean_mtab(hostp, nfsdirname); 441a69497d7SMatthew Dillon if(!write_mtab()) 442a69497d7SMatthew Dillon warnx("cannot remove entry %s:%s", 443a69497d7SMatthew Dillon hostp, nfsdirname); 444a69497d7SMatthew Dillon free_mtab(); 445a69497d7SMatthew Dillon } 446bc70c172SBrian Feldman free(orignfsdirname); 4478fae3551SRodney W. Grimes auth_destroy(clp->cl_auth); 4488fae3551SRodney W. Grimes clnt_destroy(clp); 4498fae3551SRodney W. Grimes } 4508fae3551SRodney W. Grimes return (0); 4518fae3551SRodney W. Grimes } 4528fae3551SRodney W. Grimes 4538fae3551SRodney W. Grimes char * 454bc70c172SBrian Feldman getmntname(const char *fromname, const char *onname, 455bc70c172SBrian Feldman mntwhat what, char **type, dowhat mark) 4568fae3551SRodney W. Grimes { 457d499a0efSBruce Evans static struct statfs *mntbuf; 458bc70c172SBrian Feldman static size_t mntsize = 0; 459bc70c172SBrian Feldman static char *mntcheck = NULL; 460bc70c172SBrian Feldman static char *mntcount = NULL; 461bc70c172SBrian Feldman int i, count; 4628fae3551SRodney W. Grimes 463bc70c172SBrian Feldman if (mntsize <= 0) { 464bc70c172SBrian Feldman if ((mntsize = mntinfo(&mntbuf)) <= 0) 4658fae3551SRodney W. Grimes return (NULL); 4668fae3551SRodney W. Grimes } 467bc70c172SBrian Feldman if (mntcheck == NULL) { 468bc70c172SBrian Feldman if ((mntcheck = calloc(mntsize + 1, sizeof(int))) == NULL || 469bc70c172SBrian Feldman (mntcount = calloc(mntsize + 1, sizeof(int))) == NULL) 470bc70c172SBrian Feldman err(1, "calloc"); 471bc70c172SBrian Feldman } 472bc70c172SBrian Feldman /* 473bc70c172SBrian Feldman * We want to get the file systems in the reverse order 474bc70c172SBrian Feldman * that they were mounted. Mounted and unmounted filesystems 475bc70c172SBrian Feldman * are marked or unmarked in a table called 'mntcheck'. 476bc70c172SBrian Feldman * Unmount(const char *dir, int flags) does only take the 477bc70c172SBrian Feldman * mountpoint as argument, not the destination. If we don't pay 478bc70c172SBrian Feldman * attention to the order, it can happen that a overlaying 479bc70c172SBrian Feldman * filesystem get's unmounted instead of the one the user 480bc70c172SBrian Feldman * has choosen. 481bc70c172SBrian Feldman */ 482bc70c172SBrian Feldman switch (mark) { 483bc70c172SBrian Feldman case NAME: 484bc70c172SBrian Feldman /* Return only the specific name */ 485bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 486bc70c172SBrian Feldman if (fromname != NULL && what == MNTON && 487bc70c172SBrian Feldman !strcmp(mntbuf[i].f_mntfromname, fromname) && 488bc70c172SBrian Feldman mntcheck[i] != 1) { 4898fae3551SRodney W. Grimes if (type) 490d499a0efSBruce Evans *type = mntbuf[i].f_fstypename; 4918fae3551SRodney W. Grimes return (mntbuf[i].f_mntonname); 4928fae3551SRodney W. Grimes } 493bc70c172SBrian Feldman if (fromname != NULL && what == MNTFROM && 494bc70c172SBrian Feldman !strcmp(mntbuf[i].f_mntonname, fromname) && 495bc70c172SBrian Feldman mntcheck[i] != 1) { 4968fae3551SRodney W. Grimes if (type) 497d499a0efSBruce Evans *type = mntbuf[i].f_fstypename; 4988fae3551SRodney W. Grimes return (mntbuf[i].f_mntfromname); 4998fae3551SRodney W. Grimes } 5008fae3551SRodney W. Grimes } 5018fae3551SRodney W. Grimes return (NULL); 502bc70c172SBrian Feldman case MARK: 503bc70c172SBrian Feldman /* Mark current mount with '1' and return name */ 504bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 505bc70c172SBrian Feldman if (mntcheck[i] == 0 && 506bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntonname, onname) == 0) && 507bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) { 508bc70c172SBrian Feldman mntcheck[i] = 1; 509bc70c172SBrian Feldman return (mntbuf[i].f_mntonname); 510bc70c172SBrian Feldman } 511bc70c172SBrian Feldman } 512bc70c172SBrian Feldman return (NULL); 513bc70c172SBrian Feldman case UNMARK: 514bc70c172SBrian Feldman /* Unmark current mount with '0' and return name */ 515bc70c172SBrian Feldman for (i = 0; i < mntsize; i++) { 516bc70c172SBrian Feldman if (mntcheck[i] == 1 && 517bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntonname, onname) == 0) && 518bc70c172SBrian Feldman (strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) { 519bc70c172SBrian Feldman mntcheck[i] = 0; 520bc70c172SBrian Feldman return (mntbuf[i].f_mntonname); 521bc70c172SBrian Feldman } 522bc70c172SBrian Feldman } 523bc70c172SBrian Feldman return (NULL); 524bc70c172SBrian Feldman case COUNT: 525bc70c172SBrian Feldman /* Count the equal mntfromnames */ 526bc70c172SBrian Feldman count = 0; 527bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 528bc70c172SBrian Feldman if (strcmp(mntbuf[i].f_mntfromname, fromname) == 0) 529bc70c172SBrian Feldman count++; 530bc70c172SBrian Feldman } 531bc70c172SBrian Feldman /* Mark the already unmounted mounts and return 5320602ee7cSBrian Feldman * mntfromname if count <= 1. Else return NULL. 533bc70c172SBrian Feldman */ 534bc70c172SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 535bc70c172SBrian Feldman if (strcmp(mntbuf[i].f_mntfromname, fromname) == 0) { 536bc70c172SBrian Feldman if (mntcount[i] == 1) 537bc70c172SBrian Feldman count--; 5380fe9a7daSBrian Feldman else { 539bc70c172SBrian Feldman mntcount[i] = 1; 5400fe9a7daSBrian Feldman break; 5410fe9a7daSBrian Feldman } 5420602ee7cSBrian Feldman } 5430602ee7cSBrian Feldman } 5440602ee7cSBrian Feldman if (count <= 1) 545bc70c172SBrian Feldman return (mntbuf[i].f_mntonname); 546bc70c172SBrian Feldman else 547bc70c172SBrian Feldman return (NULL); 548bc70c172SBrian Feldman case FREE: 549bc70c172SBrian Feldman free(mntbuf); 550bc70c172SBrian Feldman free(mntcheck); 551a69497d7SMatthew Dillon free(mntcount); 552bc70c172SBrian Feldman return (NULL); 553bc70c172SBrian Feldman default: 554bc70c172SBrian Feldman return (NULL); 555bc70c172SBrian Feldman } 5568fae3551SRodney W. Grimes } 5578fae3551SRodney W. Grimes 5588fae3551SRodney W. Grimes int 559bc70c172SBrian Feldman namematch(struct hostent *hp) 5608fae3551SRodney W. Grimes { 5618fae3551SRodney W. Grimes char *cp, **np; 5628fae3551SRodney W. Grimes 5638fae3551SRodney W. Grimes if ((hp == NULL) || (nfshost == NULL)) 5648fae3551SRodney W. Grimes return (1); 5658fae3551SRodney W. Grimes 5668fae3551SRodney W. Grimes if (strcasecmp(nfshost, hp->h_name) == 0) 5678fae3551SRodney W. Grimes return (1); 5688fae3551SRodney W. Grimes 5698fae3551SRodney W. Grimes if ((cp = strchr(hp->h_name, '.')) != NULL) { 5708fae3551SRodney W. Grimes *cp = '\0'; 5718fae3551SRodney W. Grimes if (strcasecmp(nfshost, hp->h_name) == 0) 5728fae3551SRodney W. Grimes return (1); 5738fae3551SRodney W. Grimes } 5748fae3551SRodney W. Grimes for (np = hp->h_aliases; *np; np++) { 5758fae3551SRodney W. Grimes if (strcasecmp(nfshost, *np) == 0) 5768fae3551SRodney W. Grimes return (1); 5778fae3551SRodney W. Grimes if ((cp = strchr(*np, '.')) != NULL) { 5788fae3551SRodney W. Grimes *cp = '\0'; 5798fae3551SRodney W. Grimes if (strcasecmp(nfshost, *np) == 0) 5808fae3551SRodney W. Grimes return (1); 5818fae3551SRodney W. Grimes } 5828fae3551SRodney W. Grimes } 5838fae3551SRodney W. Grimes return (0); 5848fae3551SRodney W. Grimes } 5858fae3551SRodney W. Grimes 586bc70c172SBrian Feldman void 587bc70c172SBrian Feldman checkmntlist(char *name, char **fromname, char **onname, char **type) 588bc70c172SBrian Feldman { 589bc70c172SBrian Feldman 590bc70c172SBrian Feldman *fromname = getmntname(name, NULL, MNTFROM, type, NAME); 591bc70c172SBrian Feldman if (*fromname == NULL) { 592bc70c172SBrian Feldman *onname = getmntname(name, NULL, MNTON, type, NAME); 593bc70c172SBrian Feldman if (*onname != NULL) 594bc70c172SBrian Feldman *fromname = name; 595bc70c172SBrian Feldman } else 596bc70c172SBrian Feldman *onname = name; 597bc70c172SBrian Feldman } 598bc70c172SBrian Feldman 599bc70c172SBrian Feldman size_t 600bc70c172SBrian Feldman mntinfo(struct statfs **mntbuf) 601bc70c172SBrian Feldman { 602bc70c172SBrian Feldman static struct statfs *origbuf; 603bc70c172SBrian Feldman size_t bufsize; 604bc70c172SBrian Feldman int mntsize; 605bc70c172SBrian Feldman 606a69497d7SMatthew Dillon mntsize = getfsstat(NULL, 0, MNT_NOWAIT); 607bc70c172SBrian Feldman if (mntsize <= 0) 608bc70c172SBrian Feldman return (0); 609bc70c172SBrian Feldman bufsize = (mntsize + 1) * sizeof(struct statfs); 610bc70c172SBrian Feldman if ((origbuf = malloc(bufsize)) == NULL) 611bc70c172SBrian Feldman err(1, "malloc"); 612bc70c172SBrian Feldman mntsize = getfsstat(origbuf, (long)bufsize, MNT_NOWAIT); 613bc70c172SBrian Feldman *mntbuf = origbuf; 614bc70c172SBrian Feldman return (mntsize); 615bc70c172SBrian Feldman } 616bc70c172SBrian Feldman 617bc70c172SBrian Feldman char * 618bc70c172SBrian Feldman getrealname(char *name, char *realname) 619bc70c172SBrian Feldman { 620bc70c172SBrian Feldman char *dirname; 621bc70c172SBrian Feldman int havedir; 622bc70c172SBrian Feldman size_t baselen; 623bc70c172SBrian Feldman size_t dirlen; 624bc70c172SBrian Feldman 625bc70c172SBrian Feldman dirname = '\0'; 626bc70c172SBrian Feldman havedir = 0; 627bc70c172SBrian Feldman if (*name == '/') { 628bc70c172SBrian Feldman if (ISDOT(name + 1) || ISDOTDOT(name + 1)) 629bc70c172SBrian Feldman strcpy(realname, "/"); 630bc70c172SBrian Feldman else { 631bc70c172SBrian Feldman if ((dirname = strrchr(name + 1, '/')) == NULL) 6320fe9a7daSBrian Feldman snprintf(realname, MAXPATHLEN, "%s", name); 633bc70c172SBrian Feldman else 634bc70c172SBrian Feldman havedir = 1; 635bc70c172SBrian Feldman } 636bc70c172SBrian Feldman } else { 637bc70c172SBrian Feldman if (ISDOT(name) || ISDOTDOT(name)) 638bc70c172SBrian Feldman (void)realpath(name, realname); 639bc70c172SBrian Feldman else { 640bc70c172SBrian Feldman if ((dirname = strrchr(name, '/')) == NULL) { 641bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 642bc70c172SBrian Feldman return (NULL); 643bc70c172SBrian Feldman } else 644bc70c172SBrian Feldman havedir = 1; 645bc70c172SBrian Feldman } 646bc70c172SBrian Feldman } 647bc70c172SBrian Feldman if (havedir) { 648bc70c172SBrian Feldman *dirname++ = '\0'; 649bc70c172SBrian Feldman if (ISDOT(dirname)) { 650bc70c172SBrian Feldman *dirname = '\0'; 651bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 652bc70c172SBrian Feldman return (NULL); 653bc70c172SBrian Feldman } else if (ISDOTDOT(dirname)) { 654bc70c172SBrian Feldman *--dirname = '/'; 655bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 656bc70c172SBrian Feldman return (NULL); 657bc70c172SBrian Feldman } else { 658bc70c172SBrian Feldman if ((realpath(name, realname)) == NULL) 659bc70c172SBrian Feldman return (NULL); 660bc70c172SBrian Feldman baselen = strlen(realname); 661bc70c172SBrian Feldman dirlen = strlen(dirname); 662bc70c172SBrian Feldman if (baselen + dirlen + 1 > MAXPATHLEN) 663bc70c172SBrian Feldman return (NULL); 664bc70c172SBrian Feldman if (realname[1] == '\0') { 665bc70c172SBrian Feldman memmove(realname + 1, dirname, dirlen); 666bc70c172SBrian Feldman realname[dirlen + 1] = '\0'; 667bc70c172SBrian Feldman } else { 668bc70c172SBrian Feldman realname[baselen] = '/'; 669bc70c172SBrian Feldman memmove(realname + baselen + 1, 670bc70c172SBrian Feldman dirname, dirlen); 671bc70c172SBrian Feldman realname[baselen + dirlen + 1] = '\0'; 672bc70c172SBrian Feldman } 673bc70c172SBrian Feldman } 674bc70c172SBrian Feldman } 675bc70c172SBrian Feldman return (realname); 676bc70c172SBrian Feldman } 677bc70c172SBrian Feldman 6788fae3551SRodney W. Grimes /* 6798fae3551SRodney W. Grimes * xdr routines for mount rpc's 6808fae3551SRodney W. Grimes */ 6818fae3551SRodney W. Grimes int 682bc70c172SBrian Feldman xdr_dir(XDR *xdrsp, char *dirp) 6838fae3551SRodney W. Grimes { 684bc70c172SBrian Feldman 6858fae3551SRodney W. Grimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 6868fae3551SRodney W. Grimes } 6878fae3551SRodney W. Grimes 6888fae3551SRodney W. Grimes void 6898fae3551SRodney W. Grimes usage() 6908fae3551SRodney W. Grimes { 691bc70c172SBrian Feldman 692210a5dc8SPhilippe Charnier (void)fprintf(stderr, "%s\n%s\n", 693210a5dc8SPhilippe Charnier "usage: umount [-fv] special | node", 694210a5dc8SPhilippe Charnier " umount -a | -A [-fv] [-h host] [-t type]"); 6958fae3551SRodney W. Grimes exit(1); 6968fae3551SRodney W. Grimes } 697