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