NFSv2/usr/src/etc/mount.c

Compare this file to the similar file:
Show the results in this format:

#ifndef lint
static  char sccsid[] = "@(#)mount.c 1.1 85/05/30 Copyr 1985 Sun Micro";
#endif

/*
 * Copyright (c) 1985 Sun Microsystems, Inc.
 */

/*
 * mount
 */
#include <sys/param.h>
#include <rpc/rpc.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <nfs/nfs.h>
#include <rpcsvc/mount.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netdb.h>
#include <stdio.h>
#include <mntent.h>

int	ro = 0;
int	hard = 1;
int	quota = 0;
int	fake = 0;
int	freq = 1;
int	passno = 2;
int	all = 0;
int	verbose = 0;

#define MAXSLEEP 15  /* in seconds */

extern int errno;

char	*index(), *rindex();
char	host[MNTMAXSTR];
char	name[MNTMAXSTR];
char	dir[MNTMAXSTR];
char	type[MNTMAXSTR];
char	opts[MNTMAXSTR];

main(argc, argv)
	int argc;
	char **argv;
{
	struct mntent mnt;
	struct mntent *mntp;
	FILE *mnttab;
	char *options;
	char *colon;

	if (argc == 1) {
		mnttab = setmntent(MOUNTED, "r");
		while ((mntp = getmntent(mnttab)) != NULL) {
			if (strcmp(mntp->mnt_type, MNTTYPE_IGNORE) == 0) {
				continue;
			}
			printent(mntp);
		}
		endmntent(mnttab);
		exit(0);
	}

	/*
	 * Set options
	 */
	while (argc > 1 && argv[1][0] == '-') {
		options = &argv[1][1];
		while (*options) {
			switch (*options) {
			case 'a':
				all++;
				break;
			case 'f':
				fake++;
				break;
			case 'o':
				if (argc < 3) {
					usage();
				}
				strcpy(opts, argv[2]);
				argv++;
				argc--;
				break;
			case 'p':
				if (argc != 2) {
					usage();
				}
				mnttab = setmntent(MOUNTED, "r");
				while ((mntp = getmntent(mnttab)) != NULL) {
					prtmntent(stdout, mntp);
				}
				endmntent(mnttab);
				exit(0);
			case 'q':
				quota++;
				break;
			case 'r':
				ro++;
				break;
			case 't':
				if (argc < 3) {
					usage();
				}
				strcpy(type, argv[2]);
				argv++;
				argc--;
				break;
			case 'v':
				verbose++;
				break;
			default:
				fprintf(stderr, "mount: unknown option: %c\n",
				    *options);
				usage();
			}
			options++;
		}
		argc--, argv++;
	}
	if (all) {
		if (argc != 1) {
			usage();
		}
		mnttab = setmntent(MNTTAB, "r");
		if (mnttab == NULL) {
			fprintf(stderr, "mount: ");
			perror(MNTTAB);
			exit(1);
		}
		while ((mntp = getmntent(mnttab)) != NULL) {
			if ((strcmp(mntp->mnt_type, MNTTYPE_IGNORE) == 0) ||
			    (strcmp(mntp->mnt_type, MNTTYPE_SWAP) == 0) ||
			    (strcmp(mntp->mnt_dir, "/") == 0) ) {
				continue;
			}
			if (type[0] != '\0' &&
			    strcmp(mntp->mnt_type, type) != 0) {
				continue;
			}
			mountfs(mntp);
		}
		exit(0);
	}

	/*
	 * Command looks like: mount <dev>|<dir>
	 * we walk through /etc/fstab til we match either fsname or dir.
	 */
	if (argc == 2) {
		mnttab = setmntent(MNTTAB, "r");
		if (mnttab == NULL) {
			fprintf(stderr, "mount: ");
			perror(MNTTAB);
			exit(1);
		}
		while ((mntp = getmntent(mnttab)) != NULL) {
			if ((strcmp(mntp->mnt_type, MNTTYPE_IGNORE) == 0) ||
			    (strcmp(mntp->mnt_type, MNTTYPE_SWAP) == 0) ) {
				continue;
			}
			if ((strcmp(mntp->mnt_fsname, argv[1]) == 0) ||
			    (strcmp(mntp->mnt_dir, argv[1]) == 0) ) {
				mountfs(mntp);
				exit(0);
			}
		}
		fprintf(stderr, "mount: %s not found in %s\n", argv[1], MNTTAB);
		exit(0);
	}

	if (argc != 3) {
		usage();
	}
	strcpy(dir, argv[2]);
	strcpy(name, argv[1]);

	/*
	 * Check for file system names of the form
	 *     host:path
	 * make these type nfs
	 */
	colon = index(name, ':');
	if (colon) {
		if (type[0] != '\0' && strcmp(type, "nfs") != 0) {
			fprintf(stderr,"%s: %s; must use type nfs\n",
			    "mount: remote file system", name);
			usage();
		}
		strcpy(type, MNTTYPE_NFS);
	}
	if (type[0] == '\0') {
		strcpy(type, MNTTYPE_42);		/* default type = 4.2 */
	}
	if (dir[0] != '/') {
		fprintf(stderr, "mount: directory path must begin with '/'\n");
		exit(1);
	}

	if (opts[0] == '\0') {
		strcpy(opts, ro ? MNTOPT_RO : MNTOPT_RW);
		strcat(opts, ",");
		strcat(opts, quota ? MNTOPT_QUOTA : MNTOPT_NOQUOTA);
		if (strcmp(type, MNTTYPE_NFS) == 0) {
			strcat(opts, ",");
			strcat(opts, hard ? MNTOPT_HARD : MNTOPT_SOFT);
		}
	}

	if (strcmp(type, MNTTYPE_NFS) == 0) {
		passno = 0;
		freq = 0;
	}

	mnt.mnt_fsname = name;
	mnt.mnt_dir = dir;
	mnt.mnt_type = type;
	mnt.mnt_opts = opts;
	mnt.mnt_freq = freq;
	mnt.mnt_passno = passno;
	mountfs(&mnt);
}

mountfs(mnt)
	struct mntent *mnt;
{
	int error;

	if (mounted(mnt)) {
		fprintf(stderr, "mount: %s already mounted\n",
		    mnt->mnt_fsname);
		return;
	}
	if (fake) {
		addtomtab(mnt);
		return;
	}
	if (strcmp(mnt->mnt_type, MNTTYPE_42) == 0) {
		error = mount_42(mnt);
	} else if (strcmp(mnt->mnt_type, MNTTYPE_NFS) == 0) {
		error = mount_nfs(mnt);
#ifdef PCFS
	} else if (strcmp(mnt->mnt_type, MNTTYPE_PC) == 0) {
		error = mount_pc(mnt);
#endif
	} else {
		fprintf(stderr,
		    "mount: unknown file system type %s\n",
		    mnt->mnt_type);
	}

	if (error) {
		fprintf(stderr, "mount: %s on ", mnt->mnt_fsname);
		perror(mnt->mnt_dir);
	}
}

mount_42(mnt)
	struct mntent *mnt;
{
	int ro;

	ro = (hasmntopt(mnt, MNTOPT_RO) == NULL) ? 0 : 1;
	if (mount(mnt->mnt_fsname, mnt->mnt_dir, ro) < 0) {
		return (1);
	}
	addtomtab(mnt);
	return (0);
}

mount_nfs(mnt)
	struct mntent *mnt;
{
	int ro;
	int hard;
	struct sockaddr_in sin;
	struct hostent *hp;
	struct fhstatus fhs;
	int err;
	char *cp;
	char *hostp = host;
	char *path;
	int s = -1;
	struct timeval timeout;
	CLIENT *client;
	enum clnt_stat rpc_stat;
	struct stat sb;
	int printed1 = 0;
	int printed2 = 0;
	int bkg = 0;
	unsigned winks = 0;  /* seconds of sleep time */

	cp = mnt->mnt_fsname;
	while ((*hostp = *cp) != ':') {
		if (*cp == '\0') {
			fprintf(stderr,
			    "mount: nfs file system; use host:path\n");
			return (1);
		}
		hostp++;
		cp++;
	}
	*hostp = '\0';
	path = ++cp;
	/*
	 * Get server's address
	 */
	if ((hp = gethostbyname(host)) == NULL) {
		/*
		 * XXX
		 * Failure may be due to yellow pages, try again
		 */
		if ((hp = gethostbyname(host)) == NULL) {
			fprintf(stderr,
			    "mount: %s not in hosts database\n", host);
			return (1);
		}
	}

	ro = (hasmntopt(mnt, MNTOPT_RO) == NULL) ? 0 : 1;
	hard = (hasmntopt(mnt, MNTOPT_HARD) == NULL) ? 0 : 1;

	/*
	 * get fhandle of remote path from server's mountd
	 */
	do {
		bzero(&sin, sizeof(sin));
		bcopy(hp->h_addr, (char *) & sin.sin_addr, hp->h_length);
		sin.sin_family = AF_INET;
		timeout.tv_usec = 0;
		timeout.tv_sec = 10;
		s = -1;
		do {
			if ((client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS,
			    timeout, &s)) == NULL) {
				sleep(winks);
				if (winks < MAXSLEEP)
					winks++;
				if (!printed1++) {
					fprintf(stderr,
					    "mount: %s server not responding",
					    mnt->mnt_fsname);
					clnt_pcreateerror("");
				}
				if (!hard && !bkg) {
					/*
					 * doing a soft mount, print a message
					 * and try forever in the background.
					 */
					fprintf(stderr,"mount: %s\n",
					  "retrying soft mount in background");
					switch (fork()) {
					case -1:
						perror("mount: cannot fork");
						return (1);
					case 0:
						/*
						 * CHILD: retry mount until it
						 * works
						 */
						bkg++;
						continue;
					default:
						/*
						 * PARENT: we are done, return
						 * ok status but don't update
						 * mtab.
						 */
						return (0);
					}
				}
			}
		} while (client == NULL);
		client->cl_auth = authunix_create_default();
		timeout.tv_usec = 0;
		timeout.tv_sec = 25;
		rpc_stat = clnt_call(client, MOUNTPROC_MNT, xdr_path, &path,
		    xdr_fhstatus, &fhs, timeout);
		if (rpc_stat != RPC_SUCCESS) {
			if (!printed2++) {
				fprintf(stderr,
				    "mount: %s server not responding",
				    mnt->mnt_fsname);
				clnt_perror(client, "");
			}
			if (!hard && !bkg) {
				/*
				 * doing a soft mount, print a message
				 * and try forever in the background.
				 */
				fprintf(stderr,
				  "mount: retrying soft mount in background\n");
				switch (fork()) {
				case -1:
					perror("mount: cannot fork");
					return (1);
				case 0:
					/*
					 * CHILD: retry mount until it
					 * works
					 */
					bkg++;
					continue;
				default:
					/*
					 * PARENT: we are done, return
					 * ok status but don't update
					 * mtab.
					 */
					return (0);
				}
			}
		}
		close(s);
		clnt_destroy(client);
	} while (rpc_stat == RPC_TIMEDOUT || fhs.fhs_status == ETIMEDOUT);

	if (rpc_stat != RPC_SUCCESS || fhs.fhs_status) {
		errno = fhs.fhs_status;
		if (errno == EACCES) {
			fprintf(stderr, "mount: not in export list for %s:%s\n",
			    host, path);
		}
		return (1);
	}
	if (printed1 || printed2) {
		fprintf(stderr, "mount: %s server ok\n", mnt->mnt_fsname);
	}

	/*
	 * remote mount the fhandle on the local path
	 */
	if (nfsmount(&sin, &fhs.fhs_fh, mnt->mnt_dir, ro, hard) < 0) {
		return (1);
	}
	addtomtab(mnt);
	if (bkg) {
		/*
		 * We are a forked off child left around to do this one
		 * mount, so now we are done, let's die.
		 */
		exit(0);
	}
	return (0);
}

#ifdef PCFS
mount_pc(mnt)
	struct mntent *mnt;
{
	int ro;

	ro = (hasmntopt(mnt, MNTOPT_RO) == NULL) ? 0 : 1;
	if (pcfs_mount(mnt->mnt_fsname, mnt->mnt_dir, ro) < 0) {
		return (1);
	}
	addtomtab(mnt);
	return (0);
}
#endif

printent(mnt)
	struct mntent *mnt;
{
	fprintf(stdout, "%s on %s type %s (%s)\n",
	    mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts);
}

prtmntent(mnttabp, mnt)
	FILE *mnttabp;
	register struct mntent *mnt;
{
	fprintf(mnttabp, "%-20.20s %-12s %-6.6s %-16.16s %d %d\n",
	    mnt->mnt_fsname,
	    mnt->mnt_dir,
	    mnt->mnt_type,
	    mnt->mnt_opts,
	    mnt->mnt_freq,
	    mnt->mnt_passno);
	return (0);
}

/*
 * Check to see if mntck is already mounted.
 * We have to be careful because getmntent modifies its static struct.
 */
mounted(mntck)
	struct mntent *mntck;
{
	int found = 0;
	struct mntent *mnt, mntsave;
	FILE *mnttab;

	mnttab = setmntent(MOUNTED, "r");
	if (mnttab == NULL) {
		fprintf(stderr, "mount: ");
		perror(MOUNTED);
		exit(1);
	}
	mntcp(mntck, &mntsave);
	while ((mnt = getmntent(mnttab)) != NULL) {
		if (strcmp(mnt->mnt_type, MNTTYPE_IGNORE) == 0) {
			continue;
		}
		if ((strcmp(mntsave.mnt_fsname, mnt->mnt_fsname) == 0) &&
		    (strcmp(mntsave.mnt_dir, mnt->mnt_dir) == 0) ) {
			found = 1;
			break;
		}
	}
	endmntent(mnttab);
	*mntck = mntsave;
	return (found);
}

mntcp(mnt1, mnt2)
	struct mntent *mnt1, *mnt2;
{
	static char fsname[128], dir[128], type[128], opts[128];

	mnt2->mnt_fsname = fsname;
	strcpy(fsname, mnt1->mnt_fsname);
	mnt2->mnt_dir = dir;
	strcpy(dir, mnt1->mnt_dir);
	mnt2->mnt_type = type;
	strcpy(type, mnt1->mnt_type);
	mnt2->mnt_opts = opts;
	strcpy(opts, mnt1->mnt_opts);
	mnt2->mnt_freq = mnt1->mnt_freq;
	mnt2->mnt_passno = mnt1->mnt_passno;
}

/*
 * update /etc/mtab
 */
addtomtab(mnt)
	struct mntent *mnt;
{
	FILE *mnted;

	mnted = setmntent(MOUNTED, "r+");
	if (mnted == NULL) {
		fprintf(stderr, "mount: ");
		perror(MOUNTED);
		exit(1);
	}
	if (addmntent(mnted, mnt)) {
		fprintf(stderr, "mount: ");
		perror(MOUNTED);
		exit(1);
	}
	endmntent(mnted);

	if (verbose) {
		fprintf(stdout, "%s mounted on %s\n",
		    mnt->mnt_fsname, mnt->mnt_dir);
	}
}

usage()
{
	fprintf(stderr,
	    "Usage: mount [-ravpfto [type|option]] ... [fsname] [dir]\n");
	exit(1);
}