121156Sdist /* 221156Sdist * Copyright (c) 1980 Regents of the University of California. 321156Sdist * All rights reserved. The Berkeley software License Agreement 421156Sdist * specifies the terms and conditions for redistribution. 521156Sdist */ 621156Sdist 710811Ssam #ifndef lint 821156Sdist char copyright[] = 921156Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1021156Sdist All rights reserved.\n"; 1121156Sdist #endif not lint 121057Sbill 1321156Sdist #ifndef lint 14*39131Smckusick static char sccsid[] = "@(#)mount.c 5.11 (Berkeley) 09/12/89"; 1521156Sdist #endif not lint 1621156Sdist 17*39131Smckusick #include "pathnames.h" 1812808Ssam #include <sys/param.h> 1935339Sbostic #include <sys/file.h> 2038445Smckusick #include <sys/time.h> 2110811Ssam #include <fstab.h> 2216669Ssam #include <errno.h> 2335339Sbostic #include <stdio.h> 2438445Smckusick #include <strings.h> 2538445Smckusick #include <sys/dir.h> 2638445Smckusick #include <sys/uio.h> 2738445Smckusick #include <sys/namei.h> 2838445Smckusick #include <sys/mount.h> 2938445Smckusick #ifdef NFS 3038445Smckusick #include <sys/socket.h> 3138445Smckusick #include <sys/socketvar.h> 3238445Smckusick #include <netdb.h> 3338445Smckusick #include <rpc/rpc.h> 3438445Smckusick #include <rpc/pmap_clnt.h> 3538445Smckusick #include <rpc/pmap_prot.h> 3638445Smckusick #include <nfs/rpcv2.h> 3738445Smckusick #include <nfs/nfsv2.h> 3838445Smckusick #include <nfs/nfs.h> 3938445Smckusick #endif 401057Sbill 4135339Sbostic #define BADTYPE(type) \ 4235339Sbostic (strcmp(type, FSTAB_RO) && strcmp(type, FSTAB_RW) && \ 4335339Sbostic strcmp(type, FSTAB_RQ)) 4435339Sbostic #define SETTYPE(type) \ 4535339Sbostic (!strcmp(type, FSTAB_RW) || !strcmp(type, FSTAB_RQ)) 461057Sbill 4738445Smckusick static int fake, verbose, mnttype; 48*39131Smckusick char **envp; 49*39131Smckusick 5038445Smckusick #ifdef NFS 5138445Smckusick int xdr_dir(), xdr_fh(); 5238632Smckusick char *getnfsargs(); 5338445Smckusick struct nfs_args nfsargs = { 5438445Smckusick (struct sockaddr_in *)0, 5538445Smckusick (nfsv2fh_t *)0, 5638445Smckusick 0, 5738445Smckusick NFS_WSIZE, 5838445Smckusick NFS_RSIZE, 5938445Smckusick NFS_TIMEO, 6038445Smckusick NFS_RETRANS, 6138445Smckusick (char *)0, 6238445Smckusick }; 635073Sroot 6438445Smckusick struct nfhret { 6538445Smckusick u_long stat; 6638445Smckusick nfsv2fh_t nfh; 6738445Smckusick }; 6838445Smckusick int retrycnt = 10000; 6938445Smckusick #define BGRND 1 7038445Smckusick #define ISBGRND 2 7138445Smckusick int opflags = 0; 7238445Smckusick #endif 7338445Smckusick 74*39131Smckusick main(argc, argv, arge) 755073Sroot int argc; 765073Sroot char **argv; 77*39131Smckusick char **arge; 781057Sbill { 7935339Sbostic extern char *optarg; 8035339Sbostic extern int optind; 8135339Sbostic register struct fstab *fs; 8235339Sbostic register int cnt; 8338632Smckusick int all, ch, rval, sfake, i; 8438632Smckusick long mntsize; 8538632Smckusick struct statfs statfsbuf, *mntbuf; 86*39131Smckusick char *type, *options = NULL; 871057Sbill 88*39131Smckusick envp = arge; 8935339Sbostic all = 0; 9035339Sbostic type = NULL; 9138445Smckusick mnttype = MOUNT_UFS; 9238445Smckusick while ((ch = getopt(argc, argv, "afrwvt:o:")) != EOF) 9335339Sbostic switch((char)ch) { 9435339Sbostic case 'a': 9535339Sbostic all = 1; 9635339Sbostic break; 9735339Sbostic case 'f': 9835339Sbostic fake = 1; 9935339Sbostic break; 10035339Sbostic case 'r': 10112808Ssam type = FSTAB_RO; 10235339Sbostic break; 10335339Sbostic case 'v': 10435339Sbostic verbose = 1; 10535339Sbostic break; 10635339Sbostic case 'w': 10735339Sbostic type = FSTAB_RW; 10835339Sbostic break; 109*39131Smckusick case 'o': 110*39131Smckusick options = optarg; 111*39131Smckusick break; 11238445Smckusick case 't': 113*39131Smckusick if (!strcmp(optarg, "ufs")) { 114*39131Smckusick mnttype = MOUNT_UFS; 115*39131Smckusick break; 116*39131Smckusick } 117*39131Smckusick if (!strcmp(optarg, "nfs")) { 11838445Smckusick mnttype = MOUNT_NFS; 119*39131Smckusick break; 120*39131Smckusick } 121*39131Smckusick if (!strcmp(optarg, "mfs")) { 122*39131Smckusick mnttype = MOUNT_MFS; 123*39131Smckusick break; 124*39131Smckusick } 125*39131Smckusick /* fall through */ 12635339Sbostic case '?': 12735339Sbostic default: 12835339Sbostic usage(); 129*39131Smckusick /* NOTREACHED */ 1305073Sroot } 13135339Sbostic argc -= optind; 13235339Sbostic argv += optind; 13335339Sbostic 13435339Sbostic /* NOSTRICT */ 13535339Sbostic 1364460Sroot if (all) { 13735369Sbostic rval = 0; 13835372Sbostic for (sfake = fake; fs = getfsent(); fake = sfake) { 13935372Sbostic if (BADTYPE(fs->fs_type)) 14035372Sbostic continue; 14135372Sbostic /* `/' is special, it's always mounted */ 14235372Sbostic if (!strcmp(fs->fs_file, "/")) 14335372Sbostic fake = 1; 14435372Sbostic rval |= mountfs(fs->fs_spec, fs->fs_file, 145*39131Smckusick type ? type : fs->fs_type, options, fs->fs_mntops); 14635372Sbostic } 14735341Sbostic exit(rval); 14835339Sbostic } 1495073Sroot 15035339Sbostic if (argc == 0) { 15135339Sbostic if (verbose || fake || type) 15235339Sbostic usage(); 15338632Smckusick if ((mntsize = getfsstat(0, 0)) < 0) { 15438632Smckusick perror("mount"); 15538632Smckusick exit(1); 15638632Smckusick } 15738632Smckusick mntbuf = 0; 15838632Smckusick do { 15938632Smckusick if (mntbuf) 16038632Smckusick free(mntbuf); 16138632Smckusick i = (mntsize + 1) * sizeof(struct statfs); 16238632Smckusick if ((mntbuf = (struct statfs *)malloc(i)) == 0) { 16338632Smckusick fprintf(stderr, 16438632Smckusick "no space for mount table buffer\n"); 16538632Smckusick exit(1); 16638632Smckusick } 16738632Smckusick if ((mntsize = getfsstat(mntbuf, i)) < 0) { 168*39131Smckusick perror("mount"); 16938632Smckusick exit(1); 17038632Smckusick } 17138632Smckusick } while (i == mntsize * sizeof(struct statfs)); 17238632Smckusick for (i = 0; i < mntsize; i++) { 17338632Smckusick if (mntbuf[i].f_flags & M_RDONLY) 17438632Smckusick type = "ro"; 17538632Smckusick else 17638632Smckusick type = "rw"; 17738632Smckusick prmount(mntbuf[i].f_mntfromname, mntbuf[i].f_mntonname, 17838632Smckusick type); 17938632Smckusick } 1804460Sroot exit(0); 1811057Sbill } 18212808Ssam 18335339Sbostic if (all) 18435339Sbostic usage(); 18535339Sbostic 18635339Sbostic if (argc == 1) { 18735339Sbostic if (!(fs = getfsfile(*argv)) && !(fs = getfsspec(*argv))) { 18835339Sbostic fprintf(stderr, 18935339Sbostic "mount: unknown special file or file system %s.\n", 19035339Sbostic *argv); 19135339Sbostic exit(1); 19235339Sbostic } 19335339Sbostic if (BADTYPE(fs->fs_type)) { 19435339Sbostic fprintf(stderr, 19535339Sbostic "mount: %s has unknown file system type.\n", *argv); 19635339Sbostic exit(1); 19735339Sbostic } 19835369Sbostic exit(mountfs(fs->fs_spec, fs->fs_file, 199*39131Smckusick type ? type : fs->fs_type, options, fs->fs_mntops)); 20012808Ssam } 2011057Sbill 20235339Sbostic if (argc != 2) 20335339Sbostic usage(); 20412808Ssam 205*39131Smckusick exit(mountfs(argv[0], argv[1], type ? type : "rw", options, NULL)); 20612808Ssam } 20712808Ssam 208*39131Smckusick mountfs(spec, name, type, options, mntopts) 209*39131Smckusick char *spec, *name, *type, *options, *mntopts; 21012808Ssam { 21135339Sbostic extern int errno; 21235339Sbostic register int cnt; 213*39131Smckusick int flags, argc, status, i; 21438070Smckusick struct ufs_args args; 215*39131Smckusick char *argp, *argv[50]; 2161057Sbill 21712808Ssam if (!fake) { 21838070Smckusick flags = 0; 21938070Smckusick if (!strcmp(type, FSTAB_RO)) 22038070Smckusick flags |= M_RDONLY; 22138445Smckusick switch (mnttype) { 22238445Smckusick case MOUNT_UFS: 223*39131Smckusick if (options) 224*39131Smckusick getufsopts(options, &flags); 225*39131Smckusick if (mntopts) 226*39131Smckusick getufsopts(mntopts, &flags); 22738445Smckusick args.fspec = spec; 22838445Smckusick argp = (caddr_t)&args; 22938445Smckusick break; 23038632Smckusick 23138632Smckusick #ifdef NFS 23238445Smckusick case MOUNT_NFS: 233*39131Smckusick if (options) 234*39131Smckusick getnfsopts(options, &nfsargs, &opflags, 235*39131Smckusick &retrycnt); 236*39131Smckusick if (mntopts) 237*39131Smckusick getnfsopts(mntopts, &nfsargs, &opflags, 238*39131Smckusick &retrycnt); 23938632Smckusick if (argp = getnfsargs(spec, name, type)) 24038632Smckusick break; 24138632Smckusick return (1); 24238632Smckusick #endif /* NFS */ 24338632Smckusick 244*39131Smckusick #ifdef MFS 245*39131Smckusick case MOUNT_MFS: 246*39131Smckusick argv[0] = "memfs"; 247*39131Smckusick argc = 1; 248*39131Smckusick if (options) 249*39131Smckusick argc += getmfsopts(options, &argv[argc]); 250*39131Smckusick if (mntopts) 251*39131Smckusick argc += getmfsopts(mntopts, &argv[argc]); 252*39131Smckusick argv[argc++] = spec; 253*39131Smckusick argv[argc++] = name; 254*39131Smckusick if (i = vfork()) { 255*39131Smckusick if (i == -1) { 256*39131Smckusick perror("mount: vfork for memfs"); 257*39131Smckusick return (1); 258*39131Smckusick } 259*39131Smckusick if (waitpid(i, &status, 0) != -1 && 260*39131Smckusick WIFEXITED(status) && 261*39131Smckusick WEXITSTATUS(status) != 0) 262*39131Smckusick return (WEXITSTATUS(status)); 263*39131Smckusick spec = "memfs"; 264*39131Smckusick goto out; 265*39131Smckusick } 266*39131Smckusick execve(_PATH_MEMFS, argv, envp); 267*39131Smckusick perror(_PATH_MEMFS); 268*39131Smckusick exit (1); 269*39131Smckusick #endif /* MFS */ 270*39131Smckusick 27138632Smckusick default: 27238632Smckusick if (opflags & ISBGRND) 27338632Smckusick exit(1); 27438632Smckusick fprintf(stderr, "%d: unknown mount type\n", mnttype); 27538632Smckusick exit(1); 27638632Smckusick /* NOTREACHED */ 27738632Smckusick 27838445Smckusick }; 27938445Smckusick if (mount(mnttype, name, flags, argp)) { 28038445Smckusick if (opflags & ISBGRND) 28138445Smckusick exit(1); 28235339Sbostic fprintf(stderr, "%s on %s: ", spec, name); 28316669Ssam switch (errno) { 28416669Ssam case EMFILE: 28535339Sbostic fprintf(stderr, "Mount table full\n"); 28616669Ssam break; 28716669Ssam case EINVAL: 28835339Sbostic fprintf(stderr, "Bogus super block\n"); 28916669Ssam break; 29016669Ssam default: 29135339Sbostic perror((char *)NULL); 29235339Sbostic break; 29316669Ssam } 29435369Sbostic return(1); 2954460Sroot } 2964460Sroot } 29735339Sbostic 298*39131Smckusick out: 29912808Ssam if (verbose) 30038632Smckusick prmount(spec, name, type); 30135339Sbostic 30238445Smckusick if (opflags & ISBGRND) 30338445Smckusick exit(); 30438445Smckusick else 30538445Smckusick return(0); 3061057Sbill } 30735339Sbostic 30835339Sbostic static 30938632Smckusick prmount(spec, name, type) 31038632Smckusick char *spec, *name, *type; 31135339Sbostic { 31238632Smckusick register char *root; 31338632Smckusick 31438445Smckusick if (opflags & ISBGRND) 31538445Smckusick return; 31638632Smckusick /* 31738632Smckusick * trim trailing /'s and find last component of name 31838632Smckusick */ 31938632Smckusick for (root = index(spec, '\0'); *--root == '/';) 32038632Smckusick /* void */; 32138632Smckusick *++root = '\0'; 32238632Smckusick if (root = rindex(spec, '/')) 32338632Smckusick spec = root + 1; 32438632Smckusick printf("%s on %s", spec, name); 32538632Smckusick if (!strcmp(type, FSTAB_RO)) 32635339Sbostic printf("\t(read-only)"); 32738632Smckusick else if (!strcmp(type, FSTAB_RQ)) 32835339Sbostic printf("\t(with quotas)"); 32935339Sbostic printf("\n"); 33035339Sbostic } 33135339Sbostic 33235339Sbostic static 33338632Smckusick usage() 33435339Sbostic { 33538632Smckusick fprintf(stderr, "usage: mount [-afrw]\nor mount [-frw] special | node\nor mount [-frw] special node\n"); 33635339Sbostic exit(1); 33735339Sbostic } 33835339Sbostic 339*39131Smckusick getufsopts(options, flagp) 340*39131Smckusick char *options; 341*39131Smckusick long *flagp; 342*39131Smckusick { 343*39131Smckusick 344*39131Smckusick return; 345*39131Smckusick } 346*39131Smckusick 347*39131Smckusick #ifdef MFS 348*39131Smckusick getmfsopts(options, argv) 349*39131Smckusick char *options; 350*39131Smckusick char **argv; 351*39131Smckusick { 352*39131Smckusick register int argc = 0; 353*39131Smckusick register char *opt; 354*39131Smckusick char *strtok(); 355*39131Smckusick 356*39131Smckusick for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) { 357*39131Smckusick if (opt[0] != '-') 358*39131Smckusick continue; 359*39131Smckusick argv[argc++] = opt; 360*39131Smckusick if (opt[2] == '\0' || opt[2] != '=') 361*39131Smckusick continue; 362*39131Smckusick opt[2] = '\0'; 363*39131Smckusick argv[argc++] = &opt[3]; 364*39131Smckusick } 365*39131Smckusick return (argc); 366*39131Smckusick } 367*39131Smckusick #endif /* MFS */ 368*39131Smckusick 36938632Smckusick #ifdef NFS 370*39131Smckusick /* 371*39131Smckusick * Handle the getoption arg. 372*39131Smckusick * Essentially update "opflags", "retrycnt" and "nfsargs" 373*39131Smckusick */ 374*39131Smckusick getnfsopts(optarg, nfsargsp, opflagsp, retrycntp) 375*39131Smckusick char *optarg; 376*39131Smckusick struct nfs_args *nfsargsp; 377*39131Smckusick int *opflagsp; 378*39131Smckusick int *retrycntp; 379*39131Smckusick { 380*39131Smckusick register char *cp, *nextcp; 381*39131Smckusick int num; 382*39131Smckusick char *nump; 383*39131Smckusick 384*39131Smckusick cp = optarg; 385*39131Smckusick while (cp != NULL && *cp != '\0') { 386*39131Smckusick if ((nextcp = index(cp, ',')) != NULL) 387*39131Smckusick *nextcp++ = '\0'; 388*39131Smckusick if ((nump = index(cp, '=')) != NULL) { 389*39131Smckusick *nump++ = '\0'; 390*39131Smckusick num = atoi(nump); 391*39131Smckusick } else 392*39131Smckusick num = -1; 393*39131Smckusick /* 394*39131Smckusick * Just test for a string match and do it 395*39131Smckusick */ 396*39131Smckusick if (!strcmp(cp, "bg")) { 397*39131Smckusick *opflagsp |= BGRND; 398*39131Smckusick } else if (!strcmp(cp, "soft")) { 399*39131Smckusick nfsargsp->flags |= NFSMNT_SOFT; 400*39131Smckusick } else if (!strcmp(cp, "intr")) { 401*39131Smckusick nfsargsp->flags |= NFSMNT_INT; 402*39131Smckusick } else if (!strcmp(cp, "retry") && num > 0) { 403*39131Smckusick *retrycntp = num; 404*39131Smckusick } else if (!strcmp(cp, "rsize") && num > 0) { 405*39131Smckusick nfsargsp->rsize = num; 406*39131Smckusick nfsargsp->flags |= NFSMNT_RSIZE; 407*39131Smckusick } else if (!strcmp(cp, "wsize") && num > 0) { 408*39131Smckusick nfsargsp->wsize = num; 409*39131Smckusick nfsargsp->flags |= NFSMNT_WSIZE; 410*39131Smckusick } else if (!strcmp(cp, "timeo") && num > 0) { 411*39131Smckusick nfsargsp->timeo = num; 412*39131Smckusick nfsargsp->flags |= NFSMNT_TIMEO; 413*39131Smckusick } else if (!strcmp(cp, "retrans") && num > 0) { 414*39131Smckusick nfsargsp->retrans = num; 415*39131Smckusick nfsargsp->flags |= NFSMNT_RETRANS; 416*39131Smckusick } 417*39131Smckusick cp = nextcp; 418*39131Smckusick } 419*39131Smckusick } 420*39131Smckusick 42138632Smckusick char * 42238632Smckusick getnfsargs(spec) 42338632Smckusick char *spec; 42435339Sbostic { 42538632Smckusick register CLIENT *clp; 42638632Smckusick struct hostent *hp; 42738632Smckusick struct sockaddr_in saddr; 42838632Smckusick struct timeval pertry, try; 42938632Smckusick enum clnt_stat clnt_stat; 43038632Smckusick int so = RPC_ANYSOCK; 43138632Smckusick char *hostp, *delimp; 43238632Smckusick u_short tport; 43338632Smckusick struct nfhret nfhret; 43438632Smckusick char nam[MNAMELEN + 1]; 43538632Smckusick 43638632Smckusick strncpy(nam, spec, MNAMELEN); 43738632Smckusick nam[MNAMELEN] = '\0'; 43838632Smckusick if ((delimp = index(spec, '@')) != NULL) { 43938632Smckusick hostp = delimp + 1; 44038632Smckusick } else if ((delimp = index(spec, ':')) != NULL) { 44138632Smckusick hostp = spec; 44238632Smckusick spec = delimp + 1; 44338632Smckusick } else { 44438632Smckusick fprintf(stderr, 44538632Smckusick "No <host>:<dirpath> or <dirpath>@<host> spec\n"); 44638632Smckusick return (0); 44738632Smckusick } 44838632Smckusick *delimp = '\0'; 44938632Smckusick if ((hp = gethostbyname(hostp)) == NULL) { 45038632Smckusick fprintf(stderr, "Can't get net id for host\n"); 45138632Smckusick return (0); 45238632Smckusick } 45338632Smckusick bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length); 45438632Smckusick nfhret.stat = EACCES; /* Mark not yet successful */ 45538632Smckusick while (retrycnt > 0) { 45638632Smckusick saddr.sin_family = AF_INET; 45738632Smckusick saddr.sin_port = htons(PMAPPORT); 45838632Smckusick if ((tport = pmap_getport(&saddr, RPCPROG_NFS, 45938632Smckusick NFS_VER2, IPPROTO_UDP)) == 0) { 46038632Smckusick if ((opflags & ISBGRND) == 0) 46138632Smckusick clnt_pcreateerror("NFS Portmap"); 46238632Smckusick } else { 46338632Smckusick saddr.sin_port = 0; 46438632Smckusick pertry.tv_sec = 10; 46538632Smckusick pertry.tv_usec = 0; 46638632Smckusick if ((clp = clntudp_create(&saddr, RPCPROG_MNT, 46738632Smckusick RPCMNT_VER1, pertry, &so)) == NULL) { 46838632Smckusick if ((opflags & ISBGRND) == 0) 46938632Smckusick clnt_pcreateerror("Cannot MNT PRC"); 47038632Smckusick } else { 47138632Smckusick clp->cl_auth = authunix_create_default(); 47238632Smckusick try.tv_sec = 10; 47338632Smckusick try.tv_usec = 0; 47438632Smckusick clnt_stat = clnt_call(clp, RPCMNT_MOUNT, 47538632Smckusick xdr_dir, spec, xdr_fh, &nfhret, try); 47638632Smckusick if (clnt_stat != RPC_SUCCESS) { 47738632Smckusick if ((opflags & ISBGRND) == 0) 47838632Smckusick clnt_perror(clp, "Bad MNT RPC"); 47938632Smckusick } else { 48038632Smckusick auth_destroy(clp->cl_auth); 48138632Smckusick clnt_destroy(clp); 48238632Smckusick retrycnt = 0; 48338632Smckusick } 48438632Smckusick } 48538632Smckusick } 48638632Smckusick if (--retrycnt > 0) { 48738632Smckusick if (opflags & BGRND) { 48838632Smckusick opflags &= ~BGRND; 48938632Smckusick if (fork()) 49038632Smckusick return (0); 49138632Smckusick else 49238632Smckusick opflags |= ISBGRND; 49338632Smckusick } 49438632Smckusick sleep(10); 49538632Smckusick } 49638632Smckusick } 49738632Smckusick if (nfhret.stat) { 49838632Smckusick if (opflags & ISBGRND) 49938632Smckusick exit(1); 50038632Smckusick fprintf(stderr, "Can't access %s, errno=%d\n", spec, 50138632Smckusick nfhret.stat); 50238632Smckusick return (0); 50338632Smckusick } 50438632Smckusick saddr.sin_port = htons(tport); 50538632Smckusick nfsargs.addr = &saddr; 50638632Smckusick nfsargs.fh = &nfhret.nfh; 50738632Smckusick nfsargs.hostname = nam; 50838632Smckusick return ((caddr_t)&nfsargs); 50935339Sbostic } 51038445Smckusick 51138445Smckusick /* 51238445Smckusick * xdr routines for mount rpc's 51338445Smckusick */ 51438445Smckusick xdr_dir(xdrsp, dirp) 51538445Smckusick XDR *xdrsp; 51638445Smckusick char *dirp; 51738445Smckusick { 51838445Smckusick return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 51938445Smckusick } 52038445Smckusick 52138445Smckusick xdr_fh(xdrsp, np) 52238445Smckusick XDR *xdrsp; 52338445Smckusick struct nfhret *np; 52438445Smckusick { 52538445Smckusick if (!xdr_u_long(xdrsp, &(np->stat))) 52638445Smckusick return (0); 52738445Smckusick if (np->stat) 52838445Smckusick return (1); 52938445Smckusick return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH)); 53038445Smckusick } 53138632Smckusick #endif /* NFS */ 532