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