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