1 /* 2 * Copyright (c) 1980, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1980, 1989, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)mount.c 8.13 (Berkeley) 02/20/94"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/wait.h> 20 #include <sys/mount.h> 21 22 #include <err.h> 23 #include <errno.h> 24 #include <fstab.h> 25 #include <signal.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "pathnames.h" 32 33 34 int debug, force, verbose, mnttype, skipvfs; 35 char *mntname; 36 37 int badvfsname __P((char *, char **)); 38 int badvfstype __P((int, char **)); 39 int getexecopts __P((char *, char **)); 40 struct statfs 41 *getmntpt __P((char *)); 42 int getmnttype __P((char *)); 43 void getstdopts __P((char *, int *)); 44 void getufsopts __P((char *, int *)); 45 char **makevfslist __P((char *)); 46 int mountfs __P((char *, char *, int, char *, char *, char *)); 47 void prmount __P((char *, char *, int)); 48 void usage __P((void)); 49 50 int 51 main(argc, argv) 52 int argc; 53 char *argv[]; 54 { 55 struct fstab *fs; 56 struct statfs *mntbuf; 57 FILE *pidfile; 58 long mntsize; 59 int all, ch, i, ret, rval, updateflg; 60 char *cp, *type, *options, **vfslist; 61 62 mntname = "ufs"; 63 mnttype = MOUNT_UFS; 64 65 all = updateflg = 0; 66 options = type = NULL; 67 vfslist = NULL; 68 while ((ch = getopt(argc, argv, "adfo:rwt:uv")) != EOF) 69 switch(ch) { 70 case 'a': 71 all = 1; 72 break; 73 case 'd': 74 debug = 1; 75 break; 76 case 'f': 77 force = 1; 78 break; 79 case 'o': 80 options = optarg; 81 break; 82 case 'r': 83 type = FSTAB_RO; 84 break; 85 case 't': 86 vfslist = makevfslist(optarg); 87 mnttype = getmnttype(optarg); 88 break; 89 case 'u': 90 updateflg = MNT_UPDATE; 91 break; 92 case 'v': 93 verbose = 1; 94 break; 95 case 'w': 96 type = FSTAB_RW; 97 break; 98 case '?': 99 default: 100 usage(); 101 /* NOTREACHED */ 102 } 103 argc -= optind; 104 argv += optind; 105 106 #define BADTYPE(type) \ 107 (strcmp(type, FSTAB_RO) && \ 108 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 109 110 if (all) { 111 rval = 0; 112 while ((fs = getfsent()) != NULL) { 113 if (BADTYPE(fs->fs_type)) 114 continue; 115 if (badvfsname(fs->fs_vfstype, vfslist)) 116 continue; 117 /* `/' is special, it's always mounted. */ 118 mnttype = getmnttype(fs->fs_vfstype); 119 rval |= mountfs(fs->fs_spec, fs->fs_file, updateflg, 120 type, options, fs->fs_mntops); 121 } 122 exit(rval); 123 } 124 125 if (argc == 0) { 126 if (verbose || debug || type) 127 usage(); 128 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 129 err(1, "getmntinfo"); 130 for (i = 0; i < mntsize; i++) { 131 if (badvfstype(mntbuf[i].f_type, vfslist)) 132 continue; 133 prmount(mntbuf[i].f_mntfromname, 134 mntbuf[i].f_mntonname, mntbuf[i].f_flags); 135 } 136 exit(0); 137 } 138 139 if (argc == 1 && vfslist != NULL) 140 usage(); 141 142 if (argc == 1 && updateflg) { 143 if ((mntbuf = getmntpt(*argv)) == NULL) 144 errx(1, 145 "unknown special file or file system %s.", *argv); 146 mnttype = mntbuf->f_type; 147 if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL) 148 errx(1, "can't find fstab entry for %s.", *argv); 149 mntname = fs->fs_vfstype; 150 151 /* 152 * Default type to fstab version if none specified on the 153 * command line. 154 */ 155 if (type == NULL) 156 type = fs->fs_type; 157 158 /* 159 * Default options to fstab version if none specified on the 160 * command line. 161 */ 162 if (options == NULL) 163 options = fs->fs_mntops; 164 else { 165 /* 166 * Concat the two strings with the command line 167 * options last so that they will override the 168 * fstab options. 169 */ 170 i = strlen(fs->fs_mntops) + strlen(options) + 2; 171 if ((cp = malloc((size_t)i)) == NULL) 172 err(1, NULL); 173 (void)snprintf(cp, i, "%s,%s", fs->fs_mntops, options); 174 options = cp; 175 } 176 ret = mountfs(fs->fs_spec, 177 mntbuf->f_mntonname, updateflg, type, options, NULL); 178 } else if (argc == 1) { 179 if ((fs = getfsfile(*argv)) == NULL && 180 (fs = getfsspec(*argv)) == NULL) 181 errx(1, 182 "unknown special file or file system %s.", *argv); 183 if (BADTYPE(fs->fs_type)) 184 errx(1, "%s has unknown file system type.", *argv); 185 mnttype = getmnttype(fs->fs_vfstype); 186 ret = mountfs(fs->fs_spec, 187 fs->fs_file, updateflg, type, options, fs->fs_mntops); 188 } else if (argc != 2) { 189 usage(); 190 ret = 1; 191 } else { 192 /* 193 * If -t flag has not been specified, and spec contains either 194 * a ':' or a '@' then assume that an NFS filesystem is being 195 * specified ala Sun. 196 */ 197 if (vfslist == NULL && 198 (strchr(argv[0], ':') || strchr(argv[0], '@'))) { 199 mnttype = MOUNT_NFS; 200 mntname = "nfs"; 201 } 202 ret = mountfs(argv[0], argv[1], updateflg, type, options, NULL); 203 } 204 /* 205 * If the mount succeeded, and we're running as root, 206 * then tell mountd the good news. 207 */ 208 if ((ret == 0) && (getuid() == 0)) { 209 if ((pidfile = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 210 pid_t pid = 0; 211 (void)fscanf(pidfile, "%ld", &pid); 212 (void)fclose(pidfile); 213 if (pid > 0 && kill(pid, SIGHUP)) 214 err(1, "signal mountd"); 215 } 216 } 217 218 exit(ret); 219 } 220 221 int 222 mountfs(spec, name, flags, type, options, mntopts) 223 char *spec, *name, *type, *options, *mntopts; 224 int flags; 225 { 226 struct ufs_args args; 227 pid_t pid; 228 int argc, i, status; 229 char *argp, *argv[50]; 230 char execname[MAXPATHLEN + 1], flagval[12], mntpath[MAXPATHLEN]; 231 232 if (mntopts) 233 getstdopts(mntopts, &flags); 234 if (options) 235 getstdopts(options, &flags); 236 if (type) 237 getstdopts(type, &flags); 238 if (force) 239 flags |= MNT_FORCE; 240 241 if (realpath(name, mntpath) == 0) { 242 warn("%s", mntpath); 243 return (1); 244 } 245 246 name = mntpath; 247 248 if (strcmp(name, "/") == 0) 249 flags |= MNT_UPDATE; 250 251 switch (mnttype) { 252 case MOUNT_UFS: 253 if (mntopts) 254 getufsopts(mntopts, &flags); 255 if (options) 256 getufsopts(options, &flags); 257 args.fspec = spec; 258 #define DEFAULT_ROOTUID -2 259 args.export.ex_root = DEFAULT_ROOTUID; 260 if (flags & MNT_RDONLY) 261 args.export.ex_flags = MNT_EXRDONLY; 262 else 263 args.export.ex_flags = 0; 264 argp = (caddr_t)&args; 265 break; 266 case MOUNT_MFS: 267 case MOUNT_NFS: 268 default: 269 argv[0] = mntname; 270 argc = 1; 271 if (flags) { 272 argv[argc++] = "-F"; 273 (void)snprintf(flagval, sizeof(flagval), "%d", flags); 274 argv[argc++] = flagval; 275 } 276 if (mntopts) 277 argc += getexecopts(mntopts, &argv[argc]); 278 if (options) 279 argc += getexecopts(options, &argv[argc]); 280 argv[argc++] = spec; 281 argv[argc++] = name; 282 argv[argc++] = NULL; 283 snprintf(execname, sizeof(execname), 284 "%s/mount_%s", _PATH_EXECDIR, mntname); 285 if (verbose) { 286 (void)printf("exec: %s", execname); 287 for (i = 1; i < argc - 1; i++) 288 (void)printf(" %s", argv[i]); 289 (void)printf("\n"); 290 } 291 if (debug) 292 break; 293 if (pid = vfork()) { 294 if (pid == -1) { 295 warn("vfork starting file system"); 296 return (1); 297 } 298 if (waitpid(pid, &status, 0) != -1 && 299 WIFEXITED(status) && 300 WEXITSTATUS(status) != 0) 301 return (WEXITSTATUS(status)); 302 spec = mntname; 303 goto out; 304 } 305 execv(execname, argv); 306 err(1, "cannot exec %s for %s", execname, name); 307 /* NOTREACHED */ 308 309 } 310 if (!debug && mount(mnttype, name, flags, argp)) { 311 (void)fprintf(stderr, "%s on %s: ", spec, name); 312 switch (errno) { 313 case EMFILE: 314 (void)fprintf(stderr, "Mount table full.\n"); 315 break; 316 case EINVAL: 317 if (flags & MNT_UPDATE) 318 (void)fprintf(stderr, "Specified device %s\n", 319 "does not match mounted device"); 320 else if (mnttype == MOUNT_UFS) 321 (void)fprintf(stderr, "Bogus super block\n"); 322 else 323 perror(NULL); 324 break; 325 default: 326 perror(NULL); 327 break; 328 } 329 return (1); 330 } 331 332 out: if (verbose) 333 prmount(spec, name, flags); 334 return (0); 335 } 336 337 void 338 prmount(spec, name, flags) 339 char *spec, *name; 340 int flags; 341 { 342 int first; 343 344 (void)printf("%s on %s", spec, name); 345 if (!(flags & MNT_VISFLAGMASK)) { 346 (void)printf("\n"); 347 return; 348 } 349 first = 0; 350 #define PR(msg) (void)printf("%s%s", !first++ ? " (" : ", ", msg) 351 if (flags & MNT_RDONLY) 352 PR("read-only"); 353 if (flags & MNT_NOEXEC) 354 PR("noexec"); 355 if (flags & MNT_NOSUID) 356 PR("nosuid"); 357 if (flags & MNT_NODEV) 358 PR("nodev"); 359 if (flags & MNT_SYNCHRONOUS) 360 PR("synchronous"); 361 if (flags & MNT_ASYNC) 362 PR("asynchronous"); 363 if (flags & MNT_QUOTA) 364 PR("with quotas"); 365 if (flags & MNT_LOCAL) 366 PR("local"); 367 if (flags & MNT_USER) 368 PR("user mount"); 369 if (flags & MNT_UNION) 370 PR("union"); 371 if (flags & MNT_EXPORTED) 372 PR("NFS exported"); 373 (void)printf(")\n"); 374 } 375 376 int 377 getmnttype(fstype) 378 char *fstype; 379 { 380 381 mntname = fstype; 382 return (strcmp(fstype, "ufs") == 0 ? MOUNT_UFS : 0); 383 } 384 385 void 386 getstdopts(options, flagp) 387 char *options; 388 int *flagp; 389 { 390 int negative; 391 char *opt, optbuf[BUFSIZ]; 392 393 (void)strcpy(optbuf, options); 394 for (opt = strtok(optbuf, ","); opt; opt = strtok(NULL, ",")) { 395 if (opt[0] == '-') 396 continue; 397 if (opt[0] == 'n' && opt[1] == 'o') { 398 negative++; 399 opt += 2; 400 } else 401 negative = 0; 402 if (!negative && !strcasecmp(opt, FSTAB_RO)) { 403 *flagp |= MNT_RDONLY; 404 continue; 405 } 406 if (!negative && !strcasecmp(opt, FSTAB_RW)) { 407 *flagp &= ~MNT_RDONLY; 408 continue; 409 } 410 if (!strcasecmp(opt, "exec")) { 411 if (negative) 412 *flagp |= MNT_NOEXEC; 413 else 414 *flagp &= ~MNT_NOEXEC; 415 continue; 416 } 417 if (!strcasecmp(opt, "suid")) { 418 if (negative) 419 *flagp |= MNT_NOSUID; 420 else 421 *flagp &= ~MNT_NOSUID; 422 continue; 423 } 424 if (!strcasecmp(opt, "dev")) { 425 if (negative) 426 *flagp |= MNT_NODEV; 427 else 428 *flagp &= ~MNT_NODEV; 429 continue; 430 } 431 if (!strcasecmp(opt, "synchronous")) { 432 if (!negative) 433 *flagp |= MNT_SYNCHRONOUS; 434 else 435 *flagp &= ~MNT_SYNCHRONOUS; 436 continue; 437 } 438 if (!strcasecmp(opt, "asynchronous")) { 439 if (!negative) 440 *flagp |= MNT_ASYNC; 441 else 442 *flagp &= ~MNT_ASYNC; 443 continue; 444 } 445 if (!strcasecmp(opt, "union")) { 446 if (!negative) 447 *flagp |= MNT_UNION; 448 else 449 *flagp &= ~MNT_UNION; 450 continue; 451 } 452 (void)fprintf(stderr, "mount: %s: unknown option\n", opt); 453 } 454 } 455 456 /* ARGSUSED */ 457 void 458 getufsopts(options, flagp) 459 char *options; 460 int *flagp; 461 { 462 463 return; 464 } 465 466 int 467 getexecopts(options, argv) 468 char *options, **argv; 469 { 470 int argc; 471 char *opt; 472 473 argc = 0; 474 for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) { 475 if (opt[0] != '-') 476 continue; 477 argv[argc++] = opt; 478 if (opt[2] == '\0' || opt[2] != '=') 479 continue; 480 opt[2] = '\0'; 481 argv[argc++] = &opt[3]; 482 } 483 return (argc); 484 } 485 486 struct statfs * 487 getmntpt(name) 488 char *name; 489 { 490 struct statfs *mntbuf; 491 long i, mntsize; 492 493 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 494 for (i = 0; i < mntsize; i++) { 495 if (!strcmp(mntbuf[i].f_mntfromname, name) || 496 !strcmp(mntbuf[i].f_mntonname, name)) 497 return (&mntbuf[i]); 498 } 499 return (NULL); 500 } 501 502 int 503 badvfstype(vfstype, vfslist) 504 int vfstype; 505 char **vfslist; 506 { 507 508 if (vfslist == NULL) 509 return (0); 510 while (*vfslist != NULL) { 511 if (vfstype == getmnttype(*vfslist)) 512 return (skipvfs); 513 vfslist++; 514 } 515 return (!skipvfs); 516 } 517 518 int 519 badvfsname(vfsname, vfslist) 520 char *vfsname; 521 char **vfslist; 522 { 523 524 if (vfslist == NULL) 525 return (0); 526 while (*vfslist != NULL) { 527 if (strcmp(vfsname, *vfslist) == 0) 528 return (skipvfs); 529 vfslist++; 530 } 531 return (!skipvfs); 532 } 533 534 char ** 535 makevfslist(fslist) 536 char *fslist; 537 { 538 int i; 539 char **av, *nextcp; 540 541 if (fslist == NULL) 542 return (NULL); 543 if (fslist[0] == 'n' && fslist[1] == 'o') { 544 fslist += 2; 545 skipvfs = 1; 546 } 547 for (i = 0, nextcp = fslist; *nextcp; nextcp++) 548 if (*nextcp == ',') 549 i++; 550 av = malloc((size_t)(i + 2) * sizeof(char *)); 551 if (av == NULL) 552 return (NULL); 553 nextcp = fslist; 554 i = 0; 555 av[i++] = nextcp; 556 while ((nextcp = index(nextcp, ',')) != NULL) { 557 *nextcp++ = '\0'; 558 av[i++] = nextcp; 559 } 560 av[i++] = NULL; 561 return (av); 562 } 563 564 void 565 usage() 566 { 567 568 (void)fprintf(stderr, 569 "usage: %s %s\n %s\n %s\n", 570 "mount [-dfruvw] [-t ufs | external_type]", 571 "[-o options] special node", 572 "mount [-adfruvw] [-t ufs | external_type]", 573 "mount [-dfruvw] special | node"); 574 exit(1); 575 } 576