umount.c revision 65564
1219974Smav/*- 2219974Smav * Copyright (c) 1980, 1989, 1993 3219974Smav * The Regents of the University of California. All rights reserved. 4219974Smav * 5219974Smav * Redistribution and use in source and binary forms, with or without 6219974Smav * modification, are permitted provided that the following conditions 7219974Smav * are met: 8219974Smav * 1. Redistributions of source code must retain the above copyright 9219974Smav * notice, this list of conditions and the following disclaimer. 10219974Smav * 2. Redistributions in binary form must reproduce the above copyright 11219974Smav * notice, this list of conditions and the following disclaimer in the 12219974Smav * documentation and/or other materials provided with the distribution. 13219974Smav * 3. All advertising materials mentioning features or use of this software 14219974Smav * must display the following acknowledgement: 15219974Smav * This product includes software developed by the University of 16219974Smav * California, Berkeley and its contributors. 17219974Smav * 4. Neither the name of the University nor the names of its contributors 18219974Smav * may be used to endorse or promote products derived from this software 19219974Smav * without specific prior written permission. 20219974Smav * 21219974Smav * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22219974Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23219974Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24219974Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25219974Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26219974Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27219974Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28219974Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29219974Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30219974Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31219974Smav * SUCH DAMAGE. 32219974Smav */ 33219974Smav 34219974Smav#ifndef lint 35219974Smavstatic const char copyright[] = 36219974Smav"@(#) Copyright (c) 1980, 1989, 1993\n\ 37219974Smav The Regents of the University of California. All rights reserved.\n"; 38219974Smav#endif /* not lint */ 39219974Smav 40219974Smav#ifndef lint 41219974Smav#if 0 42219974Smavstatic char sccsid[] = "@(#)umount.c 8.8 (Berkeley) 5/8/95"; 43219974Smav#endif 44219974Smavstatic const char rcsid[] = 45219974Smav "$FreeBSD: head/sbin/umount/umount.c 65564 2000-09-07 07:03:11Z des $"; 46219974Smav#endif /* not lint */ 47240465Smav 48219974Smav#include <sys/param.h> 49219974Smav#include <sys/mount.h> 50219974Smav 51219974Smav#include <netdb.h> 52219974Smav#include <rpc/rpc.h> 53219974Smav#include <nfs/rpcv2.h> 54219974Smav 55219974Smav#include <err.h> 56219974Smav#include <fstab.h> 57219974Smav#include <stdio.h> 58219974Smav#include <stdlib.h> 59219974Smav#include <string.h> 60219974Smav#include <unistd.h> 61219974Smav 62219974Smav#include "mounttab.h" 63219974Smav 64219974Smav#define ISDOT(x) ((x)[0] == '.' && (x)[1] == '\0') 65219974Smav#define ISDOTDOT(x) ((x)[0] == '.' && (x)[1] == '.' && (x)[2] == '\0') 66219974Smav 67219974Smavtypedef enum { MNTON, MNTFROM, NOTHING } mntwhat; 68219974Smavtypedef enum { MARK, UNMARK, NAME, COUNT, FREE } dowhat; 69219974Smav 70219974Smavstruct mtablist *mtabhead; 71219974Smavint fflag, vflag; 72219974Smavchar *nfshost; 73219974Smav 74219974Smavvoid checkmntlist (char *, char **, char **, char **); 75219974Smavint checkvfsname (const char *, char **); 76219974Smavchar *getmntname (const char *, const char *, 77219974Smav mntwhat, char **, dowhat); 78219974Smavchar *getrealname(char *, char *resolved_path); 79219974Smavchar **makevfslist (const char *); 80219974Smavsize_t mntinfo (struct statfs **); 81219974Smavint namematch (struct hostent *); 82219974Smavint umountall (char **); 83219974Smavint umountfs (char *, char **); 84219974Smavvoid usage (void); 85219974Smavint xdr_dir (XDR *, char *); 86219974Smav 87219974Smavint 88219974Smavmain(int argc, char *argv[]) 89219974Smav{ 90219974Smav int all, errs, ch, mntsize; 91219974Smav char **typelist = NULL, *mntonname, *mntfromname; 92219974Smav char *type, *mntfromnamerev, *mntonnamerev; 93219974Smav struct statfs *mntbuf; 94219974Smav 95219974Smav /* Start disks transferring immediately. */ 96219974Smav sync(); 97219974Smav 98219974Smav all = errs = 0; 99219974Smav while ((ch = getopt(argc, argv, "Aafh:t:v")) != -1) 100219974Smav switch (ch) { 101219974Smav case 'A': 102219974Smav all = 2; 103219974Smav break; 104219974Smav case 'a': 105219974Smav all = 1; 106219974Smav break; 107219974Smav case 'f': 108219974Smav fflag = MNT_FORCE; 109219974Smav break; 110219974Smav case 'h': /* -h implies -A. */ 111219974Smav all = 2; 112219974Smav nfshost = optarg; 113219974Smav break; 114219974Smav case 't': 115219974Smav if (typelist != NULL) 116219974Smav err(1, "only one -t option may be specified"); 117219974Smav typelist = makevfslist(optarg); 118219974Smav break; 119219974Smav case 'v': 120219974Smav vflag = 1; 121219974Smav break; 122219974Smav default: 123219974Smav usage(); 124219974Smav /* NOTREACHED */ 125219974Smav } 126219974Smav argc -= optind; 127219974Smav argv += optind; 128219974Smav 129219974Smav if ((argc == 0 && !all) || (argc != 0 && all)) 130219974Smav usage(); 131219974Smav 132219974Smav /* -h implies "-t nfs" if no -t flag. */ 133219974Smav if ((nfshost != NULL) && (typelist == NULL)) 134219974Smav typelist = makevfslist("nfs"); 135219974Smav 136240465Smav switch (all) { 137260385Sscottl case 2: 138260385Sscottl if ((mntsize = mntinfo(&mntbuf)) <= 0) 139219974Smav break; 140219974Smav /* 141219974Smav * We unmount the nfs-mounts in the reverse order 142219974Smav * that they were mounted. 143219974Smav */ 144219974Smav for (errs = 0, mntsize--; mntsize > 0; mntsize--) { 145219974Smav if (checkvfsname(mntbuf[mntsize].f_fstypename, 146219974Smav typelist)) 147219974Smav continue; 148219974Smav /* 149219974Smav * Check if a mountpoint is laid over by another mount. 150219974Smav * A warning will be printed to stderr if this is 151219974Smav * the case. The laid over mount remains unmounted. 152219974Smav */ 153219974Smav mntonname = mntbuf[mntsize].f_mntonname; 154219974Smav mntfromname = mntbuf[mntsize].f_mntfromname; 155219974Smav mntonnamerev = getmntname(getmntname(mntonname, 156219974Smav NULL, MNTFROM, &type, NAME), NULL, 157219974Smav MNTON, &type, NAME); 158219974Smav 159219974Smav mntfromnamerev = getmntname(mntonnamerev, 160219974Smav NULL, MNTFROM, &type, NAME); 161219974Smav 162219974Smav if (strcmp(mntonnamerev, mntonname) == 0 && 163219974Smav strcmp(mntfromnamerev, mntfromname ) != 0) 164219974Smav warnx("cannot umount %s, %s\n " 165219974Smav "is mounted there, umount it first", 166219974Smav mntonname, mntfromnamerev); 167219974Smav 168219974Smav if (umountfs(mntbuf[mntsize].f_mntonname, 169219974Smav typelist) != 0) 170219974Smav errs = 1; 171219974Smav } 172219974Smav free(mntbuf); 173219974Smav break; 174219974Smav case 1: 175219974Smav if (setfsent() == 0) 176219974Smav err(1, "%s", _PATH_FSTAB); 177219974Smav errs = umountall(typelist); 178219974Smav break; 179219974Smav case 0: 180219974Smav for (errs = 0; *argv != NULL; ++argv) 181219974Smav if (umountfs(*argv, typelist) != 0) 182219974Smav errs = 1; 183219974Smav break; 184219974Smav } 185219974Smav (void)getmntname(NULL, NULL, NOTHING, NULL, FREE); 186219974Smav exit(errs); 187219974Smav} 188219974Smav 189219974Smavint 190234603Smavumountall(char **typelist) 191219974Smav{ 192219974Smav struct vfsconf vfc; 193219974Smav struct fstab *fs; 194219974Smav int rval; 195219974Smav char *cp; 196219974Smav static int firstcall = 1; 197219974Smav 198219974Smav if ((fs = getfsent()) != NULL) 199219974Smav firstcall = 0; 200219974Smav else if (firstcall) 201219974Smav errx(1, "fstab reading failure"); 202219974Smav else 203219974Smav return (0); 204219974Smav do { 205219974Smav /* Ignore the root. */ 206219974Smav if (strcmp(fs->fs_file, "/") == 0) 207219974Smav continue; 208219974Smav /* 209219974Smav * !!! 210219974Smav * Historic practice: ignore unknown FSTAB_* fields. 211219974Smav */ 212219974Smav if (strcmp(fs->fs_type, FSTAB_RW) && 213219974Smav strcmp(fs->fs_type, FSTAB_RO) && 214219974Smav strcmp(fs->fs_type, FSTAB_RQ)) 215219974Smav continue; 216219974Smav /* Ignore unknown file system types. */ 217219974Smav if (getvfsbyname(fs->fs_vfstype, &vfc) == -1) 218219974Smav continue; 219219974Smav if (checkvfsname(fs->fs_vfstype, typelist)) 220219974Smav continue; 221219974Smav 222219974Smav /* 223219974Smav * We want to unmount the file systems in the reverse order 224219974Smav * that they were mounted. So, we save off the file name 225219974Smav * in some allocated memory, and then call recursively. 226219974Smav */ 227219974Smav if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL) 228219974Smav err(1, "malloc failed"); 229219974Smav (void)strcpy(cp, fs->fs_file); 230219974Smav rval = umountall(typelist); 231219974Smav rval = umountfs(cp, typelist) || rval; 232219974Smav free(cp); 233219974Smav return (rval); 234219974Smav } while ((fs = getfsent()) != NULL); 235219974Smav return (0); 236219974Smav} 237219974Smav 238219974Smavint 239219974Smavumountfs(char *name, char **typelist) 240219974Smav{ 241219974Smav enum clnt_stat clnt_stat; 242219974Smav struct hostent *hp; 243219974Smav struct mtablist *mtab; 244219974Smav struct sockaddr_in saddr; 245219974Smav struct timeval pertry, try; 246219974Smav CLIENT *clp; 247219974Smav size_t len; 248219974Smav int so, speclen, do_rpc; 249219974Smav char *mntonname, *mntfromname; 250219974Smav char *mntfromnamerev; 251219974Smav char *nfsdirname, *orignfsdirname; 252219974Smav char *resolved, realname[MAXPATHLEN]; 253219974Smav char *type, *delimp, *hostp, *origname; 254219974Smav 255219974Smav len = 0; 256219974Smav mtab = NULL; 257219974Smav mntfromname = mntonname = delimp = hostp = orignfsdirname = NULL; 258219974Smav 259219974Smav /* 260219974Smav * 1. Check if the name exists in the mounttable. 261219974Smav */ 262219974Smav (void)checkmntlist(name, &mntfromname, &mntonname, &type); 263219974Smav /* 264219974Smav * 2. Remove trailing slashes if there are any. After that 265219974Smav * we look up the name in the mounttable again. 266219974Smav */ 267219974Smav if (mntfromname == NULL && mntonname == NULL) { 268219974Smav speclen = strlen(name); 269219974Smav for (speclen = strlen(name); 270219974Smav speclen > 1 && name[speclen - 1] == '/'; 271219974Smav speclen--) 272219974Smav name[speclen - 1] = '\0'; 273219974Smav (void)checkmntlist(name, &mntfromname, &mntonname, &type); 274219974Smav resolved = name; 275219974Smav /* Save off original name in origname */ 276219974Smav if ((origname = strdup(name)) == NULL) 277219974Smav err(1, "strdup"); 278219974Smav /* 279219974Smav * 3. Check if the deprecated nfs-syntax with an '@' 280219974Smav * has been used and translate it to the ':' syntax. 281219974Smav * Look up the name in the mounttable again. 282219974Smav */ 283219974Smav if (mntfromname == NULL && mntonname == NULL) { 284219974Smav if ((delimp = strrchr(name, '@')) != NULL) { 285219974Smav hostp = delimp + 1; 286219974Smav if (*hostp != '\0') { 287219974Smav /* 288219974Smav * Make both '@' and ':' 289219974Smav * notations equal 290219974Smav */ 291219974Smav char *host = strdup(hostp); 292219974Smav len = strlen(hostp); 293219974Smav if (host == NULL) 294219974Smav err(1, "strdup"); 295219974Smav memmove(name + len + 1, name, 296219974Smav (size_t)(delimp - name)); 297219974Smav name[len] = ':'; 298219974Smav memmove(name, host, len); 299219974Smav free(host); 300219974Smav } 301219974Smav for (speclen = strlen(name); 302219974Smav speclen > 1 && name[speclen - 1] == '/'; 303219974Smav speclen--) 304219974Smav name[speclen - 1] = '\0'; 305219974Smav name[len + speclen + 1] = '\0'; 306219974Smav (void)checkmntlist(name, &mntfromname, 307219974Smav &mntonname, &type); 308219974Smav resolved = name; 309219974Smav } 310219974Smav /* 311219974Smav * 4. Check if a relative mountpoint has been 312219974Smav * specified. This should happen as last check, 313219974Smav * the order is important. To prevent possible 314219974Smav * nfs-hangs, we just call realpath(3) on the 315219974Smav * basedir of mountpoint and add the dirname again. 316219974Smav * Check the name in mounttable one last time. 317219974Smav */ 318219974Smav if (mntfromname == NULL && mntonname == NULL) { 319219974Smav (void)strcpy(name, origname); 320219974Smav if ((getrealname(name, realname)) != NULL) { 321219974Smav (void)checkmntlist(realname, 322219974Smav &mntfromname, &mntonname, &type); 323219974Smav resolved = realname; 324219974Smav } 325219974Smav /* 326219974Smav * All tests failed, return to main() 327219974Smav */ 328219974Smav if (mntfromname == NULL && mntonname == NULL) { 329219974Smav (void)strcpy(name, origname); 330219974Smav warnx("%s: not currently mounted", 331219974Smav origname); 332219974Smav free(origname); 333219974Smav return (1); 334219974Smav } 335219974Smav } 336219974Smav } 337219974Smav free(origname); 338219974Smav } else 339219974Smav resolved = name; 340219974Smav 341235270Smav if (checkvfsname(type, typelist)) 342235270Smav return (1); 343235270Smav 344219974Smav hp = NULL; 345219974Smav nfsdirname = NULL; 346219974Smav if (!strcmp(type, "nfs")) { 347219974Smav if ((nfsdirname = strdup(mntfromname)) == NULL) 348219974Smav err(1, "strdup"); 349219974Smav orignfsdirname = nfsdirname; 350219974Smav if ((delimp = strchr(nfsdirname, ':')) != NULL) { 351219974Smav *delimp = '\0'; 352219974Smav hostp = nfsdirname; 353235270Smav if ((hp = gethostbyname(hostp)) == NULL) { 354235270Smav warnx("can't get net id for host"); 355235270Smav } 356235270Smav nfsdirname = delimp + 1; 357235270Smav } 358235270Smav } 359219974Smav /* 360219974Smav * Check if the reverse entrys of the mounttable are really the 361219974Smav * same as the normal ones. 362219974Smav */ 363219974Smav if ((mntfromnamerev = strdup(getmntname(getmntname(mntfromname, 364219974Smav NULL, MNTON, &type, NAME), NULL, MNTFROM, &type, NAME))) == NULL) 365219974Smav err(1, "strdup"); 366219974Smav /* 367219974Smav * Mark the uppermost mount as unmounted. 368219974Smav */ 369219974Smav (void)getmntname(mntfromname, mntonname, NOTHING, &type, MARK); 370219974Smav /* 371219974Smav * If several equal mounts are in the mounttable, check the order 372219974Smav * and warn the user if necessary. 373219974Smav */ 374219974Smav if (strcmp(mntfromnamerev, mntfromname ) != 0 && 375219974Smav strcmp(resolved, mntonname) != 0) { 376219974Smav warnx("cannot umount %s, %s\n " 377219974Smav "is mounted there, umount it first", 378219974Smav mntonname, mntfromnamerev); 379219974Smav 380219974Smav /* call getmntname again to set mntcheck[i] to 0 */ 381219974Smav (void)getmntname(mntfromname, mntonname, 382219974Smav NOTHING, &type, UNMARK); 383219974Smav return (1); 384219974Smav } 385219974Smav free(mntfromnamerev); 386219974Smav /* 387219974Smav * Check if we have to start the rpc-call later. 388219974Smav * If there are still identical nfs-names mounted, 389219974Smav * we skip the rpc-call. Obviously this has to 390219974Smav * happen before unmount(2), but it should happen 391219974Smav * after the previous namecheck. 392219974Smav */ 393219974Smav if (strcmp(type, "nfs") == 0 && getmntname(mntfromname, NULL, NOTHING, 394219974Smav &type, COUNT) != NULL) 395219974Smav do_rpc = 1; 396219974Smav else 397219974Smav do_rpc = 0; 398219974Smav if (!namematch(hp)) 399219974Smav return (1); 400219974Smav if (unmount(mntonname, fflag) != 0 ) { 401219974Smav warn("unmount of %s failed", mntonname); 402219974Smav return (1); 403219974Smav } 404219974Smav if (vflag) 405219974Smav (void)printf("%s: unmount from %s\n", mntfromname, mntonname); 406219974Smav /* 407219974Smav * Report to mountd-server which nfsname 408219974Smav * has been unmounted. 409219974Smav */ 410219974Smav if (hp != NULL && !(fflag & MNT_FORCE) && do_rpc) { 411219974Smav memset(&saddr, 0, sizeof(saddr)); 412219974Smav saddr.sin_family = AF_INET; 413219974Smav saddr.sin_port = 0; 414219974Smav memmove(&saddr.sin_addr, hp->h_addr, 415219974Smav MIN(hp->h_length, sizeof(saddr.sin_addr))); 416219974Smav pertry.tv_sec = 3; 417219974Smav pertry.tv_usec = 0; 418219974Smav so = RPC_ANYSOCK; 419219974Smav if ((clp = clntudp_create(&saddr, 420219974Smav RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) { 421219974Smav clnt_pcreateerror("Cannot MNT PRC"); 422219974Smav return (1); 423219974Smav } 424219974Smav clp->cl_auth = authunix_create_default(); 425219974Smav try.tv_sec = 20; 426219974Smav try.tv_usec = 0; 427219974Smav clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, 428219974Smav nfsdirname, xdr_void, (caddr_t)0, try); 429219974Smav if (clnt_stat != RPC_SUCCESS) { 430219974Smav clnt_perror(clp, "Bad MNT RPC"); 431219974Smav return (1); 432219974Smav } 433219974Smav /* 434219974Smav * Remove the unmounted entry from /var/db/mounttab. 435219974Smav */ 436219974Smav if (read_mtab(mtab)) { 437219974Smav mtab = mtabhead; 438219974Smav clean_mtab(hostp, nfsdirname); 439219974Smav if(!write_mtab()) 440219974Smav warnx("cannot remove entry %s:%s", 441219974Smav hostp, nfsdirname); 442219974Smav free_mtab(); 443219974Smav } 444219974Smav free(orignfsdirname); 445219974Smav auth_destroy(clp->cl_auth); 446219974Smav clnt_destroy(clp); 447219974Smav } 448219974Smav return (0); 449219974Smav} 450219974Smav 451219974Smavchar * 452219974Smavgetmntname(const char *fromname, const char *onname, 453219974Smav mntwhat what, char **type, dowhat mark) 454219974Smav{ 455219974Smav static struct statfs *mntbuf; 456219974Smav static size_t mntsize = 0; 457219974Smav static char *mntcheck = NULL; 458219974Smav static char *mntcount = NULL; 459219974Smav int i, count; 460219974Smav 461219974Smav if (mntsize <= 0) { 462219974Smav if ((mntsize = mntinfo(&mntbuf)) <= 0) 463219974Smav return (NULL); 464219974Smav } 465219974Smav if (mntcheck == NULL) { 466219974Smav if ((mntcheck = calloc(mntsize + 1, sizeof(int))) == NULL || 467219974Smav (mntcount = calloc(mntsize + 1, sizeof(int))) == NULL) 468219974Smav err(1, "calloc"); 469219974Smav } 470219974Smav /* 471219974Smav * We want to get the file systems in the reverse order 472219974Smav * that they were mounted. Mounted and unmounted filesystems 473219974Smav * are marked or unmarked in a table called 'mntcheck'. 474219974Smav * Unmount(const char *dir, int flags) does only take the 475219974Smav * mountpoint as argument, not the destination. If we don't pay 476219974Smav * attention to the order, it can happen that a overlaying 477219974Smav * filesystem get's unmounted instead of the one the user 478219974Smav * has choosen. 479219974Smav */ 480219974Smav switch (mark) { 481219974Smav case NAME: 482219974Smav /* Return only the specific name */ 483219974Smav for (i = mntsize - 1; i >= 0; i--) { 484219974Smav if (fromname != NULL && what == MNTON && 485219974Smav !strcmp(mntbuf[i].f_mntfromname, fromname) && 486219974Smav mntcheck[i] != 1) { 487219974Smav if (type) 488219974Smav *type = mntbuf[i].f_fstypename; 489219974Smav return (mntbuf[i].f_mntonname); 490219974Smav } 491219974Smav if (fromname != NULL && what == MNTFROM && 492219974Smav !strcmp(mntbuf[i].f_mntonname, fromname) && 493219974Smav mntcheck[i] != 1) { 494219974Smav if (type) 495219974Smav *type = mntbuf[i].f_fstypename; 496219974Smav return (mntbuf[i].f_mntfromname); 497219974Smav } 498219974Smav } 499219974Smav return (NULL); 500219974Smav case MARK: 501219974Smav /* Mark current mount with '1' and return name */ 502219974Smav for (i = mntsize - 1; i >= 0; i--) { 503219974Smav if (mntcheck[i] == 0 && 504219974Smav (strcmp(mntbuf[i].f_mntonname, onname) == 0) && 505219974Smav (strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) { 506219974Smav mntcheck[i] = 1; 507219974Smav return (mntbuf[i].f_mntonname); 508219974Smav } 509219974Smav } 510219974Smav return (NULL); 511219974Smav case UNMARK: 512219974Smav /* Unmark current mount with '0' and return name */ 513219974Smav for (i = 0; i < mntsize; i++) { 514219974Smav if (mntcheck[i] == 1 && 515219974Smav (strcmp(mntbuf[i].f_mntonname, onname) == 0) && 516219974Smav (strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) { 517219974Smav mntcheck[i] = 0; 518219974Smav return (mntbuf[i].f_mntonname); 519219974Smav } 520219974Smav } 521219974Smav return (NULL); 522219974Smav case COUNT: 523219974Smav /* Count the equal mntfromnames */ 524219974Smav count = 0; 525219974Smav for (i = mntsize - 1; i >= 0; i--) { 526219974Smav if (strcmp(mntbuf[i].f_mntfromname, fromname) == 0) 527219974Smav count++; 528219974Smav } 529219974Smav /* Mark the already unmounted mounts and return 530219974Smav * mntfromname if count <= 1. Else return NULL. 531219974Smav */ 532219974Smav for (i = mntsize - 1; i >= 0; i--) { 533219974Smav if (strcmp(mntbuf[i].f_mntfromname, fromname) == 0) { 534219974Smav if (mntcount[i] == 1) 535219974Smav count--; 536219974Smav else { 537219974Smav mntcount[i] = 1; 538219974Smav break; 539219974Smav } 540219974Smav } 541219974Smav } 542219974Smav if (count <= 1) 543219974Smav return (mntbuf[i].f_mntonname); 544219974Smav else 545219974Smav return (NULL); 546219974Smav case FREE: 547219974Smav free(mntbuf); 548219974Smav free(mntcheck); 549219974Smav free(mntcount); 550219974Smav return (NULL); 551219974Smav default: 552219974Smav return (NULL); 553219974Smav } 554219974Smav} 555219974Smav 556219974Smavint 557219974Smavnamematch(struct hostent *hp) 558219974Smav{ 559219974Smav char *cp, **np; 560219974Smav 561219974Smav if ((hp == NULL) || (nfshost == NULL)) 562219974Smav return (1); 563219974Smav 564219974Smav if (strcasecmp(nfshost, hp->h_name) == 0) 565219974Smav return (1); 566219974Smav 567219974Smav if ((cp = strchr(hp->h_name, '.')) != NULL) { 568219974Smav *cp = '\0'; 569219974Smav if (strcasecmp(nfshost, hp->h_name) == 0) 570219974Smav return (1); 571219974Smav } 572219974Smav for (np = hp->h_aliases; *np; np++) { 573219974Smav if (strcasecmp(nfshost, *np) == 0) 574219974Smav return (1); 575219974Smav if ((cp = strchr(*np, '.')) != NULL) { 576219974Smav *cp = '\0'; 577219974Smav if (strcasecmp(nfshost, *np) == 0) 578219974Smav return (1); 579219974Smav } 580219974Smav } 581219974Smav return (0); 582219974Smav} 583219974Smav 584219974Smavvoid 585219974Smavcheckmntlist(char *name, char **fromname, char **onname, char **type) 586219974Smav{ 587219974Smav 588219974Smav *fromname = getmntname(name, NULL, MNTFROM, type, NAME); 589219974Smav if (*fromname == NULL) { 590219974Smav *onname = getmntname(name, NULL, MNTON, type, NAME); 591219974Smav if (*onname != NULL) 592219974Smav *fromname = name; 593219974Smav } else 594219974Smav *onname = name; 595219974Smav} 596219974Smav 597219974Smavsize_t 598219974Smavmntinfo(struct statfs **mntbuf) 599219974Smav{ 600219974Smav static struct statfs *origbuf; 601219974Smav size_t bufsize; 602219974Smav int mntsize; 603219974Smav 604219974Smav mntsize = getfsstat(NULL, 0, MNT_NOWAIT); 605219974Smav if (mntsize <= 0) 606219974Smav return (0); 607219974Smav bufsize = (mntsize + 1) * sizeof(struct statfs); 608219974Smav if ((origbuf = malloc(bufsize)) == NULL) 609219974Smav err(1, "malloc"); 610219974Smav mntsize = getfsstat(origbuf, (long)bufsize, MNT_NOWAIT); 611219974Smav *mntbuf = origbuf; 612219974Smav return (mntsize); 613219974Smav} 614219974Smav 615219974Smavchar * 616219974Smavgetrealname(char *name, char *realname) 617219974Smav{ 618219974Smav char *dirname; 619219974Smav int havedir; 620219974Smav size_t baselen; 621219974Smav size_t dirlen; 622219974Smav 623219974Smav dirname = '\0'; 624219974Smav havedir = 0; 625219974Smav if (*name == '/') { 626219974Smav if (ISDOT(name + 1) || ISDOTDOT(name + 1)) 627219974Smav strcpy(realname, "/"); 628219974Smav else { 629219974Smav if ((dirname = strrchr(name + 1, '/')) == NULL) 630219974Smav snprintf(realname, MAXPATHLEN, "%s", name); 631219974Smav else 632219974Smav havedir = 1; 633219974Smav } 634219974Smav } else { 635219974Smav if (ISDOT(name) || ISDOTDOT(name)) 636219974Smav (void)realpath(name, realname); 637219974Smav else { 638219974Smav if ((dirname = strrchr(name, '/')) == NULL) { 639219974Smav if ((realpath(name, realname)) == NULL) 640219974Smav return (NULL); 641219974Smav } else 642219974Smav havedir = 1; 643219974Smav } 644219974Smav } 645219974Smav if (havedir) { 646219974Smav *dirname++ = '\0'; 647219974Smav if (ISDOT(dirname)) { 648219974Smav *dirname = '\0'; 649219974Smav if ((realpath(name, realname)) == NULL) 650219974Smav return (NULL); 651219974Smav } else if (ISDOTDOT(dirname)) { 652219974Smav *--dirname = '/'; 653219974Smav if ((realpath(name, realname)) == NULL) 654219974Smav return (NULL); 655219974Smav } else { 656219974Smav if ((realpath(name, realname)) == NULL) 657219974Smav return (NULL); 658219974Smav baselen = strlen(realname); 659219974Smav dirlen = strlen(dirname); 660219974Smav if (baselen + dirlen + 1 > MAXPATHLEN) 661219974Smav return (NULL); 662219974Smav if (realname[1] == '\0') { 663219974Smav memmove(realname + 1, dirname, dirlen); 664219974Smav realname[dirlen + 1] = '\0'; 665219974Smav } else { 666219974Smav realname[baselen] = '/'; 667219974Smav memmove(realname + baselen + 1, 668219974Smav dirname, dirlen); 669219974Smav realname[baselen + dirlen + 1] = '\0'; 670219974Smav } 671219974Smav } 672219974Smav } 673219974Smav return (realname); 674219974Smav} 675219974Smav 676219974Smav/* 677219974Smav * xdr routines for mount rpc's 678219974Smav */ 679219974Smavint 680219974Smavxdr_dir(XDR *xdrsp, char *dirp) 681219974Smav{ 682219974Smav 683219974Smav return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 684219974Smav} 685219974Smav 686219974Smavvoid 687219974Smavusage() 688219974Smav{ 689219974Smav 690219974Smav (void)fprintf(stderr, "%s\n%s\n", 691219974Smav "usage: umount [-fv] special | node", 692219974Smav " umount -a | -A [-fv] [-h host] [-t type]"); 693219974Smav exit(1); 694219974Smav} 695219974Smav