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.11 (Berkeley) 02/17/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, pid, 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 if ((pidfile = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 205 pid = 0; 206 (void)fscanf(pidfile, "%ld", &pid); 207 (void)fclose(pidfile); 208 if (pid > 0 && kill(pid, SIGHUP)) 209 err(1, "signal mountd"); 210 } 211 212 exit(ret); 213 } 214 215 int 216 mountfs(spec, name, flags, type, options, mntopts) 217 char *spec, *name, *type, *options, *mntopts; 218 int flags; 219 { 220 struct ufs_args args; 221 pid_t pid; 222 int argc, i, status; 223 char *argp, *argv[50]; 224 char execname[MAXPATHLEN + 1], flagval[12], mntpath[MAXPATHLEN]; 225 226 if (mntopts) 227 getstdopts(mntopts, &flags); 228 if (options) 229 getstdopts(options, &flags); 230 if (type) 231 getstdopts(type, &flags); 232 if (force) 233 flags |= MNT_FORCE; 234 235 if (realpath(name, mntpath) == 0) { 236 warn("%s", mntpath); 237 return (1); 238 } 239 240 name = mntpath; 241 242 if (strcmp(name, "/") == 0) 243 flags |= MNT_UPDATE; 244 245 switch (mnttype) { 246 case MOUNT_UFS: 247 if (mntopts) 248 getufsopts(mntopts, &flags); 249 if (options) 250 getufsopts(options, &flags); 251 args.fspec = spec; 252 #define DEFAULT_ROOTUID -2 253 args.export.ex_root = DEFAULT_ROOTUID; 254 if (flags & MNT_RDONLY) 255 args.export.ex_flags = MNT_EXRDONLY; 256 else 257 args.export.ex_flags = 0; 258 argp = (caddr_t)&args; 259 break; 260 case MOUNT_MFS: 261 case MOUNT_NFS: 262 default: 263 argv[0] = mntname; 264 argc = 1; 265 if (flags) { 266 argv[argc++] = "-F"; 267 (void)snprintf(flagval, sizeof(flagval), "%d", flags); 268 argv[argc++] = flagval; 269 } 270 if (mntopts) 271 argc += getexecopts(mntopts, &argv[argc]); 272 if (options) 273 argc += getexecopts(options, &argv[argc]); 274 argv[argc++] = spec; 275 argv[argc++] = name; 276 argv[argc++] = NULL; 277 snprintf(execname, sizeof(execname), 278 "%s/mount_%s", _PATH_EXECDIR, mntname); 279 if (verbose) { 280 (void)printf("exec: %s", execname); 281 for (i = 1; i < argc - 1; i++) 282 (void)printf(" %s", argv[i]); 283 (void)printf("\n"); 284 } 285 if (debug) 286 break; 287 if (pid = vfork()) { 288 if (pid == -1) { 289 warn("vfork starting file system"); 290 return (1); 291 } 292 if (waitpid(pid, &status, 0) != -1 && 293 WIFEXITED(status) && 294 WEXITSTATUS(status) != 0) 295 return (WEXITSTATUS(status)); 296 spec = mntname; 297 goto out; 298 } 299 execv(execname, argv); 300 err(1, "cannot exec %s for %s", execname, name); 301 /* NOTREACHED */ 302 303 } 304 if (!debug && mount(mnttype, name, flags, argp)) { 305 (void)fprintf(stderr, "%s on %s: ", spec, name); 306 switch (errno) { 307 case EMFILE: 308 (void)fprintf(stderr, "Mount table full.\n"); 309 break; 310 case EINVAL: 311 if (flags & MNT_UPDATE) 312 (void)fprintf(stderr, "Specified device %s\n", 313 "does not match mounted device"); 314 else if (mnttype == MOUNT_UFS) 315 (void)fprintf(stderr, "Bogus super block\n"); 316 else 317 perror(NULL); 318 break; 319 default: 320 perror(NULL); 321 break; 322 } 323 return (1); 324 } 325 326 out: if (verbose) 327 prmount(spec, name, flags); 328 return (0); 329 } 330 331 void 332 prmount(spec, name, flags) 333 char *spec, *name; 334 int flags; 335 { 336 int first; 337 338 (void)printf("%s on %s", spec, name); 339 if (!(flags & MNT_VISFLAGMASK)) { 340 (void)printf("\n"); 341 return; 342 } 343 first = 0; 344 #define PR(msg) (void)printf("%s%s", !first++ ? " (" : ", ", msg) 345 if (flags & MNT_RDONLY) 346 PR("read-only"); 347 if (flags & MNT_NOEXEC) 348 PR("noexec"); 349 if (flags & MNT_NOSUID) 350 PR("nosuid"); 351 if (flags & MNT_NODEV) 352 PR("nodev"); 353 if (flags & MNT_SYNCHRONOUS) 354 PR("synchronous"); 355 if (flags & MNT_ASYNC) 356 PR("asynchronous"); 357 if (flags & MNT_QUOTA) 358 PR("with quotas"); 359 if (flags & MNT_LOCAL) 360 PR("local"); 361 if (flags & MNT_UNION) 362 PR("union"); 363 if (flags & MNT_EXPORTED) 364 PR("NFS exported"); 365 (void)printf(")\n"); 366 } 367 368 int 369 getmnttype(fstype) 370 char *fstype; 371 { 372 373 mntname = fstype; 374 return (strcmp(fstype, "ufs") == 0 ? MOUNT_UFS : 0); 375 } 376 377 void 378 getstdopts(options, flagp) 379 char *options; 380 int *flagp; 381 { 382 int negative; 383 char *opt, optbuf[BUFSIZ]; 384 385 (void)strcpy(optbuf, options); 386 for (opt = strtok(optbuf, ","); opt; opt = strtok(NULL, ",")) { 387 if (opt[0] == '-') 388 continue; 389 if (opt[0] == 'n' && opt[1] == 'o') { 390 negative++; 391 opt += 2; 392 } else 393 negative = 0; 394 if (!negative && !strcasecmp(opt, FSTAB_RO)) { 395 *flagp |= MNT_RDONLY; 396 continue; 397 } 398 if (!negative && !strcasecmp(opt, FSTAB_RW)) { 399 *flagp &= ~MNT_RDONLY; 400 continue; 401 } 402 if (!strcasecmp(opt, "exec")) { 403 if (negative) 404 *flagp |= MNT_NOEXEC; 405 else 406 *flagp &= ~MNT_NOEXEC; 407 continue; 408 } 409 if (!strcasecmp(opt, "suid")) { 410 if (negative) 411 *flagp |= MNT_NOSUID; 412 else 413 *flagp &= ~MNT_NOSUID; 414 continue; 415 } 416 if (!strcasecmp(opt, "dev")) { 417 if (negative) 418 *flagp |= MNT_NODEV; 419 else 420 *flagp &= ~MNT_NODEV; 421 continue; 422 } 423 if (!strcasecmp(opt, "synchronous")) { 424 if (!negative) 425 *flagp |= MNT_SYNCHRONOUS; 426 else 427 *flagp &= ~MNT_SYNCHRONOUS; 428 continue; 429 } 430 if (!strcasecmp(opt, "asynchronous")) { 431 if (!negative) 432 *flagp |= MNT_ASYNC; 433 else 434 *flagp &= ~MNT_ASYNC; 435 continue; 436 } 437 if (!strcasecmp(opt, "union")) { 438 if (!negative) 439 *flagp |= MNT_UNION; 440 else 441 *flagp &= ~MNT_UNION; 442 continue; 443 } 444 (void)fprintf(stderr, "mount: %s: unknown option\n", opt); 445 } 446 } 447 448 /* ARGSUSED */ 449 void 450 getufsopts(options, flagp) 451 char *options; 452 int *flagp; 453 { 454 455 return; 456 } 457 458 int 459 getexecopts(options, argv) 460 char *options, **argv; 461 { 462 int argc; 463 char *opt; 464 465 argc = 0; 466 for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) { 467 if (opt[0] != '-') 468 continue; 469 argv[argc++] = opt; 470 if (opt[2] == '\0' || opt[2] != '=') 471 continue; 472 opt[2] = '\0'; 473 argv[argc++] = &opt[3]; 474 } 475 return (argc); 476 } 477 478 struct statfs * 479 getmntpt(name) 480 char *name; 481 { 482 struct statfs *mntbuf; 483 long i, mntsize; 484 485 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 486 for (i = 0; i < mntsize; i++) { 487 if (!strcmp(mntbuf[i].f_mntfromname, name) || 488 !strcmp(mntbuf[i].f_mntonname, name)) 489 return (&mntbuf[i]); 490 } 491 return (NULL); 492 } 493 494 int 495 badvfstype(vfstype, vfslist) 496 int vfstype; 497 char **vfslist; 498 { 499 500 if (vfslist == NULL) 501 return (0); 502 while (*vfslist != NULL) { 503 if (vfstype == getmnttype(*vfslist)) 504 return (skipvfs); 505 vfslist++; 506 } 507 return (!skipvfs); 508 } 509 510 int 511 badvfsname(vfsname, vfslist) 512 char *vfsname; 513 char **vfslist; 514 { 515 516 if (vfslist == NULL) 517 return (0); 518 while (*vfslist != NULL) { 519 if (strcmp(vfsname, *vfslist) == 0) 520 return (skipvfs); 521 vfslist++; 522 } 523 return (!skipvfs); 524 } 525 526 char ** 527 makevfslist(fslist) 528 char *fslist; 529 { 530 int i; 531 char **av, *nextcp; 532 533 if (fslist == NULL) 534 return (NULL); 535 if (fslist[0] == 'n' && fslist[1] == 'o') { 536 fslist += 2; 537 skipvfs = 1; 538 } 539 for (i = 0, nextcp = fslist; *nextcp; nextcp++) 540 if (*nextcp == ',') 541 i++; 542 av = malloc((size_t)(i + 2) * sizeof(char *)); 543 if (av == NULL) 544 return (NULL); 545 nextcp = fslist; 546 i = 0; 547 av[i++] = nextcp; 548 while ((nextcp = index(nextcp, ',')) != NULL) { 549 *nextcp++ = '\0'; 550 av[i++] = nextcp; 551 } 552 av[i++] = NULL; 553 return (av); 554 } 555 556 void 557 usage() 558 { 559 560 (void)fprintf(stderr, 561 "usage:\n mount %s %s\n mount %s\n mount %s\n", 562 "[ -frwu ] [ -t ufs | external_type ]", 563 "[ -o options ] special node", 564 "[ -afrwu ] [ -t ufs | external_type ]", 565 "[ -frwu ] special | node"); 566 exit(1); 567 } 568