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.48 (Berkeley) 01/13/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 (!strcmp(mntbuf->f_mntfromname, "root_device")) { 146 fs = getfsfile("/"); 147 strcpy(mntbuf->f_mntfromname, fs->fs_spec); 148 } 149 ret = mountfs(mntbuf->f_mntfromname, mntbuf->f_mntonname, 150 updateflg, type, options, (char *)NULL); 151 } else if (argc == 1) { 152 if (!(fs = getfsfile(*argv)) && !(fs = getfsspec(*argv))) { 153 (void) fprintf(stderr, 154 "mount: unknown special file or file system %s.\n", 155 *argv); 156 exit(1); 157 } 158 if (BADTYPE(fs->fs_type)) { 159 (void) fprintf(stderr, 160 "mount: %s has unknown file system type.\n", *argv); 161 exit(1); 162 } 163 mnttype = getmnttype(fs->fs_vfstype); 164 ret = mountfs(fs->fs_spec, fs->fs_file, updateflg, 165 type, options, fs->fs_mntops); 166 } else if (argc != 2) { 167 usage(); 168 ret = 1; 169 } else { 170 /* 171 * If -t flag has not been specified, and spec 172 * contains either a ':' or a '@' then assume that 173 * an NFS filesystem is being specified ala Sun. 174 */ 175 if (vfslist == (char **)0 && 176 (index(argv[0], ':') || index(argv[0], '@'))) { 177 mnttype = MOUNT_NFS; 178 mntname = "nfs"; 179 } 180 ret = mountfs(argv[0], argv[1], updateflg, type, options, 181 (char *)NULL); 182 } 183 if ((pidfile = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 184 pid = 0; 185 fscanf(pidfile, "%d", &pid); 186 fclose(pidfile); 187 if (pid > 0) 188 kill(pid, SIGHUP); 189 } 190 exit (ret); 191 } 192 193 mountfs(spec, name, flags, type, options, mntopts) 194 char *spec, *name, *type, *options, *mntopts; 195 int flags; 196 { 197 union wait status; 198 pid_t pid; 199 int argc, i; 200 struct ufs_args args; 201 char *argp, *argv[50]; 202 char execname[MAXPATHLEN + 1], flagval[12]; 203 204 if (mntopts) 205 getstdopts(mntopts, &flags); 206 if (options) 207 getstdopts(options, &flags); 208 if (type) 209 getstdopts(type, &flags); 210 switch (mnttype) { 211 case MOUNT_LFS: 212 case MOUNT_UFS: 213 if (mntopts) 214 getufsopts(mntopts, &flags); 215 if (options) 216 getufsopts(options, &flags); 217 args.fspec = spec; 218 args.exroot = DEFAULT_ROOTUID; 219 if (flags & MNT_RDONLY) 220 args.exflags = MNT_EXRDONLY; 221 else 222 args.exflags = 0; 223 argp = (caddr_t)&args; 224 break; 225 226 case MOUNT_MFS: 227 case MOUNT_NFS: 228 default: 229 argv[0] = mntname; 230 argc = 1; 231 if (flags) { 232 argv[argc++] = "-F"; 233 sprintf(flagval, "%d", flags); 234 argv[argc++] = flagval; 235 } 236 if (mntopts) 237 argc += getexecopts(mntopts, &argv[argc]); 238 if (options) 239 argc += getexecopts(options, &argv[argc]); 240 argv[argc++] = spec; 241 argv[argc++] = name; 242 argv[argc++] = NULL; 243 sprintf(execname, "%s/mount_%s", _PATH_EXECDIR, mntname); 244 if (verbose) { 245 (void)printf("exec: %s", execname); 246 for (i = 1; i < argc - 1; i++) 247 (void)printf(" %s", argv[i]); 248 (void)printf("\n"); 249 } 250 if (fake) 251 break; 252 if (pid = vfork()) { 253 if (pid == -1) { 254 perror("mount: vfork starting file system"); 255 return (1); 256 } 257 if (waitpid(pid, (int *)&status, 0) != -1 && 258 WIFEXITED(status) && 259 WEXITSTATUS(status) != 0) 260 return (WEXITSTATUS(status)); 261 spec = mntname; 262 goto out; 263 } 264 execve(execname, argv, envp); 265 (void) fprintf(stderr, "mount: cannot exec %s for %s: ", 266 execname, name); 267 perror((char *)NULL); 268 exit (1); 269 /* NOTREACHED */ 270 271 } 272 if (!fake && mount(mnttype, name, flags, argp)) { 273 (void) fprintf(stderr, "%s on %s: ", spec, name); 274 switch (errno) { 275 case EMFILE: 276 (void) fprintf(stderr, "Mount table full\n"); 277 break; 278 case EINVAL: 279 if (flags & MNT_UPDATE) 280 (void) fprintf(stderr, "Specified device %s\n", 281 "does not match mounted device"); 282 else if (mnttype == MOUNT_UFS) 283 (void) fprintf(stderr, "Bogus super block\n"); 284 else 285 perror((char *)NULL); 286 break; 287 default: 288 perror((char *)NULL); 289 break; 290 } 291 return(1); 292 } 293 294 out: 295 if (verbose) 296 prmount(spec, name, flags); 297 298 return(0); 299 } 300 301 static void 302 prmount(spec, name, flags) 303 char *spec, *name; 304 register short flags; 305 { 306 register int first; 307 308 (void)printf("%s on %s", spec, name); 309 if (!(flags & MNT_VISFLAGMASK)) { 310 (void)printf("\n"); 311 return; 312 } 313 first = 0; 314 #define PR(msg) (void)printf("%s%s", !first++ ? " (" : ", ", msg) 315 if (flags & MNT_RDONLY) 316 PR("read-only"); 317 if (flags & MNT_NOEXEC) 318 PR("noexec"); 319 if (flags & MNT_NOSUID) 320 PR("nosuid"); 321 if (flags & MNT_NODEV) 322 PR("nodev"); 323 if (flags & MNT_SYNCHRONOUS) 324 PR("synchronous"); 325 if (flags & MNT_QUOTA) 326 PR("with quotas"); 327 if (flags & MNT_LOCAL) 328 PR("local"); 329 if (flags & MNT_EXPORTED) 330 PR("NFS exported"); 331 (void)printf(")\n"); 332 } 333 334 getmnttype(fstype) 335 char *fstype; 336 { 337 338 mntname = fstype; 339 if (!strcmp(fstype, "ufs")) 340 return (MOUNT_UFS); 341 if (!strcmp(fstype, "nfs")) 342 return (MOUNT_NFS); 343 if (!strcmp(fstype, "mfs")) 344 return (MOUNT_MFS); 345 if (!strcmp(fstype, "lfs")) 346 return (MOUNT_LFS); 347 return (0); 348 } 349 350 usage() 351 { 352 353 (void) fprintf(stderr, 354 "usage:\n mount %s %s\n mount %s\n mount %s\n", 355 "[ -frwu ] [ -t ufs | external_type ]", 356 "[ -o options ] special node", 357 "[ -afrwu ] [ -t ufs | external_type ]", 358 "[ -frwu ] special | node"); 359 exit(1); 360 } 361 362 getstdopts(options, flagp) 363 char *options; 364 int *flagp; 365 { 366 register char *opt; 367 int negative; 368 char optbuf[BUFSIZ]; 369 370 (void)strcpy(optbuf, options); 371 for (opt = strtok(optbuf, ","); opt; opt = strtok((char *)NULL, ",")) { 372 if (opt[0] == 'n' && opt[1] == 'o') { 373 negative++; 374 opt += 2; 375 } else { 376 negative = 0; 377 } 378 if (!negative && !strcasecmp(opt, FSTAB_RO)) { 379 *flagp |= MNT_RDONLY; 380 continue; 381 } 382 if (!negative && !strcasecmp(opt, FSTAB_RW)) { 383 *flagp &= ~MNT_RDONLY; 384 continue; 385 } 386 if (!strcasecmp(opt, "exec")) { 387 if (negative) 388 *flagp |= MNT_NOEXEC; 389 else 390 *flagp &= ~MNT_NOEXEC; 391 continue; 392 } 393 if (!strcasecmp(opt, "suid")) { 394 if (negative) 395 *flagp |= MNT_NOSUID; 396 else 397 *flagp &= ~MNT_NOSUID; 398 continue; 399 } 400 if (!strcasecmp(opt, "dev")) { 401 if (negative) 402 *flagp |= MNT_NODEV; 403 else 404 *flagp &= ~MNT_NODEV; 405 continue; 406 } 407 if (!strcasecmp(opt, "synchronous")) { 408 if (!negative) 409 *flagp |= MNT_SYNCHRONOUS; 410 else 411 *flagp &= ~MNT_SYNCHRONOUS; 412 continue; 413 } 414 } 415 } 416 417 /* ARGSUSED */ 418 getufsopts(options, flagp) 419 char *options; 420 int *flagp; 421 { 422 return; 423 } 424 425 getexecopts(options, argv) 426 char *options; 427 char **argv; 428 { 429 register int argc = 0; 430 register char *opt; 431 432 for (opt = strtok(options, ","); opt; opt = strtok((char *)NULL, ",")) { 433 if (opt[0] != '-') 434 continue; 435 argv[argc++] = opt; 436 if (opt[2] == '\0' || opt[2] != '=') 437 continue; 438 opt[2] = '\0'; 439 argv[argc++] = &opt[3]; 440 } 441 return (argc); 442 } 443 444 struct statfs * 445 getmntpt(name) 446 char *name; 447 { 448 long mntsize; 449 register long i; 450 struct statfs *mntbuf; 451 452 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 453 for (i = 0; i < mntsize; i++) { 454 if (!strcmp(mntbuf[i].f_mntfromname, name) || 455 !strcmp(mntbuf[i].f_mntonname, name)) 456 return (&mntbuf[i]); 457 } 458 return ((struct statfs *)0); 459 } 460 461 static int skipvfs; 462 463 badvfstype(vfstype, vfslist) 464 short vfstype; 465 char **vfslist; 466 { 467 468 if (vfslist == 0) 469 return(0); 470 while (*vfslist) { 471 if (vfstype == getmnttype(*vfslist)) 472 return(skipvfs); 473 vfslist++; 474 } 475 return (!skipvfs); 476 } 477 478 badvfsname(vfsname, vfslist) 479 char *vfsname; 480 char **vfslist; 481 { 482 483 if (vfslist == 0) 484 return(0); 485 while (*vfslist) { 486 if (strcmp(vfsname, *vfslist) == 0) 487 return(skipvfs); 488 vfslist++; 489 } 490 return (!skipvfs); 491 } 492 493 char ** 494 makevfslist(fslist) 495 char *fslist; 496 { 497 register char **av, *nextcp; 498 register int i; 499 500 if (fslist == NULL) 501 return (NULL); 502 if (fslist[0] == 'n' && fslist[1] == 'o') { 503 fslist += 2; 504 skipvfs = 1; 505 } 506 for (i = 0, nextcp = fslist; *nextcp; nextcp++) 507 if (*nextcp == ',') 508 i++; 509 av = (char **)malloc((size_t)(i+2) * sizeof(char *)); 510 if (av == NULL) 511 return (NULL); 512 nextcp = fslist; 513 i = 0; 514 av[i++] = nextcp; 515 while (nextcp = index(nextcp, ',')) { 516 *nextcp++ = '\0'; 517 av[i++] = nextcp; 518 } 519 av[i++] = 0; 520 return (av); 521 } 522