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.39 (Berkeley) 06/22/90"; 16 #endif /* not lint */ 17 18 #include "pathnames.h" 19 #include <sys/param.h> 20 #include <sys/file.h> 21 #include <sys/time.h> 22 #include <sys/wait.h> 23 #include <fstab.h> 24 #include <errno.h> 25 #include <stdio.h> 26 #include <signal.h> 27 #include <string.h> 28 #include <sys/mount.h> 29 #ifdef NFS 30 #include <sys/socket.h> 31 #include <sys/socketvar.h> 32 #include <netdb.h> 33 #include <rpc/rpc.h> 34 #include <rpc/pmap_clnt.h> 35 #include <rpc/pmap_prot.h> 36 #include <nfs/rpcv2.h> 37 #include <nfs/nfsv2.h> 38 #include <nfs/nfs.h> 39 #endif 40 41 #define DEFAULT_ROOTUID -2 42 43 #define BADTYPE(type) \ 44 (strcmp(type, FSTAB_RO) && strcmp(type, FSTAB_RW) && \ 45 strcmp(type, FSTAB_RQ)) 46 #define SETTYPE(type) \ 47 (!strcmp(type, FSTAB_RW) || !strcmp(type, FSTAB_RQ)) 48 49 int fake, verbose, updateflg, mnttype; 50 char *mntname, **envp; 51 char **vfslist, **makevfslist(); 52 53 #ifdef NFS 54 int xdr_dir(), xdr_fh(); 55 char *getnfsargs(); 56 struct nfs_args nfsdefargs = { 57 (struct sockaddr *)0, 58 SOCK_DGRAM, 59 0, 60 (nfsv2fh_t *)0, 61 0, 62 NFS_WSIZE, 63 NFS_RSIZE, 64 NFS_TIMEO, 65 NFS_RETRANS, 66 (char *)0, 67 }; 68 69 struct nfhret { 70 u_long stat; 71 nfsv2fh_t nfh; 72 }; 73 #define DEF_RETRY 10000 74 int retrycnt; 75 #define BGRND 1 76 #define ISBGRND 2 77 int opflags = 0; 78 #endif 79 80 main(argc, argv, arge) 81 int argc; 82 char **argv; 83 char **arge; 84 { 85 extern char *optarg; 86 extern int optind; 87 register struct fstab *fs; 88 int all, ch, rval, flags, ret, pid, i; 89 long mntsize; 90 struct statfs *mntbuf, *getmntpt(); 91 char *type, *options = NULL; 92 FILE *pidfile; 93 94 envp = arge; 95 all = 0; 96 type = NULL; 97 mnttype = MOUNT_UFS; 98 mntname = "ufs"; 99 while ((ch = getopt(argc, argv, "afrwuvt:o:")) != EOF) 100 switch((char)ch) { 101 case 'a': 102 all = 1; 103 break; 104 case 'f': 105 fake = 1; 106 break; 107 case 'r': 108 type = FSTAB_RO; 109 break; 110 case 'u': 111 updateflg = MNT_UPDATE; 112 break; 113 case 'v': 114 verbose = 1; 115 break; 116 case 'w': 117 type = FSTAB_RW; 118 break; 119 case 'o': 120 options = optarg; 121 break; 122 case 't': 123 vfslist = makevfslist(optarg); 124 mnttype = getmnttype(optarg); 125 break; 126 case '?': 127 default: 128 usage(); 129 /* NOTREACHED */ 130 } 131 argc -= optind; 132 argv += optind; 133 134 /* NOSTRICT */ 135 136 if (all) { 137 rval = 0; 138 while (fs = getfsent()) { 139 if (BADTYPE(fs->fs_type)) 140 continue; 141 if (badvfsname(fs->fs_vfstype, vfslist)) 142 continue; 143 /* `/' is special, it's always mounted */ 144 if (!strcmp(fs->fs_file, "/")) 145 flags = MNT_UPDATE; 146 else 147 flags = updateflg; 148 mnttype = getmnttype(fs->fs_vfstype); 149 rval |= mountfs(fs->fs_spec, fs->fs_file, flags, 150 type, options, fs->fs_mntops); 151 } 152 exit(rval); 153 } 154 155 if (argc == 0) { 156 if (verbose || fake || type) 157 usage(); 158 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { 159 fprintf(stderr, 160 "mount: cannot get mount information\n"); 161 exit(1); 162 } 163 for (i = 0; i < mntsize; i++) { 164 if (badvfstype(mntbuf[i].f_type, vfslist)) 165 continue; 166 prmount(mntbuf[i].f_mntfromname, mntbuf[i].f_mntonname, 167 mntbuf[i].f_flags); 168 } 169 exit(0); 170 } 171 172 if (argc == 1 && updateflg) { 173 if ((mntbuf = getmntpt(*argv)) == NULL) { 174 fprintf(stderr, 175 "mount: unknown special file or file system %s.\n", 176 *argv); 177 exit(1); 178 } 179 mnttype = mntbuf->f_type; 180 if (!strcmp(mntbuf->f_mntfromname, "root_device")) { 181 fs = getfsfile("/"); 182 strcpy(mntbuf->f_mntfromname, fs->fs_spec); 183 } 184 ret = mountfs(mntbuf->f_mntfromname, mntbuf->f_mntonname, 185 updateflg, type, options, (char *)NULL); 186 } else if (argc == 1) { 187 if (!(fs = getfsfile(*argv)) && !(fs = getfsspec(*argv))) { 188 fprintf(stderr, 189 "mount: unknown special file or file system %s.\n", 190 *argv); 191 exit(1); 192 } 193 if (BADTYPE(fs->fs_type)) { 194 fprintf(stderr, 195 "mount: %s has unknown file system type.\n", *argv); 196 exit(1); 197 } 198 mnttype = getmnttype(fs->fs_vfstype); 199 ret = mountfs(fs->fs_spec, fs->fs_file, updateflg, 200 type, options, fs->fs_mntops); 201 } else if (argc != 2) { 202 usage(); 203 ret = 1; 204 } else { 205 /* 206 * If -t flag has not been specified, and spec 207 * contains either a ':' or a '@' then assume that 208 * an NFS filesystem is being specified ala Sun. 209 */ 210 if (vfslist == (char **)0 && 211 (index(argv[0], ':') || index(argv[0], '@'))) 212 mnttype = MOUNT_NFS; 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 extern int errno; 231 union wait status; 232 pid_t pid; 233 int argc, i; 234 struct ufs_args args; 235 struct nfs_args nfsargs; 236 char *argp, *argv[50]; 237 char execname[MAXPATHLEN + 1], flagval[12]; 238 239 nfsargs = nfsdefargs; 240 if (mntopts) 241 getstdopts(mntopts, &flags); 242 if (options) 243 getstdopts(options, &flags); 244 if (type) 245 getstdopts(type, &flags); 246 switch (mnttype) { 247 case MOUNT_UFS: 248 if (mntopts) 249 getufsopts(mntopts, &flags); 250 if (options) 251 getufsopts(options, &flags); 252 args.fspec = spec; 253 args.exroot = DEFAULT_ROOTUID; 254 if (flags & MNT_RDONLY) 255 args.exflags = MNT_EXRDONLY; 256 else 257 args.exflags = 0; 258 argp = (caddr_t)&args; 259 break; 260 261 #ifdef NFS 262 case MOUNT_NFS: 263 retrycnt = DEF_RETRY; 264 if (mntopts) 265 getnfsopts(mntopts, &nfsargs, &opflags, &retrycnt); 266 if (options) 267 getnfsopts(options, &nfsargs, &opflags, &retrycnt); 268 if (argp = getnfsargs(spec, &nfsargs)) 269 break; 270 return (1); 271 #endif /* NFS */ 272 273 case MOUNT_MFS: 274 default: 275 argv[0] = mntname; 276 argc = 1; 277 if (flags) { 278 argv[argc++] = "-F"; 279 sprintf(flagval, "%d", flags); 280 argv[argc++] = flagval; 281 } 282 if (mntopts) 283 argc += getexecopts(mntopts, &argv[argc]); 284 if (options) 285 argc += getexecopts(options, &argv[argc]); 286 argv[argc++] = spec; 287 argv[argc++] = name; 288 argv[argc++] = NULL; 289 sprintf(execname, "%s/mount_%s", _PATH_EXECDIR, mntname); 290 if (verbose) { 291 (void)printf("exec: %s", execname); 292 for (i = 1; i < argc - 1; i++) 293 (void)printf(" %s", argv[i]); 294 (void)printf("\n"); 295 } 296 if (fake) 297 break; 298 if (pid = vfork()) { 299 if (pid == -1) { 300 perror("mount: vfork starting file system"); 301 return (1); 302 } 303 if (waitpid(pid, &status, 0) != -1 && 304 WIFEXITED(status) && 305 WEXITSTATUS(status) != 0) 306 return (WEXITSTATUS(status)); 307 spec = mntname; 308 goto out; 309 } 310 execve(execname, argv, envp); 311 fprintf(stderr, "mount: cannot exec %s for %s: ", 312 execname, name); 313 perror((char *)NULL); 314 exit (1); 315 /* NOTREACHED */ 316 317 } 318 if (!fake && mount(mnttype, name, flags, argp)) { 319 if (opflags & ISBGRND) 320 exit(1); 321 fprintf(stderr, "%s on %s: ", spec, name); 322 switch (errno) { 323 case EMFILE: 324 fprintf(stderr, "Mount table full\n"); 325 break; 326 case EINVAL: 327 if (flags & MNT_UPDATE) 328 fprintf(stderr, "Specified device does %s\n", 329 "not match mounted device"); 330 else 331 fprintf(stderr, "Bogus super block\n"); 332 break; 333 case EOPNOTSUPP: 334 fprintf(stderr, "Operation not supported\n"); 335 break; 336 default: 337 perror((char *)NULL); 338 break; 339 } 340 return(1); 341 } 342 343 out: 344 if (verbose) 345 prmount(spec, name, flags); 346 347 if (opflags & ISBGRND) 348 exit(1); 349 return(0); 350 } 351 352 static 353 prmount(spec, name, flags) 354 char *spec, *name; 355 register short flags; 356 { 357 register int first; 358 359 if (opflags & ISBGRND) 360 return; 361 (void)printf("%s on %s", spec, name); 362 if (!(flags & MNT_VISFLAGMASK)) { 363 (void)printf("\n"); 364 return; 365 } 366 first = 0; 367 #define PR(msg) (void)printf("%s%s", !first++ ? " (" : ", ", msg) 368 if (flags & MNT_RDONLY) 369 PR("read-only"); 370 if (flags & MNT_NOEXEC) 371 PR("noexec"); 372 if (flags & MNT_NOSUID) 373 PR("nosuid"); 374 if (flags & MNT_NODEV) 375 PR("nodev"); 376 if (flags & MNT_SYNCHRONOUS) 377 PR("synchronous"); 378 if (flags & MNT_QUOTA) 379 PR("with quotas"); 380 if (flags & MNT_LOCAL) 381 PR("local"); 382 if (flags & MNT_EXPORTED) 383 if (flags & MNT_EXRDONLY) 384 PR("NFS exported read-only"); 385 else 386 PR("NFS exported"); 387 (void)printf(")\n"); 388 } 389 390 getmnttype(fstype) 391 char *fstype; 392 { 393 394 mntname = fstype; 395 if (!strcmp(fstype, "ufs")) 396 return (MOUNT_UFS); 397 if (!strcmp(fstype, "nfs")) 398 return (MOUNT_NFS); 399 if (!strcmp(fstype, "mfs")) 400 return (MOUNT_MFS); 401 return (0); 402 } 403 404 usage() 405 { 406 407 fprintf(stderr, "usage:\n mount %s %s\n mount %s\n mount %s\n", 408 "[ -frwu ] [ -t nfs | ufs | external_type ]", 409 "[ -o options ] special node", 410 "[ -afrwu ] [ -t nfs | ufs | external_type ]", 411 "[ -frwu ] special | node"); 412 exit(1); 413 } 414 415 getstdopts(options, flagp) 416 char *options; 417 int *flagp; 418 { 419 register char *opt; 420 int negative; 421 char optbuf[BUFSIZ]; 422 423 (void)strcpy(optbuf, options); 424 for (opt = strtok(optbuf, ","); opt; opt = strtok((char *)NULL, ",")) { 425 if (opt[0] == 'n' && opt[1] == 'o') { 426 negative++; 427 opt += 2; 428 } else { 429 negative = 0; 430 } 431 if (!negative && !strcasecmp(opt, FSTAB_RO)) { 432 *flagp |= MNT_RDONLY; 433 continue; 434 } 435 if (!negative && !strcasecmp(opt, FSTAB_RW)) { 436 *flagp &= ~MNT_RDONLY; 437 continue; 438 } 439 if (!strcasecmp(opt, "exec")) { 440 if (negative) 441 *flagp |= MNT_NOEXEC; 442 else 443 *flagp &= ~MNT_NOEXEC; 444 continue; 445 } 446 if (!strcasecmp(opt, "suid")) { 447 if (negative) 448 *flagp |= MNT_NOSUID; 449 else 450 *flagp &= ~MNT_NOSUID; 451 continue; 452 } 453 if (!strcasecmp(opt, "dev")) { 454 if (negative) 455 *flagp |= MNT_NODEV; 456 else 457 *flagp &= ~MNT_NODEV; 458 continue; 459 } 460 if (!strcasecmp(opt, "synchronous")) { 461 if (!negative) 462 *flagp |= MNT_SYNCHRONOUS; 463 else 464 *flagp &= ~MNT_SYNCHRONOUS; 465 continue; 466 } 467 } 468 } 469 470 /* ARGSUSED */ 471 getufsopts(options, flagp) 472 char *options; 473 int *flagp; 474 { 475 return; 476 } 477 478 getexecopts(options, argv) 479 char *options; 480 char **argv; 481 { 482 register int argc = 0; 483 register char *opt; 484 485 for (opt = strtok(options, ","); opt; opt = strtok((char *)NULL, ",")) { 486 if (opt[0] != '-') 487 continue; 488 argv[argc++] = opt; 489 if (opt[2] == '\0' || opt[2] != '=') 490 continue; 491 opt[2] = '\0'; 492 argv[argc++] = &opt[3]; 493 } 494 return (argc); 495 } 496 497 struct statfs * 498 getmntpt(name) 499 char *name; 500 { 501 long mntsize; 502 register long i; 503 struct statfs *mntbuf; 504 505 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 506 for (i = 0; i < mntsize; i++) { 507 if (!strcmp(mntbuf[i].f_mntfromname, name) || 508 !strcmp(mntbuf[i].f_mntonname, name)) 509 return (&mntbuf[i]); 510 } 511 return ((struct statfs *)0); 512 } 513 514 static int skipvfs; 515 516 badvfstype(vfstype, vfslist) 517 short vfstype; 518 char **vfslist; 519 { 520 521 if (vfslist == 0) 522 return(0); 523 while (*vfslist) { 524 if (vfstype == getmnttype(*vfslist)) 525 return(skipvfs); 526 vfslist++; 527 } 528 return (!skipvfs); 529 } 530 531 badvfsname(vfsname, vfslist) 532 char *vfsname; 533 char **vfslist; 534 { 535 536 if (vfslist == 0) 537 return(0); 538 while (*vfslist) { 539 if (strcmp(vfsname, *vfslist) == 0) 540 return(skipvfs); 541 vfslist++; 542 } 543 return (!skipvfs); 544 } 545 546 char ** 547 makevfslist(fslist) 548 char *fslist; 549 { 550 register char **av, *nextcp; 551 register int i; 552 553 if (fslist == NULL) 554 return (NULL); 555 if (fslist[0] == 'n' && fslist[1] == 'o') { 556 fslist += 2; 557 skipvfs = 1; 558 } 559 for (i = 0, nextcp = fslist; *nextcp; nextcp++) 560 if (*nextcp == ',') 561 i++; 562 av = (char **)malloc((size_t)(i+2) * sizeof(char *)); 563 if (av == NULL) 564 return (NULL); 565 nextcp = fslist; 566 i = 0; 567 av[i++] = nextcp; 568 while (nextcp = index(nextcp, ',')) { 569 *nextcp++ = '\0'; 570 av[i++] = nextcp; 571 } 572 av[i++] = 0; 573 return (av); 574 } 575 576 #ifdef NFS 577 /* 578 * Handle the getoption arg. 579 * Essentially update "opflags", "retrycnt" and "nfsargs" 580 */ 581 getnfsopts(optarg, nfsargsp, opflagsp, retrycntp) 582 char *optarg; 583 struct nfs_args *nfsargsp; 584 int *opflagsp; 585 int *retrycntp; 586 { 587 register char *cp, *nextcp; 588 int num; 589 char *nump; 590 591 cp = optarg; 592 while (cp != NULL && *cp != '\0') { 593 if ((nextcp = index(cp, ',')) != NULL) 594 *nextcp++ = '\0'; 595 if ((nump = index(cp, '=')) != NULL) { 596 *nump++ = '\0'; 597 num = atoi(nump); 598 } else 599 num = -1; 600 /* 601 * Just test for a string match and do it 602 */ 603 if (!strcmp(cp, "bg")) { 604 *opflagsp |= BGRND; 605 } else if (!strcmp(cp, "soft")) { 606 if (nfsargsp->flags & NFSMNT_SPONGY) { 607 fprintf(stderr, 608 "Options soft, spongy mutually exclusive\n"); 609 exit(1); 610 } 611 nfsargsp->flags |= NFSMNT_SOFT; 612 } else if (!strcmp(cp, "spongy")) { 613 if (nfsargsp->flags & NFSMNT_SOFT) { 614 fprintf(stderr, 615 "Options soft, spongy mutually exclusive\n"); 616 exit(1); 617 } 618 nfsargsp->flags |= NFSMNT_SPONGY; 619 } else if (!strcmp(cp, "intr")) { 620 nfsargsp->flags |= NFSMNT_INT; 621 } else if (!strcmp(cp, "tcp")) { 622 nfsargsp->sotype = SOCK_STREAM; 623 } else if (!strcmp(cp, "noconn")) { 624 nfsargsp->flags |= NFSMNT_NOCONN; 625 } else if (!strcmp(cp, "retry") && num > 0) { 626 *retrycntp = num; 627 } else if (!strcmp(cp, "rsize") && num > 0) { 628 nfsargsp->rsize = num; 629 nfsargsp->flags |= NFSMNT_RSIZE; 630 } else if (!strcmp(cp, "wsize") && num > 0) { 631 nfsargsp->wsize = num; 632 nfsargsp->flags |= NFSMNT_WSIZE; 633 } else if (!strcmp(cp, "timeo") && num > 0) { 634 nfsargsp->timeo = num; 635 nfsargsp->flags |= NFSMNT_TIMEO; 636 } else if (!strcmp(cp, "retrans") && num > 0) { 637 nfsargsp->retrans = num; 638 nfsargsp->flags |= NFSMNT_RETRANS; 639 } 640 cp = nextcp; 641 } 642 if (nfsargsp->sotype == SOCK_DGRAM) { 643 if (nfsargsp->rsize > NFS_MAXDGRAMDATA) 644 nfsargsp->rsize = NFS_MAXDGRAMDATA; 645 if (nfsargsp->wsize > NFS_MAXDGRAMDATA) 646 nfsargsp->wsize = NFS_MAXDGRAMDATA; 647 } 648 } 649 650 char * 651 getnfsargs(spec, nfsargsp) 652 char *spec; 653 struct nfs_args *nfsargsp; 654 { 655 extern int errno; 656 register CLIENT *clp; 657 struct hostent *hp; 658 static struct sockaddr_in saddr; 659 struct timeval pertry, try; 660 enum clnt_stat clnt_stat; 661 int so = RPC_ANYSOCK; 662 char *hostp, *delimp; 663 u_short tport; 664 static struct nfhret nfhret; 665 static char nam[MNAMELEN + 1]; 666 667 strncpy(nam, spec, MNAMELEN); 668 nam[MNAMELEN] = '\0'; 669 if ((delimp = index(spec, '@')) != NULL) { 670 hostp = delimp + 1; 671 } else if ((delimp = index(spec, ':')) != NULL) { 672 hostp = spec; 673 spec = delimp + 1; 674 } else { 675 fprintf(stderr, 676 "No <host>:<dirpath> or <dirpath>@<host> spec\n"); 677 return (0); 678 } 679 *delimp = '\0'; 680 if ((hp = gethostbyname(hostp)) == NULL) { 681 fprintf(stderr, "Can't get net id for host\n"); 682 return (0); 683 } 684 bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length); 685 nfhret.stat = EACCES; /* Mark not yet successful */ 686 while (retrycnt > 0) { 687 saddr.sin_family = AF_INET; 688 saddr.sin_port = htons(PMAPPORT); 689 if ((tport = pmap_getport(&saddr, RPCPROG_NFS, 690 NFS_VER2, IPPROTO_UDP)) == 0) { 691 if ((opflags & ISBGRND) == 0) 692 clnt_pcreateerror("NFS Portmap"); 693 } else { 694 saddr.sin_port = 0; 695 pertry.tv_sec = 10; 696 pertry.tv_usec = 0; 697 if ((clp = clntudp_create(&saddr, RPCPROG_MNT, 698 RPCMNT_VER1, pertry, &so)) == NULL) { 699 if ((opflags & ISBGRND) == 0) 700 clnt_pcreateerror("Cannot MNT PRC"); 701 } else { 702 clp->cl_auth = authunix_create_default(); 703 try.tv_sec = 10; 704 try.tv_usec = 0; 705 clnt_stat = clnt_call(clp, RPCMNT_MOUNT, 706 xdr_dir, spec, xdr_fh, &nfhret, try); 707 if (clnt_stat != RPC_SUCCESS) { 708 if ((opflags & ISBGRND) == 0) 709 clnt_perror(clp, "Bad MNT RPC"); 710 } else { 711 auth_destroy(clp->cl_auth); 712 clnt_destroy(clp); 713 retrycnt = 0; 714 } 715 } 716 } 717 if (--retrycnt > 0) { 718 if (opflags & BGRND) { 719 opflags &= ~BGRND; 720 if (fork()) 721 return (0); 722 else 723 opflags |= ISBGRND; 724 } 725 sleep(10); 726 } 727 } 728 if (nfhret.stat) { 729 if (opflags & ISBGRND) 730 exit(1); 731 fprintf(stderr, "Can't access %s: ", spec); 732 errno = nfhret.stat; 733 perror((char *)NULL); 734 return (0); 735 } 736 saddr.sin_port = htons(tport); 737 nfsargsp->addr = (struct sockaddr *) &saddr; 738 nfsargsp->fh = &nfhret.nfh; 739 nfsargsp->hostname = nam; 740 return ((caddr_t)nfsargsp); 741 } 742 743 /* 744 * xdr routines for mount rpc's 745 */ 746 xdr_dir(xdrsp, dirp) 747 XDR *xdrsp; 748 char *dirp; 749 { 750 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 751 } 752 753 xdr_fh(xdrsp, np) 754 XDR *xdrsp; 755 struct nfhret *np; 756 { 757 if (!xdr_u_long(xdrsp, &(np->stat))) 758 return (0); 759 if (np->stat) 760 return (1); 761 return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH)); 762 } 763 #endif /* NFS */ 764