xref: /csrg-svn/sbin/mount/mount.c (revision 38445)
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*38445Smckusick static char sccsid[] = "@(#)mount.c	5.9 (Berkeley) 07/11/89";
1521156Sdist #endif not lint
1621156Sdist 
1712808Ssam #include <sys/param.h>
1835339Sbostic #include <sys/file.h>
19*38445Smckusick #include <sys/time.h>
2010811Ssam #include <fstab.h>
2112808Ssam #include <mtab.h>
2216669Ssam #include <errno.h>
2335339Sbostic #include <stdio.h>
24*38445Smckusick #include <strings.h>
25*38445Smckusick #include <sys/dir.h>
26*38445Smckusick #include <sys/uio.h>
27*38445Smckusick #include <sys/namei.h>
28*38445Smckusick #include <sys/mount.h>
29*38445Smckusick #ifdef NFS
30*38445Smckusick #include <sys/socket.h>
31*38445Smckusick #include <sys/socketvar.h>
32*38445Smckusick #include <netdb.h>
33*38445Smckusick #include <rpc/rpc.h>
34*38445Smckusick #include <rpc/pmap_clnt.h>
35*38445Smckusick #include <rpc/pmap_prot.h>
36*38445Smckusick #include <nfs/rpcv2.h>
37*38445Smckusick #include <nfs/nfsv2.h>
38*38445Smckusick #include <nfs/nfs.h>
39*38445Smckusick #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 
4735339Sbostic #define	MTAB	"/etc/mtab"
481057Sbill 
4935339Sbostic static struct mtab mtab[NMOUNT];
50*38445Smckusick static int fake, verbose, mnttype;
51*38445Smckusick #ifdef NFS
52*38445Smckusick int xdr_dir(), xdr_fh();
53*38445Smckusick struct nfs_args nfsargs = {
54*38445Smckusick 	(struct sockaddr_in *)0,
55*38445Smckusick 	(nfsv2fh_t *)0,
56*38445Smckusick 	0,
57*38445Smckusick 	NFS_WSIZE,
58*38445Smckusick 	NFS_RSIZE,
59*38445Smckusick 	NFS_TIMEO,
60*38445Smckusick 	NFS_RETRANS,
61*38445Smckusick 	(char *)0,
62*38445Smckusick };
635073Sroot 
64*38445Smckusick struct nfhret {
65*38445Smckusick 	u_long	stat;
66*38445Smckusick 	nfsv2fh_t nfh;
67*38445Smckusick };
68*38445Smckusick int retrycnt = 10000;
69*38445Smckusick #define	BGRND	1
70*38445Smckusick #define	ISBGRND	2
71*38445Smckusick int opflags = 0;
72*38445Smckusick #endif
73*38445Smckusick 
741057Sbill main(argc, argv)
755073Sroot 	int argc;
765073Sroot 	char **argv;
771057Sbill {
7835339Sbostic 	extern char *optarg;
7935339Sbostic 	extern int optind;
801057Sbill 	register struct mtab *mp;
8135339Sbostic 	register struct fstab *fs;
8235339Sbostic 	register int cnt;
8335372Sbostic 	int all, ch, fd, rval, sfake;
8435339Sbostic 	char *type;
851057Sbill 
8635339Sbostic 	all = 0;
8735339Sbostic 	type = NULL;
88*38445Smckusick 	mnttype = MOUNT_UFS;
89*38445Smckusick 	while ((ch = getopt(argc, argv, "afrwvt:o:")) != EOF)
9035339Sbostic 		switch((char)ch) {
9135339Sbostic 		case 'a':
9235339Sbostic 			all = 1;
9335339Sbostic 			break;
9435339Sbostic 		case 'f':
9535339Sbostic 			fake = 1;
9635339Sbostic 			break;
9735339Sbostic 		case 'r':
9812808Ssam 			type = FSTAB_RO;
9935339Sbostic 			break;
10035339Sbostic 		case 'v':
10135339Sbostic 			verbose = 1;
10235339Sbostic 			break;
10335339Sbostic 		case 'w':
10435339Sbostic 			type = FSTAB_RW;
10535339Sbostic 			break;
106*38445Smckusick #ifdef NFS
107*38445Smckusick 		case 't':
108*38445Smckusick 			if (!strcmp(optarg, "nfs"))
109*38445Smckusick 				mnttype = MOUNT_NFS;
110*38445Smckusick 			break;
111*38445Smckusick 		case 'o':
112*38445Smckusick 			getoptions(optarg,&nfsargs,&opflags,&retrycnt);
113*38445Smckusick 			break;
114*38445Smckusick #endif
11535339Sbostic 		case '?':
11635339Sbostic 		default:
11735339Sbostic 			usage();
1185073Sroot 		}
11935339Sbostic 	argc -= optind;
12035339Sbostic 	argv += optind;
12135339Sbostic 
12235339Sbostic 	/* NOSTRICT */
12335339Sbostic 	if ((fd = open(MTAB, O_RDONLY, 0)) >= 0) {
12435339Sbostic 		if (read(fd, (char *)mtab, NMOUNT * sizeof(struct mtab)) < 0)
12535339Sbostic 			mtaberr();
12635339Sbostic 		(void)close(fd);
1271057Sbill 	}
12835339Sbostic 
1294460Sroot 	if (all) {
13035369Sbostic 		rval = 0;
13135372Sbostic 		for (sfake = fake; fs = getfsent(); fake = sfake) {
13235372Sbostic 			if (BADTYPE(fs->fs_type))
13335372Sbostic 				continue;
13435372Sbostic 			/* `/' is special, it's always mounted */
13535372Sbostic 			if (!strcmp(fs->fs_file, "/"))
13635372Sbostic 				fake = 1;
137*38445Smckusick #ifdef NFS
138*38445Smckusick 			if (index(fs->fs_spec, '@') != NULL) {
139*38445Smckusick 				if (fs->fs_vfstype != NULL &&
140*38445Smckusick 				    strcmp(fs->fs_vfstype, "nfs"))
141*38445Smckusick 					continue;
142*38445Smckusick 				if (fs->fs_mntops != NULL)
143*38445Smckusick 					getoptions(fs->fs_mntops, &nfsargs,
144*38445Smckusick 						&opflags, &retrycnt);
145*38445Smckusick 				mnttype = MOUNT_NFS;
146*38445Smckusick 			} else
147*38445Smckusick 				mnttype = MOUNT_UFS;
148*38445Smckusick #endif
14935372Sbostic 			rval |= mountfs(fs->fs_spec, fs->fs_file,
15035372Sbostic 			    type ? type : fs->fs_type);
15135372Sbostic 		}
15235341Sbostic 		exit(rval);
15335339Sbostic 	}
1545073Sroot 
15535339Sbostic 	if (argc == 0) {
15635339Sbostic 		if (verbose || fake || type)
15735339Sbostic 			usage();
15835339Sbostic 		for (mp = mtab, cnt = NMOUNT; cnt--; ++mp)
15935339Sbostic 			if (*mp->m_path)
16035339Sbostic 				prmtab(mp);
1614460Sroot 		exit(0);
1621057Sbill 	}
16312808Ssam 
16435339Sbostic 	if (all)
16535339Sbostic 		usage();
16635339Sbostic 
16735339Sbostic 	if (argc == 1) {
16835339Sbostic 		if (!(fs = getfsfile(*argv)) && !(fs = getfsspec(*argv))) {
16935339Sbostic 			fprintf(stderr,
17035339Sbostic 			    "mount: unknown special file or file system %s.\n",
17135339Sbostic 			    *argv);
17235339Sbostic 			exit(1);
17335339Sbostic 		}
17435339Sbostic 		if (BADTYPE(fs->fs_type)) {
17535339Sbostic 			fprintf(stderr,
17635339Sbostic 			    "mount: %s has unknown file system type.\n", *argv);
17735339Sbostic 			exit(1);
17835339Sbostic 		}
17935369Sbostic 		exit(mountfs(fs->fs_spec, fs->fs_file,
18035369Sbostic 		    type ? type : fs->fs_type));
18112808Ssam 	}
1821057Sbill 
18335339Sbostic 	if (argc != 2)
18435339Sbostic 		usage();
18512808Ssam 
18635369Sbostic 	exit(mountfs(argv[0], argv[1], type ? type : "rw"));
18712808Ssam }
18812808Ssam 
18935339Sbostic static
19012808Ssam mountfs(spec, name, type)
19112808Ssam 	char *spec, *name, *type;
19212808Ssam {
19335339Sbostic 	extern int errno;
19435339Sbostic 	register struct mtab *mp, *space;
19535339Sbostic 	register int cnt;
19635339Sbostic 	register char *p;
197*38445Smckusick #ifdef NFS
198*38445Smckusick 	register CLIENT *clp;
199*38445Smckusick 	struct hostent *hp;
200*38445Smckusick 	struct sockaddr_in saddr;
201*38445Smckusick 	struct timeval pertry, try;
202*38445Smckusick 	enum clnt_stat clnt_stat;
203*38445Smckusick 	int so = RPC_ANYSOCK;
204*38445Smckusick 	char *hostp, *delimp;
205*38445Smckusick 	u_short tport;
206*38445Smckusick 	struct nfhret nfhret;
207*38445Smckusick 	char nam[MNAMELEN+1];
208*38445Smckusick #endif
20938070Smckusick 	int fd, flags;
21038070Smckusick 	struct ufs_args args;
211*38445Smckusick 	char *argp;
2121057Sbill 
21312808Ssam 	if (!fake) {
21438070Smckusick 		flags = 0;
21538070Smckusick 		if (!strcmp(type, FSTAB_RO))
21638070Smckusick 			flags |= M_RDONLY;
217*38445Smckusick #ifdef NFS
218*38445Smckusick 		switch (mnttype) {
219*38445Smckusick 		case MOUNT_UFS:
220*38445Smckusick 			args.fspec = spec;
221*38445Smckusick 			argp = (caddr_t)&args;
222*38445Smckusick 			break;
223*38445Smckusick 		case MOUNT_NFS:
224*38445Smckusick 			strncpy(nam, spec, MNAMELEN);
225*38445Smckusick 			nam[MNAMELEN] = '\0';
226*38445Smckusick 			if ((delimp = index(spec, '@')) != NULL) {
227*38445Smckusick 				hostp = delimp+1;
228*38445Smckusick 			} else if ((delimp = index(spec, ':')) != NULL) {
229*38445Smckusick 				hostp = spec;
230*38445Smckusick 				spec = delimp+1;
231*38445Smckusick 			} else {
232*38445Smckusick 				fprintf(stderr, "No <host>:<dirpath> or <dirpath>@<host> spec\n");
233*38445Smckusick 				return (1);
234*38445Smckusick 			}
235*38445Smckusick 			*delimp = '\0';
236*38445Smckusick 			if ((hp = gethostbyname(hostp)) == NULL) {
237*38445Smckusick 				fprintf(stderr,"Can't get net id for host\n");
238*38445Smckusick 				return (1);
239*38445Smckusick 			}
240*38445Smckusick 			bcopy(hp->h_addr,(caddr_t)&saddr.sin_addr,hp->h_length);
241*38445Smckusick 			nfhret.stat = EACCES;	/* Mark not yet successful */
242*38445Smckusick 			while (retrycnt > 0) {
243*38445Smckusick 				saddr.sin_family = AF_INET;
244*38445Smckusick 				saddr.sin_port = htons(PMAPPORT);
245*38445Smckusick 				if ((tport = pmap_getport(&saddr, RPCPROG_NFS,
246*38445Smckusick 					NFS_VER2, IPPROTO_UDP)) == 0) {
247*38445Smckusick 					if ((opflags & ISBGRND) == 0)
248*38445Smckusick 						clnt_pcreateerror("NFS Portmap");
249*38445Smckusick 				} else {
250*38445Smckusick 					saddr.sin_port = 0;
251*38445Smckusick 					pertry.tv_sec = 10;
252*38445Smckusick 					pertry.tv_usec = 0;
253*38445Smckusick 					if ((clp = clntudp_create(&saddr, RPCPROG_MNT,
254*38445Smckusick 						RPCMNT_VER1, pertry, &so)) == NULL) {
255*38445Smckusick 						if ((opflags & ISBGRND) == 0)
256*38445Smckusick 							clnt_pcreateerror("Cannot MNT PRC");
257*38445Smckusick 					} else {
258*38445Smckusick 						clp->cl_auth = authunix_create_default();
259*38445Smckusick 						try.tv_sec = 10;
260*38445Smckusick 						try.tv_usec = 0;
261*38445Smckusick 						clnt_stat = clnt_call(clp, RPCMNT_MOUNT, xdr_dir, spec,
262*38445Smckusick 							xdr_fh, &nfhret, try);
263*38445Smckusick 						if (clnt_stat != RPC_SUCCESS) {
264*38445Smckusick 							if ((opflags & ISBGRND) == 0)
265*38445Smckusick 								clnt_perror(clp, "Bad MNT RPC");
266*38445Smckusick 						} else {
267*38445Smckusick 							auth_destroy(clp->cl_auth);
268*38445Smckusick 							clnt_destroy(clp);
269*38445Smckusick 							retrycnt = 0;
270*38445Smckusick 						}
271*38445Smckusick 					}
272*38445Smckusick 				}
273*38445Smckusick 				if (--retrycnt > 0) {
274*38445Smckusick 					if (opflags & BGRND) {
275*38445Smckusick 						opflags &= ~BGRND;
276*38445Smckusick 						if (fork())
277*38445Smckusick 							return (0);
278*38445Smckusick 						else
279*38445Smckusick 							opflags |= ISBGRND;
280*38445Smckusick 					}
281*38445Smckusick 					sleep(10);
282*38445Smckusick 				}
283*38445Smckusick 			}
284*38445Smckusick 			if (nfhret.stat) {
285*38445Smckusick 				if (opflags & ISBGRND)
286*38445Smckusick 					exit(1);
287*38445Smckusick 				fprintf(stderr, "Can't access %s, errno=%d\n",
288*38445Smckusick 					spec, nfhret.stat);
289*38445Smckusick 				return (1);
290*38445Smckusick 			}
291*38445Smckusick 			saddr.sin_port = htons(tport);
292*38445Smckusick 			nfsargs.addr = &saddr;
293*38445Smckusick 			nfsargs.fh = &nfhret.nfh;
294*38445Smckusick 			nfsargs.hostname = nam;
295*38445Smckusick 			argp = (caddr_t)&nfsargs;
296*38445Smckusick 			break;
297*38445Smckusick 		};
298*38445Smckusick #endif
299*38445Smckusick 		if (mount(mnttype, name, flags, argp)) {
300*38445Smckusick 			if (opflags & ISBGRND)
301*38445Smckusick 				exit(1);
30235339Sbostic 			fprintf(stderr, "%s on %s: ", spec, name);
30316669Ssam 			switch (errno) {
30416669Ssam 			case EMFILE:
30535339Sbostic 				fprintf(stderr, "Mount table full\n");
30616669Ssam 				break;
30716669Ssam 			case EINVAL:
30835339Sbostic 				fprintf(stderr, "Bogus super block\n");
30916669Ssam 				break;
31016669Ssam 			default:
31135339Sbostic 				perror((char *)NULL);
31235339Sbostic 				break;
31316669Ssam 			}
31435369Sbostic 			return(1);
3154460Sroot 		}
31635339Sbostic 
31712808Ssam 		/* we don't do quotas.... */
31812808Ssam 		if (strcmp(type, FSTAB_RQ) == 0)
31912808Ssam 			type = FSTAB_RW;
3204460Sroot 	}
32135339Sbostic 
32235339Sbostic 	/* trim trailing /'s and find last component of name */
32335339Sbostic 	for (p = index(spec, '\0'); *--p == '/';);
32435339Sbostic 	*++p = '\0';
32535339Sbostic 	if (p = rindex(spec, '/')) {
32635339Sbostic 		*p = '\0';
32735339Sbostic 		spec = p + 1;
32812808Ssam 	}
32935339Sbostic 
33035339Sbostic 	for (mp = mtab, cnt = NMOUNT, space = NULL; cnt--; ++mp) {
33135339Sbostic 		if (!strcmp(mp->m_dname, spec))
33235339Sbostic 			break;
33335339Sbostic 		if (!space && !*mp->m_path)
33435339Sbostic 			space = mp;
33535339Sbostic 	}
33635339Sbostic 	if (cnt == -1) {
33735339Sbostic 		if (!space) {
338*38445Smckusick 			if ((opflags & ISBGRND) == 0)
339*38445Smckusick 				fprintf(stderr, "mount: no more room in %s.\n", MTAB);
34035339Sbostic 			exit(1);
34135339Sbostic 		}
34235339Sbostic 		mp = space;
34335339Sbostic 	}
34435339Sbostic 
34535339Sbostic #define	DNMAX	(sizeof(mtab[0].m_dname) - 1)
34635339Sbostic #define	PNMAX	(sizeof(mtab[0].m_path) - 1)
34735339Sbostic 
34835339Sbostic 	(void)strncpy(mp->m_dname, spec, DNMAX);
34912808Ssam 	mp->m_dname[DNMAX] = '\0';
35035339Sbostic 	(void)strncpy(mp->m_path, name, PNMAX);
35112808Ssam 	mp->m_path[PNMAX] = '\0';
35235339Sbostic 	(void)strcpy(mp->m_type, type);
35335339Sbostic 
35412808Ssam 	if (verbose)
35512808Ssam 		prmtab(mp);
35635339Sbostic 
35735339Sbostic 	for (mp = mtab + NMOUNT - 1; mp > mtab && !*mp->m_path; --mp);
35835339Sbostic 	if ((fd = open(MTAB, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0)
35935339Sbostic 		mtaberr();
36035339Sbostic 	cnt = (mp - mtab + 1) * sizeof(struct mtab);
36135339Sbostic 	/* NOSTRICT */
36235339Sbostic 	if (write(fd, (char *)mtab, cnt) != cnt)
36335339Sbostic 		mtaberr();
36435339Sbostic 	(void)close(fd);
365*38445Smckusick 	if (opflags & ISBGRND)
366*38445Smckusick 		exit();
367*38445Smckusick 	else
368*38445Smckusick 		return(0);
3691057Sbill }
37035339Sbostic 
37135339Sbostic static
37235339Sbostic prmtab(mp)
37335339Sbostic 	register struct mtab *mp;
37435339Sbostic {
375*38445Smckusick 	if (opflags & ISBGRND)
376*38445Smckusick 		return;
37735339Sbostic 	printf("%s on %s", mp->m_dname, mp->m_path);
37835339Sbostic 	if (!strcmp(mp->m_type, FSTAB_RO))
37935339Sbostic 		printf("\t(read-only)");
38035339Sbostic 	else if (!strcmp(mp->m_type, FSTAB_RQ))
38135339Sbostic 		printf("\t(with quotas)");
38235339Sbostic 	printf("\n");
38335339Sbostic }
38435339Sbostic 
38535339Sbostic static
38635339Sbostic mtaberr()
38735339Sbostic {
388*38445Smckusick 	if (opflags & ISBGRND)
389*38445Smckusick 		exit(1);
39035339Sbostic 	fprintf(stderr, "mount: %s: ", MTAB);
39135339Sbostic 	perror((char *)NULL);
39235339Sbostic 	exit(1);
39335339Sbostic }
39435339Sbostic 
39535339Sbostic static
39635339Sbostic usage()
39735339Sbostic {
39835369Sbostic 	fprintf(stderr, "usage: mount [-afrw]\nor mount [-frw] special | node\nor mount [-frw] special node\n");
39935339Sbostic 	exit(1);
40035339Sbostic }
401*38445Smckusick 
402*38445Smckusick #ifdef NFS
403*38445Smckusick /*
404*38445Smckusick  * xdr routines for mount rpc's
405*38445Smckusick  */
406*38445Smckusick xdr_dir(xdrsp, dirp)
407*38445Smckusick 	XDR *xdrsp;
408*38445Smckusick 	char *dirp;
409*38445Smckusick {
410*38445Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
411*38445Smckusick }
412*38445Smckusick 
413*38445Smckusick xdr_fh(xdrsp, np)
414*38445Smckusick 	XDR *xdrsp;
415*38445Smckusick 	struct nfhret *np;
416*38445Smckusick {
417*38445Smckusick 	if (!xdr_u_long(xdrsp, &(np->stat)))
418*38445Smckusick 		return (0);
419*38445Smckusick 	if (np->stat)
420*38445Smckusick 		return (1);
421*38445Smckusick 	return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH));
422*38445Smckusick }
423*38445Smckusick 
424*38445Smckusick /*
425*38445Smckusick  * Handle the getoption arg.
426*38445Smckusick  * Essentially update "opflags", "retrycnt" and "nfsargs"
427*38445Smckusick  */
428*38445Smckusick getoptions(optarg, nfsargsp, opflagsp, retrycntp)
429*38445Smckusick 	char *optarg;
430*38445Smckusick 	struct nfs_args *nfsargsp;
431*38445Smckusick 	int *opflagsp;
432*38445Smckusick 	int *retrycntp;
433*38445Smckusick {
434*38445Smckusick 	register char *cp, *nextcp;
435*38445Smckusick 	int num;
436*38445Smckusick 	char *nump;
437*38445Smckusick 
438*38445Smckusick 	cp = optarg;
439*38445Smckusick 	while (cp != NULL && *cp != '\0') {
440*38445Smckusick 		if ((nextcp = index(cp, ',')) != NULL)
441*38445Smckusick 			*nextcp++ = '\0';
442*38445Smckusick 		if ((nump = index(cp, '=')) != NULL) {
443*38445Smckusick 			*nump++ = '\0';
444*38445Smckusick 			num = atoi(nump);
445*38445Smckusick 		} else
446*38445Smckusick 			num = -1;
447*38445Smckusick 		/*
448*38445Smckusick 		 * Just test for a string match and do it
449*38445Smckusick 		 */
450*38445Smckusick 		if (!strcmp(cp, "bg")) {
451*38445Smckusick 			*opflagsp |= BGRND;
452*38445Smckusick 		} else if (!strcmp(cp, "soft")) {
453*38445Smckusick 			nfsargsp->flags |= NFSMNT_SOFT;
454*38445Smckusick 		} else if (!strcmp(cp, "intr")) {
455*38445Smckusick 			nfsargsp->flags |= NFSMNT_INT;
456*38445Smckusick 		} else if (!strcmp(cp, "retry") && num > 0) {
457*38445Smckusick 			*retrycntp = num;
458*38445Smckusick 		} else if (!strcmp(cp, "rsize") && num > 0) {
459*38445Smckusick 			nfsargsp->rsize = num;
460*38445Smckusick 			nfsargsp->flags |= NFSMNT_RSIZE;
461*38445Smckusick 		} else if (!strcmp(cp, "wsize") && num > 0) {
462*38445Smckusick 			nfsargsp->wsize = num;
463*38445Smckusick 			nfsargsp->flags |= NFSMNT_WSIZE;
464*38445Smckusick 		} else if (!strcmp(cp, "timeo") && num > 0) {
465*38445Smckusick 			nfsargsp->timeo = num;
466*38445Smckusick 			nfsargsp->flags |= NFSMNT_TIMEO;
467*38445Smckusick 		} else if (!strcmp(cp, "retrans") && num > 0) {
468*38445Smckusick 			nfsargsp->retrans = num;
469*38445Smckusick 			nfsargsp->flags |= NFSMNT_RETRANS;
470*38445Smckusick 		}
471*38445Smckusick 		cp = nextcp;
472*38445Smckusick 	}
473*38445Smckusick }
474*38445Smckusick #endif
475