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