1: /* 2: * Copyright (c) 1980, 1989, 1993, 1994 3: * The Regents of the University of California. All rights reserved. 4: * 5: * Redistribution and use in source and binary forms, with or without 6: * modification, are permitted provided that the following conditions 7: * are met: 8: * 1. Redistributions of source code must retain the above copyright 9: * notice, this list of conditions and the following disclaimer. 10: * 2. Redistributions in binary form must reproduce the above copyright 11: * notice, this list of conditions and the following disclaimer in the 12: * documentation and/or other materials provided with the distribution. 13: * 3. All advertising materials mentioning features or use of this software 14: * must display the following acknowledgement: 15: * This product includes software developed by the University of 16: * California, Berkeley and its contributors. 17: * 4. Neither the name of the University nor the names of its contributors 18: * may be used to endorse or promote products derived from this software 19: * without specific prior written permission. 20: * 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31: * SUCH DAMAGE. 32: */ 33: 34: #if !defined(lint) && defined(DOSCCS) 35: static char copyright[] = 36: "@(#) Copyright (c) 1980, 1989, 1993, 1994\n\ 37: The Regents of the University of California. All rights reserved.\n"; 38: 39: static char sccsid[] = "@(#)mount.c 8.19.4 (2.11BSD) 1997/6/29"; 40: #endif /* not lint */ 41: 42: #include <sys/param.h> 43: #include <sys/mount.h> 44: #include <sys/wait.h> 45: 46: #include <errno.h> 47: #include <fstab.h> 48: #include <signal.h> 49: #include <stdio.h> 50: #include <stdlib.h> 51: #include <string.h> 52: #include <unistd.h> 53: 54: #include "pathnames.h" 55: 56: int debug, verbose, skipvfs, mountrw; 57: 58: int badvfsname(); 59: int badvfstype(); 60: char *catopt(); 61: struct statfs *getmntpt(); 62: char **makevfslist(); 63: void mangle(); 64: int mountfs(); 65: void prmount(); 66: void usage(); 67: 68: /* From mount_ufs.c. */ 69: int mount_ufs(); 70: 71: /* Map from mount otions to printable formats. */ 72: static struct opt { 73: int o_opt; 74: char *o_name; 75: } optnames[] = { 76: { MNT_ASYNC, "asynchronous" }, 77: { MNT_NOATIME, "noaccesstime" }, 78: { MNT_NODEV, "nodev" }, 79: { MNT_NOEXEC, "noexec" }, 80: { MNT_NOSUID, "nosuid" }, 81: { MNT_QUOTA, "with quotas" }, 82: { MNT_RDONLY, "read-only" }, 83: { MNT_SYNCHRONOUS, "synchronous" }, 84: { NULL } 85: }; 86: 87: int 88: main(argc, argv) 89: int argc; 90: register char *argv[]; 91: { 92: char *mntonname, **vfslist, *vfstype; 93: register struct fstab *fs; 94: struct statfs *mntbuf; 95: int all, ch, i, init_flags, mntsize, rval; 96: char *options, *na; 97: 98: all = init_flags = 0; 99: options = NULL; 100: vfslist = NULL; 101: vfstype = "ufs"; 102: while ((ch = getopt(argc, argv, "adfo:rwt:uv")) != EOF) 103: switch (ch) { 104: case 'a': 105: all = 1; 106: break; 107: case 'd': 108: debug = 1; 109: break; 110: case 'f': 111: #ifdef notnow 112: init_flags |= MNT_FORCE; 113: #endif 114: break; 115: case 'o': 116: if (*optarg) 117: options = catopt(options, optarg); 118: break; 119: case 'r': 120: init_flags |= MNT_RDONLY; 121: mountrw = 0; 122: break; 123: case 't': 124: if (vfslist != NULL) 125: errx(1, "only one -t option may be specified."); 126: vfslist = makevfslist(optarg); 127: vfstype = optarg; 128: break; 129: case 'u': 130: init_flags |= MNT_UPDATE; 131: break; 132: case 'v': 133: verbose = 1; 134: break; 135: case 'w': 136: init_flags &= ~MNT_RDONLY; 137: mountrw = 1; 138: break; 139: case '?': 140: default: 141: usage(); 142: /* NOTREACHED */ 143: } 144: argc -= optind; 145: argv += optind; 146: 147: #define BADTYPE(type) \ 148: (strcmp(type, FSTAB_RO) && \ 149: strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 150: 151: rval = 0; 152: switch (argc) { 153: case 0: 154: if (all) 155: while ((fs = getfsent()) != NULL) { 156: if (BADTYPE(fs->fs_type)) 157: continue; 158: /* 159: * Check to see if "na" is one of the options, 160: * if so, don't mount it. 161: */ 162: if (fs->fs_mntops && 163: (na = strstr(fs->fs_mntops, "na")) && 164: ((na = fs->fs_mntops) || na[-1] == ',') && 165: (na[2] == ',' || na[2] == '\0')) { 166: continue; 167: } 168: if (badvfsname(fs->fs_vfstype, vfslist)) 169: continue; 170: if (mountfs(fs->fs_vfstype, fs->fs_spec, 171: fs->fs_file, init_flags, options, 172: fs->fs_mntops)) 173: rval = 1; 174: } 175: else { 176: if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 177: err(1, "getmntinfo"); 178: for (i = 0; i < mntsize; i++) { 179: if (badvfstype(mntbuf[i].f_type, vfslist)) 180: continue; 181: prmount(mntbuf[i].f_mntfromname, 182: mntbuf[i].f_mntonname, mntbuf[i].f_flags); 183: } 184: } 185: exit(rval); 186: case 1: 187: if (vfslist != NULL) 188: usage(); 189: 190: if (init_flags & MNT_UPDATE) { 191: if ((mntbuf = getmntpt(*argv)) == NULL) 192: errx(1, 193: "unknown special file or file system %s.", 194: *argv); 195: if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL) 196: errx(1, "can't find fstab entry for %s.", 197: *argv); 198: /* If it's an update, ignore the fstab file options. */ 199: fs->fs_mntops = NULL; 200: mntonname = mntbuf->f_mntonname; 201: } else { 202: if ((fs = getfsfile(*argv)) == NULL && 203: (fs = getfsspec(*argv)) == NULL) 204: errx(1, 205: "%s: unknown special file or file system.", 206: *argv); 207: if (BADTYPE(fs->fs_type)) 208: errx(1, "%s has unknown file system type.", 209: *argv); 210: mntonname = fs->fs_file; 211: } 212: rval = mountfs(fs->fs_vfstype, fs->fs_spec, 213: mntonname, init_flags, options, fs->fs_mntops); 214: break; 215: case 2: 216: /* 217: * If -t flag has not been specified, and spec contains either 218: * a ':' or a '@' then assume that an NFS filesystem is being 219: * specified ala Sun. Since 2BSD does not support nfs an 220: * error is declared here rather than from mountfs(). 221: */ 222: if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL) 223: err(1, "nfs not supported"); 224: rval = mountfs(vfstype, 225: argv[0], argv[1], init_flags, options, NULL); 226: break; 227: default: 228: usage(); 229: /* NOTREACHED */ 230: } 231: 232: exit(rval); 233: } 234: 235: int 236: mountfs(vfstype, spec, name, flags, options, mntopts) 237: char *vfstype, *spec, *name, *options, *mntopts; 238: int flags; 239: { 240: /* List of directories containing mount_xxx subcommands. */ 241: static char *edirs[] = { 242: _PATH_SBIN, 243: _PATH_USRSBIN, 244: NULL 245: }; 246: char *argv[100], **edir; 247: struct statfs sf; 248: pid_t pid; 249: int argc, i; 250: union wait status; 251: char *optbuf, execname[MAXPATHLEN + 1]; 252: 253: if (options == NULL) { 254: if (mntopts == NULL || *mntopts == '\0') 255: options = "rw"; 256: else 257: options = mntopts; 258: mntopts = ""; 259: if (debug) 260: printf("options: %s\n", options); 261: } 262: optbuf = catopt(mntopts ? strdup(mntopts) : 0, options); 263: 264: if (strcmp(name, "/") == 0) 265: flags |= MNT_UPDATE; 266: #ifdef notnow 267: if (flags & MNT_FORCE) 268: optbuf = catopt(optbuf, "force"); 269: #endif 270: if (flags & MNT_RDONLY) 271: optbuf = catopt(optbuf, "ro"); 272: if (mountrw) 273: optbuf = catopt(optbuf, "rw"); 274: if (flags & MNT_UPDATE) 275: optbuf = catopt(optbuf, "update"); 276: 277: argc = 0; 278: argv[argc++] = vfstype; 279: mangle(optbuf, &argc, argv); 280: argv[argc++] = spec; 281: argv[argc++] = name; 282: argv[argc] = NULL; 283: 284: if (debug) { 285: (void)printf("exec: mount_%s", vfstype); 286: for (i = 1; i < argc; i++) 287: (void)printf(" %s", argv[i]); 288: (void)printf("\n"); 289: return (0); 290: } 291: 292: switch (pid = vfork()) { 293: case -1: /* Error. */ 294: warn("vfork"); 295: free(optbuf); 296: return (1); 297: case 0: /* Child. */ 298: if (strcmp(vfstype, "ufs") == 0) 299: _exit(mount_ufs(argc, (char **) argv)); 300: 301: /* Go find an executable. */ 302: edir = edirs; 303: do { 304: (void)sprintf(execname, "%s/mount_%s", *edir, vfstype); 305: execv(execname, (char **)argv); 306: if (errno != ENOENT) 307: warn("exec %s for %s", execname, name); 308: } while (*++edir != NULL); 309: 310: if (errno == ENOENT) 311: warn("exec %s for %s", execname, name); 312: _exit(1); 313: /* NOTREACHED */ 314: default: /* Parent. */ 315: free(optbuf); 316: 317: if (waitpid(pid, &status, 0) < 0) { 318: warn("waitpid"); 319: return (1); 320: } 321: 322: if (WIFEXITED(status)) { 323: if (WEXITSTATUS(status) != 0) 324: return (WEXITSTATUS(status)); 325: } else if (WIFSIGNALED(status)) { 326: warnx("%s: %s", name, sys_siglist[status.w_termsig]); 327: return (1); 328: } 329: 330: if (verbose) { 331: if (statfs(name, &sf) < 0) { 332: warn("%s", name); 333: return (1); 334: } 335: prmount(sf.f_mntfromname, sf.f_mntonname, sf.f_flags); 336: } 337: break; 338: } 339: 340: return (0); 341: } 342: 343: void 344: prmount(spec, name, flags) 345: char *spec, *name; 346: int flags; 347: { 348: register struct opt *o; 349: register int f; 350: 351: (void)printf("%s on %s", spec, name); 352: 353: flags &= MNT_VISFLAGMASK; 354: for (f = 0, o = optnames; flags && o->o_opt; o++) 355: if (flags & o->o_opt) { 356: (void)printf("%s%s", !f++ ? " (" : ", ", o->o_name); 357: flags &= ~o->o_opt; 358: } 359: (void)printf(f ? ")\n" : "\n"); 360: } 361: 362: struct statfs * 363: getmntpt(name) 364: char *name; 365: { 366: struct statfs *mntbuf; 367: register int i, mntsize; 368: 369: mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 370: for (i = 0; i < mntsize; i++) 371: if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 372: strcmp(mntbuf[i].f_mntonname, name) == 0) 373: return (&mntbuf[i]); 374: return (NULL); 375: } 376: 377: int 378: badvfsname(vfsname, vfslist) 379: char *vfsname; 380: register char **vfslist; 381: { 382: 383: if (vfslist == NULL) 384: return (0); 385: while (*vfslist != NULL) { 386: if (strcmp(vfsname, *vfslist) == 0) 387: return (skipvfs); 388: ++vfslist; 389: } 390: return (!skipvfs); 391: } 392: 393: int 394: badvfstype(vfstype, vfslist) 395: int vfstype; 396: register char **vfslist; 397: { 398: static char *vfsnames[] = INITMOUNTNAMES; 399: 400: if ((vfstype < 0) || (vfstype > MOUNT_MAXTYPE)) 401: return (0); 402: 403: return (badvfsname(vfsnames[vfstype], vfslist)); 404: } 405: 406: char ** 407: makevfslist(fslist) 408: char *fslist; 409: { 410: register char **av; 411: int i; 412: register char *nextcp; 413: 414: if (fslist == NULL) 415: return (NULL); 416: if (fslist[0] == 'n' && fslist[1] == 'o') { 417: fslist += 2; 418: skipvfs = 1; 419: } 420: for (i = 0, nextcp = fslist; *nextcp; nextcp++) 421: if (*nextcp == ',') 422: i++; 423: if ((av = (char **)malloc((size_t)(i + 2) * sizeof(char *))) == NULL) { 424: warn(NULL); 425: return (NULL); 426: } 427: nextcp = fslist; 428: i = 0; 429: av[i++] = nextcp; 430: while ((nextcp = strchr(nextcp, ',')) != NULL) { 431: *nextcp++ = '\0'; 432: av[i++] = nextcp; 433: } 434: av[i++] = NULL; 435: return (av); 436: } 437: 438: char * 439: catopt(s0, s1) 440: char *s0; 441: char *s1; 442: { 443: size_t i; 444: char *cp; 445: 446: if (s0 && *s0) { 447: i = strlen(s0) + strlen(s1) + 1 + 1; 448: if ((cp = (char *)malloc(i)) == NULL) 449: err(1, NULL); 450: (void)sprintf(cp, "%s,%s", s0, s1); 451: } else 452: cp = strdup(s1); 453: 454: if (s0) 455: free(s0); 456: return (cp); 457: } 458: 459: void 460: mangle(options, argcp, argv) 461: char *options; 462: int *argcp; 463: register char **argv; 464: { 465: register char *p; 466: char *s; 467: register int argc; 468: 469: argc = *argcp; 470: for (s = options; (p = strsep(&s, ",")) != NULL;) 471: if (*p != '\0') 472: if (*p == '-') { 473: argv[argc++] = p; 474: p = strchr(p, '='); 475: if (p) { 476: *p = '\0'; 477: argv[argc++] = p+1; 478: } 479: } else { 480: argv[argc++] = "-o"; 481: argv[argc++] = p; 482: } 483: 484: *argcp = argc; 485: } 486: 487: void 488: usage() 489: { 490: 491: (void)fprintf(stderr, 492: "usage: mount %s %s\n mount %s\n mount %s\n", 493: "[-dfruvw] [-o options] [-t ufs | external_type]", 494: "special node", 495: "[-adfruvw] [-t ufs | external_type]", 496: "[-dfruvw] special | node"); 497: exit(1); 498: }