xref: /onnv-gate/usr/src/cmd/fs.d/cachefs/mount/mount.c (revision 633:04519cb7de3b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*633Sgt29601  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
280Sstevel@tonic-gate /*	    All Rights Reserved */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
320Sstevel@tonic-gate  * under license from the Regents of the University of California.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  *
390Sstevel@tonic-gate  *			mount.c
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * Cachefs mount program.
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #include <locale.h>
450Sstevel@tonic-gate #include <stdio.h>
460Sstevel@tonic-gate #include <stdlib.h>
470Sstevel@tonic-gate #include <string.h>
480Sstevel@tonic-gate #include <strings.h>
490Sstevel@tonic-gate #include <stdarg.h>
500Sstevel@tonic-gate #include <unistd.h>
510Sstevel@tonic-gate #include <limits.h>
520Sstevel@tonic-gate #include <errno.h>
530Sstevel@tonic-gate #include <wait.h>
540Sstevel@tonic-gate #include <ctype.h>
550Sstevel@tonic-gate #include <fcntl.h>
560Sstevel@tonic-gate #include <fslib.h>
570Sstevel@tonic-gate #include <sys/types.h>
580Sstevel@tonic-gate #include <sys/time.h>
590Sstevel@tonic-gate #include <sys/param.h>
600Sstevel@tonic-gate #include <sys/stat.h>
610Sstevel@tonic-gate #include <sys/fcntl.h>
620Sstevel@tonic-gate #include <sys/mount.h>
630Sstevel@tonic-gate #include <sys/mntent.h>
640Sstevel@tonic-gate #include <sys/mnttab.h>
650Sstevel@tonic-gate #include <sys/mntio.h>
660Sstevel@tonic-gate #include <sys/fs/cachefs_fs.h>
670Sstevel@tonic-gate #include <sys/utsname.h>
680Sstevel@tonic-gate #include <rpc/rpc.h>
690Sstevel@tonic-gate #include <kstat.h>
700Sstevel@tonic-gate #undef MAX
710Sstevel@tonic-gate #include <nfs/nfs.h>
720Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
730Sstevel@tonic-gate #include <sys/mkdev.h>
740Sstevel@tonic-gate #include "../common/subr.h"
750Sstevel@tonic-gate #include "../common/cachefsd.h"
760Sstevel@tonic-gate 
770Sstevel@tonic-gate char *cfs_opts[] = {
780Sstevel@tonic-gate #define	CFSOPT_BACKFSTYPE	0
790Sstevel@tonic-gate 	"backfstype",
800Sstevel@tonic-gate #define	CFSOPT_CACHEDIR		1
810Sstevel@tonic-gate 	"cachedir",
820Sstevel@tonic-gate #define	CFSOPT_CACHEID		2
830Sstevel@tonic-gate 	"cacheid",
840Sstevel@tonic-gate #define	CFSOPT_BACKPATH		3
850Sstevel@tonic-gate 	"backpath",
860Sstevel@tonic-gate 
870Sstevel@tonic-gate #define	CFSOPT_WRITEAROUND	4
880Sstevel@tonic-gate 	"write-around",
890Sstevel@tonic-gate #define	CFSOPT_NONSHARED	5
900Sstevel@tonic-gate 	"non-shared",
910Sstevel@tonic-gate 
920Sstevel@tonic-gate #define	CFSOPT_DISCONNECTABLE	6
930Sstevel@tonic-gate 	"disconnectable",
940Sstevel@tonic-gate #define	CFSOPT_SOFT		7
950Sstevel@tonic-gate 	"soft",
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #define	CFSOPT_NOCONST		8
980Sstevel@tonic-gate 	"noconst",
990Sstevel@tonic-gate #define	CFSOPT_CODCONST		9
1000Sstevel@tonic-gate 	"demandconst",
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate #define	CFSOPT_LOCALACCESS	10
1030Sstevel@tonic-gate 	"local-access",
1040Sstevel@tonic-gate #define	CFSOPT_LAZYMOUNT	11
1050Sstevel@tonic-gate 	"lazy-mount",
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate #define	CFSOPT_RW		12
1080Sstevel@tonic-gate 	"rw",
1090Sstevel@tonic-gate #define	CFSOPT_RO		13
1100Sstevel@tonic-gate 	"ro",
1110Sstevel@tonic-gate #define	CFSOPT_SUID		14
1120Sstevel@tonic-gate 	"suid",
1130Sstevel@tonic-gate #define	CFSOPT_NOSUID		15
1140Sstevel@tonic-gate 	"nosuid",
1150Sstevel@tonic-gate #define	CFSOPT_REMOUNT		16
1160Sstevel@tonic-gate 	"remount",
1170Sstevel@tonic-gate #define	CFSOPT_FGSIZE		17
1180Sstevel@tonic-gate 	"fgsize",
1190Sstevel@tonic-gate #define	CFSOPT_POPSIZE		18
1200Sstevel@tonic-gate 	"popsize",
1210Sstevel@tonic-gate #define	CFSOPT_ACREGMIN		19
1220Sstevel@tonic-gate 	"acregmin",
1230Sstevel@tonic-gate #define	CFSOPT_ACREGMAX		20
1240Sstevel@tonic-gate 	"acregmax",
1250Sstevel@tonic-gate #define	CFSOPT_ACDIRMIN		21
1260Sstevel@tonic-gate 	"acdirmin",
1270Sstevel@tonic-gate #define	CFSOPT_ACDIRMAX		22
1280Sstevel@tonic-gate 	"acdirmax",
1290Sstevel@tonic-gate #define	CFSOPT_ACTIMEO		23
1300Sstevel@tonic-gate 	"actimeo",
1310Sstevel@tonic-gate #define	CFSOPT_SLIDE		24
1320Sstevel@tonic-gate 	"slide",
1330Sstevel@tonic-gate #define	CFSOPT_NOSETSEC		25
1340Sstevel@tonic-gate 	"nosec",	/* XXX should we use MNTOPT_NOTSETSEC? */
1350Sstevel@tonic-gate #define	CFSOPT_LLOCK		26
1360Sstevel@tonic-gate 	"llock",
1370Sstevel@tonic-gate #define	CFSOPT_NONOTIFY		27
1380Sstevel@tonic-gate 	"nonotify",
1390Sstevel@tonic-gate #define	CFSOPT_SNR		28
1400Sstevel@tonic-gate 	"snr",
1410Sstevel@tonic-gate #define	CFSOPT_NOFILL		29
1420Sstevel@tonic-gate 	"nofill",
1430Sstevel@tonic-gate #ifdef CFS_NFSV3_PASSTHROUGH
1440Sstevel@tonic-gate #define	CFSOPT_NFSV3PASSTHROUGH	30
1450Sstevel@tonic-gate 	"nfsv3pass",
1460Sstevel@tonic-gate #endif /* CFS_NFSV3_PASSTHROUGH */
1470Sstevel@tonic-gate 	NULL
1480Sstevel@tonic-gate };
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate #define	MNTTYPE_CFS	"cachefs"	/* XXX - to be added to mntent.h */
1510Sstevel@tonic-gate 					/* XXX - and should be cachefs */
1520Sstevel@tonic-gate #define	CFS_DEF_DIR	"/cache"	/* XXX - should be added to cfs.h */
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate #define	bad(val) (val == NULL || !isdigit(*val))
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate #define	VFS_PATH	"/usr/lib/fs"
1570Sstevel@tonic-gate #define	ALT_PATH	"/etc/fs"
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate /* forward references */
1600Sstevel@tonic-gate void usage(char *msgp);
1610Sstevel@tonic-gate void pr_err(char *fmt, ...);
1620Sstevel@tonic-gate int set_cfs_args(char *optionp, struct cachefs_mountargs *margsp, int *mflagp,
1630Sstevel@tonic-gate     char **backfstypepp, char **reducepp, int *notifyp, int *nfsv3pass);
1640Sstevel@tonic-gate int get_mount_point(char *cachedirp, char *specp, char **pathpp);
1650Sstevel@tonic-gate int dobackmnt(struct cachefs_mountargs *margsp, char *reducep, char *specp,
1660Sstevel@tonic-gate     char *backfstypep, char *mynamep, int readonly);
1670Sstevel@tonic-gate void doexec(char *fstype, char **newargv, char *myname);
1680Sstevel@tonic-gate char *get_back_fsid(char *specp);
1690Sstevel@tonic-gate char *get_cacheid(char *, char *);
1700Sstevel@tonic-gate void record_mount(char *mntp, char *specp, char *backfsp, char *backfstypep,
1710Sstevel@tonic-gate     char *cachedirp, char *cacheidp, char *optionp, char *reducep);
1720Sstevel@tonic-gate int daemon_notify(char *cachedirp, char *cacheidp);
1730Sstevel@tonic-gate int pingserver(char *backmntp);
1740Sstevel@tonic-gate int check_cache(char *cachedirp);
1750Sstevel@tonic-gate uint32_t cachefs_get_back_nfsvers(char *cfs_backfs, int nomnttab);
1760Sstevel@tonic-gate int cfs_nfsv4_build_opts(char *optionp, char *cfs_nfsv4ops);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate int nomnttab;
1790Sstevel@tonic-gate int quiet;
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate  *
1820Sstevel@tonic-gate  *			main
1830Sstevel@tonic-gate  *
1840Sstevel@tonic-gate  * Description:
1850Sstevel@tonic-gate  *	Main routine for the cachefs mount program.
1860Sstevel@tonic-gate  * Arguments:
1870Sstevel@tonic-gate  *	argc	number of command line arguments
1880Sstevel@tonic-gate  *	argv	list of command line arguments
1890Sstevel@tonic-gate  * Returns:
1900Sstevel@tonic-gate  *	Returns 0 for success, 1 an error was encountered.
1910Sstevel@tonic-gate  * Preconditions:
1920Sstevel@tonic-gate  */
1930Sstevel@tonic-gate 
194*633Sgt29601 int
main(int argc,char ** argv)1950Sstevel@tonic-gate main(int argc, char **argv)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	char *myname;
1980Sstevel@tonic-gate 	char *optionp;
1990Sstevel@tonic-gate 	char *opigp;
2000Sstevel@tonic-gate 	int mflag;
2010Sstevel@tonic-gate 	int readonly;
2020Sstevel@tonic-gate 	struct cachefs_mountargs margs;
2030Sstevel@tonic-gate 	char *backfstypep;
2040Sstevel@tonic-gate 	char *reducep;
2050Sstevel@tonic-gate 	char *specp;
2060Sstevel@tonic-gate 	int xx;
2070Sstevel@tonic-gate 	int stat_loc;
2080Sstevel@tonic-gate 	char *newargv[20];
2090Sstevel@tonic-gate 	char *mntp;
2100Sstevel@tonic-gate 	pid_t pid;
2110Sstevel@tonic-gate 	int mounted;
2120Sstevel@tonic-gate 	int c;
2130Sstevel@tonic-gate 	int lockid;
2140Sstevel@tonic-gate 	int Oflg;
2150Sstevel@tonic-gate 	char *strp;
2160Sstevel@tonic-gate 	char servname[33];
2170Sstevel@tonic-gate 	int notify = 1;
2180Sstevel@tonic-gate 	struct stat64 statb;
2190Sstevel@tonic-gate 	struct mnttagdesc mtdesc;
2200Sstevel@tonic-gate 	char mops[MAX_MNTOPT_STR];
2210Sstevel@tonic-gate 	char cfs_nfsv4ops[MAX_MNTOPT_STR];
2220Sstevel@tonic-gate 	uint32_t nfsvers = 0;
2230Sstevel@tonic-gate 	uint32_t nfsvers_error = FALSE;
2240Sstevel@tonic-gate 	int nfsv3pass = 0;
2250Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2260Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
2270Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
2280Sstevel@tonic-gate #endif
2290Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	if (argv[0]) {
2320Sstevel@tonic-gate 		myname = strrchr(argv[0], '/');
2330Sstevel@tonic-gate 		if (myname)
2340Sstevel@tonic-gate 			myname++;
2350Sstevel@tonic-gate 		else
2360Sstevel@tonic-gate 			myname = argv[0];
2370Sstevel@tonic-gate 	} else {
2380Sstevel@tonic-gate 		myname = "path unknown";
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	optionp = NULL;
2420Sstevel@tonic-gate 	nomnttab = 0;
2430Sstevel@tonic-gate 	quiet = 0;
2440Sstevel@tonic-gate 	readonly = 0;
2450Sstevel@tonic-gate 	Oflg = 0;
2460Sstevel@tonic-gate 	cfs_nfsv4ops[0] = '\0';
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	/* process command line options */
2490Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "mo:Orq")) != EOF) {
2500Sstevel@tonic-gate 		switch (c) {
2510Sstevel@tonic-gate 		case 'm':	/* no entry in /etc/mnttab */
2520Sstevel@tonic-gate 			nomnttab = 1;
2530Sstevel@tonic-gate 			break;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 		case 'o':
2560Sstevel@tonic-gate 			optionp = optarg;
2570Sstevel@tonic-gate 			break;
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 		case 'O':
2600Sstevel@tonic-gate 			Oflg++;
2610Sstevel@tonic-gate 			break;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		case 'r':	/* read only mount */
2640Sstevel@tonic-gate 			readonly = 1;
2650Sstevel@tonic-gate 			break;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 		case 'q':
2680Sstevel@tonic-gate 			quiet = 1;
2690Sstevel@tonic-gate 			break;
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 		default:
2720Sstevel@tonic-gate 			usage("invalid option");
2730Sstevel@tonic-gate 			return (1);
2740Sstevel@tonic-gate 		}
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	/* if -o not specified */
2780Sstevel@tonic-gate 	if (optionp == NULL) {
2790Sstevel@tonic-gate 		usage(gettext("\"-o backfstype\" must be specified"));
2800Sstevel@tonic-gate 		return (1);
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	/* verify special device and mount point are specified */
2840Sstevel@tonic-gate 	if (argc - optind < 2) {
2850Sstevel@tonic-gate 		usage(gettext("must specify special device and mount point"));
2860Sstevel@tonic-gate 		return (1);
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	/* Store mount point and special device. */
2900Sstevel@tonic-gate 	specp = argv[argc - 2];
2910Sstevel@tonic-gate 	mntp = argv[argc - 1];
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	/* Initialize default mount values */
2940Sstevel@tonic-gate 	margs.cfs_options.opt_flags = CFS_ACCESS_BACKFS;
2950Sstevel@tonic-gate 	margs.cfs_options.opt_popsize = DEF_POP_SIZE;
2960Sstevel@tonic-gate 	margs.cfs_options.opt_fgsize = DEF_FILEGRP_SIZE;
2970Sstevel@tonic-gate 	margs.cfs_fsid = NULL;
2980Sstevel@tonic-gate 	memset(margs.cfs_cacheid, 0, sizeof (margs.cfs_cacheid));
2990Sstevel@tonic-gate 	margs.cfs_cachedir = CFS_DEF_DIR;
3000Sstevel@tonic-gate 	margs.cfs_backfs = NULL;
3010Sstevel@tonic-gate 	margs.cfs_acregmin = 0;
3020Sstevel@tonic-gate 	margs.cfs_acregmax = 0;
3030Sstevel@tonic-gate 	margs.cfs_acdirmin = 0;
3040Sstevel@tonic-gate 	margs.cfs_acdirmax = 0;
3050Sstevel@tonic-gate 	mflag = MS_OPTIONSTR;
3060Sstevel@tonic-gate 	if (nomnttab)
3070Sstevel@tonic-gate 		mflag |= MS_NOMNTTAB;
3080Sstevel@tonic-gate 	backfstypep = NULL;
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	/* process -o options */
3110Sstevel@tonic-gate 	xx = set_cfs_args(optionp, &margs, &mflag, &backfstypep, &reducep,
3120Sstevel@tonic-gate 	    &notify, &nfsv3pass);
3130Sstevel@tonic-gate 	if (xx) {
3140Sstevel@tonic-gate 		return (1);
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 	strcpy(mops, optionp);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	/* backfstype has to be specified */
3190Sstevel@tonic-gate 	if (backfstypep == NULL) {
3200Sstevel@tonic-gate 		usage(gettext("\"-o backfstype\" must be specified"));
3210Sstevel@tonic-gate 		return (1);
3220Sstevel@tonic-gate 	}
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	if ((strcmp(backfstypep, "nfs") != 0) &&
3250Sstevel@tonic-gate 				(strcmp(backfstypep, "hsfs") != 0)) {
3260Sstevel@tonic-gate 		pr_err(gettext("%s as backfstype is not supported."),
3270Sstevel@tonic-gate 					backfstypep);
3280Sstevel@tonic-gate 		return (1);
3290Sstevel@tonic-gate 	}
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	/* set default write mode if not specified */
3320Sstevel@tonic-gate 	if ((margs.cfs_options.opt_flags &
3330Sstevel@tonic-gate 	    (CFS_WRITE_AROUND|CFS_NONSHARED)) == 0) {
3340Sstevel@tonic-gate 		margs.cfs_options.opt_flags |= CFS_WRITE_AROUND;
3350Sstevel@tonic-gate 		if (strcmp(backfstypep, "hsfs") == 0)
3360Sstevel@tonic-gate 			mflag |= MS_RDONLY;
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	/* if read-only was specified with the -r option */
3400Sstevel@tonic-gate 	if (readonly) {
3410Sstevel@tonic-gate 		mflag |= MS_RDONLY;
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/* if overlay was specified with -O option */
3450Sstevel@tonic-gate 	if (Oflg) {
3460Sstevel@tonic-gate 		mflag |= MS_OVERLAY;
3470Sstevel@tonic-gate 	}
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	/* get the fsid of the backfs and the cacheid */
3500Sstevel@tonic-gate 	margs.cfs_fsid = get_back_fsid(specp);
3510Sstevel@tonic-gate 	if (margs.cfs_fsid == NULL) {
3520Sstevel@tonic-gate 		pr_err(gettext("out of memory"));
3530Sstevel@tonic-gate 		return (1);
3540Sstevel@tonic-gate 	}
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	/*
3570Sstevel@tonic-gate 	 * If using this cachedir to mount a file system for the first time
3580Sstevel@tonic-gate 	 * after reboot, the ncheck for the sanity of the cachedir
3590Sstevel@tonic-gate 	 */
3600Sstevel@tonic-gate 	if (first_time_ab(margs.cfs_cachedir))
3610Sstevel@tonic-gate 		if (check_cache(margs.cfs_cachedir))
3620Sstevel@tonic-gate 			return (1);
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	/* get the front file system cache id if necessary */
3650Sstevel@tonic-gate 	if (margs.cfs_cacheid[0] == '\0') {
3660Sstevel@tonic-gate 		char *cacheid = get_cacheid(margs.cfs_fsid, mntp);
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 		if (cacheid == NULL) {
3690Sstevel@tonic-gate 			pr_err(gettext("default cacheid too long"));
3700Sstevel@tonic-gate 			return (1);
3710Sstevel@tonic-gate 		}
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 		strcpy(margs.cfs_cacheid, cacheid);
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	/* lock the cache directory shared */
3770Sstevel@tonic-gate 	lockid = cachefs_dir_lock(margs.cfs_cachedir, 1);
3780Sstevel@tonic-gate 	if (lockid == -1) {
3790Sstevel@tonic-gate 		/* exit if could not get the lock */
3800Sstevel@tonic-gate 		return (1);
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	/* if no mount point was specified and we are not remounting */
3840Sstevel@tonic-gate 	mounted = 0;
3850Sstevel@tonic-gate 	if ((margs.cfs_backfs == NULL) &&
3860Sstevel@tonic-gate 	    (((mflag & MS_REMOUNT) == 0) ||
3870Sstevel@tonic-gate 	    (margs.cfs_options.opt_flags & CFS_SLIDE))) {
3880Sstevel@tonic-gate 		/* if a disconnectable mount */
3890Sstevel@tonic-gate 		xx = 0;
3900Sstevel@tonic-gate 		if (margs.cfs_options.opt_flags & CFS_DISCONNECTABLE) {
3910Sstevel@tonic-gate 			/* see if the server is alive */
3920Sstevel@tonic-gate 			xx = pingserver(specp);
3930Sstevel@tonic-gate 		}
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 		/* attempt to mount the back file system */
3960Sstevel@tonic-gate 		if (xx == 0) {
3970Sstevel@tonic-gate 			xx = dobackmnt(&margs, reducep, specp, backfstypep,
3980Sstevel@tonic-gate 			    myname, readonly);
3990Sstevel@tonic-gate 			/*
4000Sstevel@tonic-gate 			 * nfs mount exits with a value of 32 if a timeout
4010Sstevel@tonic-gate 			 * error occurs trying the mount.
4020Sstevel@tonic-gate 			 */
4030Sstevel@tonic-gate 			if (xx && (xx != 32)) {
4040Sstevel@tonic-gate 				cachefs_dir_unlock(lockid);
4050Sstevel@tonic-gate 				rmdir(margs.cfs_backfs);
4060Sstevel@tonic-gate 				return (1);
4070Sstevel@tonic-gate 			}
4080Sstevel@tonic-gate 			if (xx == 0)
4090Sstevel@tonic-gate 				mounted = 1;
4100Sstevel@tonic-gate 		}
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/*
4140Sstevel@tonic-gate 	 * At this point the back file system should be mounted.
4150Sstevel@tonic-gate 	 * Get NFS version information for the back filesystem if
4160Sstevel@tonic-gate 	 * it is NFS. The version information is required
4170Sstevel@tonic-gate 	 * because NFS version 4 is incompatible with cachefs
4180Sstevel@tonic-gate 	 * and we provide pass-through support for NFS version 4
4190Sstevel@tonic-gate 	 * with cachefs, aka the cachefs mount is installed but
4200Sstevel@tonic-gate 	 * there is no caching. This is indicated to the kernel
4210Sstevel@tonic-gate 	 * during the mount by setting the CFS_BACKFS_NFSV4 flag.
4220Sstevel@tonic-gate 	 */
4230Sstevel@tonic-gate 	if (margs.cfs_backfs != NULL && strcmp(backfstypep, "nfs") == 0) {
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 		nfsvers = cachefs_get_back_nfsvers(margs.cfs_backfs, nomnttab);
4260Sstevel@tonic-gate 		switch (nfsvers) {
4270Sstevel@tonic-gate 		case 2:
4280Sstevel@tonic-gate 			break;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 		case 3:
4310Sstevel@tonic-gate 			if (nfsv3pass) {
4320Sstevel@tonic-gate 				/* Force pass through (for debugging) */
4330Sstevel@tonic-gate 				margs.cfs_options.opt_flags = CFS_BACKFS_NFSV4;
4340Sstevel@tonic-gate 				if (cfs_nfsv4_build_opts(optionp,
4350Sstevel@tonic-gate 						cfs_nfsv4ops) != 0) {
4360Sstevel@tonic-gate 					nfsvers_error = TRUE;
4370Sstevel@tonic-gate 					goto clean_backmnt;
4380Sstevel@tonic-gate 				}
4390Sstevel@tonic-gate 			}
4400Sstevel@tonic-gate 			break;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 		case 4:
4430Sstevel@tonic-gate 			/*
4440Sstevel@tonic-gate 			 * overwrite old option flags with NFSv4 flag.
4450Sstevel@tonic-gate 			 * Note that will also operate in strict
4460Sstevel@tonic-gate 			 * consistency mode. Clean up the option string
4470Sstevel@tonic-gate 			 * to get rid of the cachefs-specific options
4480Sstevel@tonic-gate 			 * to be in sync with the opt flags, otherwise
4490Sstevel@tonic-gate 			 * these can make it into the mnttab and cause
4500Sstevel@tonic-gate 			 * problems (esp. the disconnected option).
4510Sstevel@tonic-gate 			 */
4520Sstevel@tonic-gate 			margs.cfs_options.opt_flags = CFS_BACKFS_NFSV4;
4530Sstevel@tonic-gate 			if (cfs_nfsv4_build_opts(optionp, cfs_nfsv4ops) != 0) {
4540Sstevel@tonic-gate 				nfsvers_error = TRUE;
4550Sstevel@tonic-gate 				goto clean_backmnt;
4560Sstevel@tonic-gate 			}
4570Sstevel@tonic-gate 			break;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 		default:
4600Sstevel@tonic-gate 			/* error, unknown version */
4610Sstevel@tonic-gate 			nfsvers_error = TRUE;
4620Sstevel@tonic-gate 			goto clean_backmnt;
4630Sstevel@tonic-gate 		}
4640Sstevel@tonic-gate 	}
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	/*
4670Sstevel@tonic-gate 	 * Grab server name from special file arg if it is there or set
4680Sstevel@tonic-gate 	 * server name to "server unknown".
4690Sstevel@tonic-gate 	 */
4700Sstevel@tonic-gate 	margs.cfs_hostname = servname;
4710Sstevel@tonic-gate 	strncpy(servname, specp, sizeof (servname));
4720Sstevel@tonic-gate 	servname[sizeof (servname) - 1] = '\0';
4730Sstevel@tonic-gate 	strp = strchr(servname, ':');
4740Sstevel@tonic-gate 	if (strp == NULL) {
4750Sstevel@tonic-gate 		margs.cfs_hostname = "server unknown";
4760Sstevel@tonic-gate 		margs.cfs_backfsname = specp;
4770Sstevel@tonic-gate 	} else {
4780Sstevel@tonic-gate 		*strp = '\0';
4790Sstevel@tonic-gate 		/*
4800Sstevel@tonic-gate 		 * The rest of the special file arg is the name of
4810Sstevel@tonic-gate 		 * the back filesystem.
4820Sstevel@tonic-gate 		 */
4830Sstevel@tonic-gate 		strp++;
4840Sstevel@tonic-gate 		margs.cfs_backfsname = strp;
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	/* mount the cache file system */
4880Sstevel@tonic-gate 	xx = mount((margs.cfs_backfs != NULL) ? margs.cfs_backfs : "nobackfs",
4890Sstevel@tonic-gate 		mntp, mflag | MS_DATA, MNTTYPE_CFS,
4900Sstevel@tonic-gate 		&margs, sizeof (margs),
4910Sstevel@tonic-gate 		(cfs_nfsv4ops[0] == '\0' ? mops : cfs_nfsv4ops),
4920Sstevel@tonic-gate 		MAX_MNTOPT_STR);
4930Sstevel@tonic-gate clean_backmnt:
4940Sstevel@tonic-gate 	if (xx == -1 || nfsvers_error) {
4950Sstevel@tonic-gate 		if (nfsvers_error) {
4960Sstevel@tonic-gate 			pr_err(gettext("nfs version error."));
4970Sstevel@tonic-gate 		} else if (errno == ESRCH) {
4980Sstevel@tonic-gate 			pr_err(gettext("mount failed, options do not match."));
4990Sstevel@tonic-gate 		} else if ((errno == EAGAIN) && (margs.cfs_backfs == NULL)) {
5000Sstevel@tonic-gate 			pr_err(gettext("mount failed, server not responding."));
5010Sstevel@tonic-gate 		} else {
5020Sstevel@tonic-gate 			pr_err(gettext("mount failed %s"), strerror(errno));
5030Sstevel@tonic-gate 		}
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 		/* try to unmount the back file system if we mounted it */
5060Sstevel@tonic-gate 		if (mounted) {
5070Sstevel@tonic-gate 			xx = 1;
5080Sstevel@tonic-gate 			newargv[xx++] = "umount";
5090Sstevel@tonic-gate 			newargv[xx++] = margs.cfs_backfs;
5100Sstevel@tonic-gate 			newargv[xx++] = NULL;
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 			/* fork */
5130Sstevel@tonic-gate 			if ((pid = fork()) == -1) {
5140Sstevel@tonic-gate 				pr_err(gettext("could not fork: %s"),
5150Sstevel@tonic-gate 				    strerror(errno));
5160Sstevel@tonic-gate 				cachefs_dir_unlock(lockid);
5170Sstevel@tonic-gate 				return (1);
5180Sstevel@tonic-gate 			}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 			/* if the child */
5210Sstevel@tonic-gate 			if (pid == 0) {
5220Sstevel@tonic-gate 				/* do the unmount */
5230Sstevel@tonic-gate 				doexec(backfstypep, newargv, "umount");
5240Sstevel@tonic-gate 			}
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 			/* else if the parent */
5270Sstevel@tonic-gate 			else {
5280Sstevel@tonic-gate 				wait(0);
5290Sstevel@tonic-gate 			}
5300Sstevel@tonic-gate 			rmdir(margs.cfs_backfs);
5310Sstevel@tonic-gate 		}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 		cachefs_dir_unlock(lockid);
5340Sstevel@tonic-gate 		return (1);
5350Sstevel@tonic-gate 	}
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	/* release the lock on the cache directory */
5380Sstevel@tonic-gate 	cachefs_dir_unlock(lockid);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/* record the mount information in the fscache directory */
5410Sstevel@tonic-gate 	record_mount(mntp, specp, margs.cfs_backfs, backfstypep,
5420Sstevel@tonic-gate 		margs.cfs_cachedir, margs.cfs_cacheid,
5430Sstevel@tonic-gate 		(cfs_nfsv4ops[0] == '\0' ? optionp : cfs_nfsv4ops), reducep);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	/* notify the daemon of the mount */
5460Sstevel@tonic-gate 	if (notify)
5470Sstevel@tonic-gate 		daemon_notify(margs.cfs_cachedir, margs.cfs_cacheid);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	/* update mnttab file if necessary */
5500Sstevel@tonic-gate 	if (!nomnttab) {
5510Sstevel@tonic-gate 		/*
5520Sstevel@tonic-gate 		 * If we added the back file system, tag it with ignore,
5530Sstevel@tonic-gate 		 * however, don't fail the mount after its done
5540Sstevel@tonic-gate 		 * if the tag can't be added (eg., this would cause
5550Sstevel@tonic-gate 		 * automounter problems).
5560Sstevel@tonic-gate 		 */
5570Sstevel@tonic-gate 		if (mounted) {
5580Sstevel@tonic-gate 			FILE *mt;
5590Sstevel@tonic-gate 			struct extmnttab mnt;
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 			if ((mt = fopen(MNTTAB, "r")) == NULL)
5620Sstevel@tonic-gate 				return (1);
5630Sstevel@tonic-gate 			while (getextmntent(mt, &mnt, sizeof (mnt)) != -1) {
5640Sstevel@tonic-gate 				if (mnt.mnt_mountp != NULL &&
5650Sstevel@tonic-gate 				    strcmp(margs.cfs_backfs,
5660Sstevel@tonic-gate 					mnt.mnt_mountp) == 0) {
5670Sstevel@tonic-gate 					/* found it, do tag ioctl */
5680Sstevel@tonic-gate 					mtdesc.mtd_major = mnt.mnt_major;
5690Sstevel@tonic-gate 					mtdesc.mtd_minor = mnt.mnt_minor;
5700Sstevel@tonic-gate 					mtdesc.mtd_mntpt = margs.cfs_backfs;
5710Sstevel@tonic-gate 					mtdesc.mtd_tag = MNTOPT_IGNORE;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 					(void) ioctl(fileno(mt),
5740Sstevel@tonic-gate 						MNTIOC_SETTAG, &mtdesc);
5750Sstevel@tonic-gate 					break;
5760Sstevel@tonic-gate 				}
5770Sstevel@tonic-gate 			}
5780Sstevel@tonic-gate 			fclose(mt);
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	/* return success */
5830Sstevel@tonic-gate 	return (0);
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate /*
5880Sstevel@tonic-gate  *
5890Sstevel@tonic-gate  *			usage
5900Sstevel@tonic-gate  *
5910Sstevel@tonic-gate  * Description:
5920Sstevel@tonic-gate  *	Prints a short usage message.
5930Sstevel@tonic-gate  * Arguments:
5940Sstevel@tonic-gate  *	msgp	message to include with the usage message
5950Sstevel@tonic-gate  * Returns:
5960Sstevel@tonic-gate  * Preconditions:
5970Sstevel@tonic-gate  */
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate void
usage(char * msgp)6000Sstevel@tonic-gate usage(char *msgp)
6010Sstevel@tonic-gate {
6020Sstevel@tonic-gate 	if (msgp) {
6030Sstevel@tonic-gate 		pr_err(gettext("%s"), msgp);
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	fprintf(stderr,
6070Sstevel@tonic-gate 	    gettext("Usage: mount -F cachefs [generic options] "
6080Sstevel@tonic-gate 	    "-o backfstype=file_system_type[FSTypespecific_options] "
6090Sstevel@tonic-gate 	    "special mount_point\n"));
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate /*
6130Sstevel@tonic-gate  *
6140Sstevel@tonic-gate  *			pr_err
6150Sstevel@tonic-gate  *
6160Sstevel@tonic-gate  * Description:
6170Sstevel@tonic-gate  *	Prints an error message to stderr.
6180Sstevel@tonic-gate  * Arguments:
6190Sstevel@tonic-gate  *	fmt	printf style format
6200Sstevel@tonic-gate  *	...	arguments for fmt
6210Sstevel@tonic-gate  * Returns:
6220Sstevel@tonic-gate  * Preconditions:
6230Sstevel@tonic-gate  *	precond(fmt)
6240Sstevel@tonic-gate  */
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate void
pr_err(char * fmt,...)6270Sstevel@tonic-gate pr_err(char *fmt, ...)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	va_list ap;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	va_start(ap, fmt);
6320Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("mount -F cachefs: "));
6330Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
6340Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
6350Sstevel@tonic-gate 	va_end(ap);
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate /*
6390Sstevel@tonic-gate  *
6400Sstevel@tonic-gate  *			set_cfs_args
6410Sstevel@tonic-gate  *
6420Sstevel@tonic-gate  * Description:
6430Sstevel@tonic-gate  *	Parse the comma delimited set of options specified by optionp
6440Sstevel@tonic-gate  *	and puts the results in margsp, mflagp, and backfstypepp.
6450Sstevel@tonic-gate  *	A string is constructed of options which are not specific to
6460Sstevel@tonic-gate  *	cfs and is placed in reducepp.
6470Sstevel@tonic-gate  *	Pointers to strings are invalid if this routine is called again.
6480Sstevel@tonic-gate  *	No initialization is done on margsp, mflagp, or backfstypepp.
6490Sstevel@tonic-gate  * Arguments:
6500Sstevel@tonic-gate  *	optionp		string of comma delimited options
6510Sstevel@tonic-gate  *	margsp		option results for the mount dataptr arg
6520Sstevel@tonic-gate  *	mflagp		option results for the mount mflag arg
6530Sstevel@tonic-gate  *	backfstypepp	set to name of back file system type
6540Sstevel@tonic-gate  *	reducepp	set to the option string without cfs specific options
6550Sstevel@tonic-gate  * Returns:
6560Sstevel@tonic-gate  *	Returns 0 for success, -1 for an error.
6570Sstevel@tonic-gate  * Preconditions:
6580Sstevel@tonic-gate  *	precond(optionp)
6590Sstevel@tonic-gate  *	precond(margsp)
6600Sstevel@tonic-gate  *	precond(mflagp)
6610Sstevel@tonic-gate  *	precond(backfstypepp)
6620Sstevel@tonic-gate  *	precond(reducepp)
6630Sstevel@tonic-gate  */
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate int
set_cfs_args(char * optionp,struct cachefs_mountargs * margsp,int * mflagp,char ** backfstypepp,char ** reducepp,int * notifyp,int * nfsv3pass)6660Sstevel@tonic-gate set_cfs_args(char *optionp, struct cachefs_mountargs *margsp, int *mflagp,
6670Sstevel@tonic-gate     char **backfstypepp, char **reducepp, int *notifyp, int *nfsv3pass)
6680Sstevel@tonic-gate {
6690Sstevel@tonic-gate 	static char *optstrp = NULL;
6700Sstevel@tonic-gate 	static char *reducep = NULL;
6710Sstevel@tonic-gate 	char *savep, *strp, *valp;
6720Sstevel@tonic-gate 	int badopt;
6730Sstevel@tonic-gate 	int ret;
6740Sstevel@tonic-gate 	int o_backpath = 0;
6750Sstevel@tonic-gate 	int o_writemode = 0;
6760Sstevel@tonic-gate 	int xx;
6770Sstevel@tonic-gate 	uint_t yy;
6780Sstevel@tonic-gate 	struct stat64 sinfo;
6790Sstevel@tonic-gate 	char *pbuf;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	/* free up any previous options */
6820Sstevel@tonic-gate 	free(optstrp);
6830Sstevel@tonic-gate 	optstrp = NULL;
6840Sstevel@tonic-gate 	free(reducep);
6850Sstevel@tonic-gate 	reducep = NULL;
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	/* make a copy of the options so we can modify it */
6880Sstevel@tonic-gate 	optstrp = strp = strdup(optionp);
6890Sstevel@tonic-gate 	reducep = malloc(strlen(optionp) + 1000);
6900Sstevel@tonic-gate 	if ((strp == NULL) || (reducep == NULL)) {
6910Sstevel@tonic-gate 		pr_err(gettext("out of memory"));
6920Sstevel@tonic-gate 		return (-1);
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 	*reducep = '\0';
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	/* parse the options */
6970Sstevel@tonic-gate 	badopt = 0;
6980Sstevel@tonic-gate 	ret = 0;
6990Sstevel@tonic-gate 	while (*strp) {
7000Sstevel@tonic-gate 		savep = strp;
7010Sstevel@tonic-gate 		switch (getsubopt(&strp, cfs_opts, &valp)) {
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 		case CFSOPT_BACKFSTYPE:
7040Sstevel@tonic-gate 			if (valp == NULL)
7050Sstevel@tonic-gate 				badopt = 1;
7060Sstevel@tonic-gate 			else
7070Sstevel@tonic-gate 				*backfstypepp = valp;
7080Sstevel@tonic-gate 			break;
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 		case CFSOPT_CACHEDIR:
7110Sstevel@tonic-gate 			if (valp == NULL)
7120Sstevel@tonic-gate 				badopt = 1;
7130Sstevel@tonic-gate 			else {
7140Sstevel@tonic-gate 				margsp->cfs_cachedir = valp;
7150Sstevel@tonic-gate 				if (valp[0] != '/') {
7160Sstevel@tonic-gate 				    pbuf = (char *)malloc(MAXPATHLEN +
7170Sstevel@tonic-gate 						strlen(valp) + 3);
7180Sstevel@tonic-gate 				    if (pbuf == NULL) {
7190Sstevel@tonic-gate 					pr_err(gettext("out of memory"));
7200Sstevel@tonic-gate 					badopt = 1;
7210Sstevel@tonic-gate 					break;
7220Sstevel@tonic-gate 				    }
7230Sstevel@tonic-gate 				    if (getcwd(pbuf, MAXPATHLEN+1) == NULL) {
7240Sstevel@tonic-gate 					pr_err(gettext("cachedir too long"));
7250Sstevel@tonic-gate 					badopt = 1;
7260Sstevel@tonic-gate 					break;
7270Sstevel@tonic-gate 				    }
7280Sstevel@tonic-gate 				    if (pbuf[strlen(pbuf)-1] != '/')
7290Sstevel@tonic-gate 					strcat(pbuf, "/");
7300Sstevel@tonic-gate 				    strcat(pbuf, valp);
7310Sstevel@tonic-gate 				    margsp->cfs_cachedir = pbuf;
7320Sstevel@tonic-gate 				}
7330Sstevel@tonic-gate 			}
7340Sstevel@tonic-gate 			break;
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 		case CFSOPT_CACHEID:
7370Sstevel@tonic-gate 			if (valp == NULL) {
7380Sstevel@tonic-gate 				badopt = 1;
7390Sstevel@tonic-gate 				break;
7400Sstevel@tonic-gate 			}
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 			if (strlen(valp) >= (size_t)C_MAX_MOUNT_FSCDIRNAME) {
7430Sstevel@tonic-gate 				pr_err(gettext("cacheid too long"));
7440Sstevel@tonic-gate 				badopt = 1;
7450Sstevel@tonic-gate 				break;
7460Sstevel@tonic-gate 			}
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 			memset(margsp->cfs_cacheid, 0, C_MAX_MOUNT_FSCDIRNAME);
7490Sstevel@tonic-gate 			strcpy(margsp->cfs_cacheid, valp);
7500Sstevel@tonic-gate 			break;
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 		case CFSOPT_BACKPATH:
7530Sstevel@tonic-gate 			if (valp == NULL)
7540Sstevel@tonic-gate 				badopt = 1;
7550Sstevel@tonic-gate 			else {
7560Sstevel@tonic-gate 				margsp->cfs_backfs = valp;
7570Sstevel@tonic-gate 				o_backpath = 1;
7580Sstevel@tonic-gate 			}
7590Sstevel@tonic-gate 			break;
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 		case CFSOPT_WRITEAROUND:
7620Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_WRITE_AROUND;
7630Sstevel@tonic-gate 			o_writemode++;
7640Sstevel@tonic-gate 			break;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 		case CFSOPT_NONSHARED:
7670Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_NONSHARED;
7680Sstevel@tonic-gate 			o_writemode++;
7690Sstevel@tonic-gate 			break;
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 		case CFSOPT_NOCONST:
7720Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_NOCONST_MODE;
7730Sstevel@tonic-gate 			break;
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 		case CFSOPT_CODCONST:
7760Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_CODCONST_MODE;
7770Sstevel@tonic-gate 			break;
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 		case CFSOPT_LOCALACCESS:
7800Sstevel@tonic-gate 			margsp->cfs_options.opt_flags &= ~CFS_ACCESS_BACKFS;
7810Sstevel@tonic-gate 			break;
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 		case CFSOPT_NOSETSEC:
7840Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_NOACL;
7850Sstevel@tonic-gate 			break;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 		case CFSOPT_LLOCK:
7880Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_LLOCK;
7890Sstevel@tonic-gate 			strcat(reducep, ",");
7900Sstevel@tonic-gate 			strcat(reducep, savep);
7910Sstevel@tonic-gate 			break;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 		case CFSOPT_REMOUNT:
7940Sstevel@tonic-gate 			*mflagp |= MS_REMOUNT;
7950Sstevel@tonic-gate 			break;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 		case CFSOPT_SLIDE:
7980Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_SLIDE;
7990Sstevel@tonic-gate 			break;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 		case CFSOPT_FGSIZE:
8020Sstevel@tonic-gate 			if (bad(valp))
8030Sstevel@tonic-gate 				badopt = 1;
8040Sstevel@tonic-gate 			else
8050Sstevel@tonic-gate 				margsp->cfs_options.opt_fgsize = atoi(valp);
8060Sstevel@tonic-gate 			break;
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 		case CFSOPT_POPSIZE:
8090Sstevel@tonic-gate 			if (bad(valp))
8100Sstevel@tonic-gate 				badopt = 1;
8110Sstevel@tonic-gate 			else
8120Sstevel@tonic-gate 				margsp->cfs_options.opt_popsize =
8130Sstevel@tonic-gate 				    atoi(valp) * 1024;
8140Sstevel@tonic-gate 			break;
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 		case CFSOPT_ACREGMIN:
8170Sstevel@tonic-gate 			if (bad(valp))
8180Sstevel@tonic-gate 				badopt = 1;
8190Sstevel@tonic-gate 			else
8200Sstevel@tonic-gate 				margsp->cfs_acregmin = atoi(valp);
8210Sstevel@tonic-gate 			break;
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 		case CFSOPT_ACREGMAX:
8240Sstevel@tonic-gate 			if (bad(valp))
8250Sstevel@tonic-gate 				badopt = 1;
8260Sstevel@tonic-gate 			else
8270Sstevel@tonic-gate 				margsp->cfs_acregmax = atoi(valp);
8280Sstevel@tonic-gate 			break;
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 		case CFSOPT_ACDIRMIN:
8310Sstevel@tonic-gate 			if (bad(valp))
8320Sstevel@tonic-gate 				badopt = 1;
8330Sstevel@tonic-gate 			else
8340Sstevel@tonic-gate 				margsp->cfs_acdirmin = atoi(valp);
8350Sstevel@tonic-gate 			break;
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 		case CFSOPT_ACDIRMAX:
8380Sstevel@tonic-gate 			if (bad(valp))
8390Sstevel@tonic-gate 				badopt = 1;
8400Sstevel@tonic-gate 			else
8410Sstevel@tonic-gate 				margsp->cfs_acdirmax = atoi(valp);
8420Sstevel@tonic-gate 			break;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 		case CFSOPT_ACTIMEO:
8450Sstevel@tonic-gate 			if (bad(valp))
8460Sstevel@tonic-gate 				badopt = 1;
8470Sstevel@tonic-gate 			else {
8480Sstevel@tonic-gate 				yy = atoi(valp);
8490Sstevel@tonic-gate 				margsp->cfs_acregmin = yy;
8500Sstevel@tonic-gate 				margsp->cfs_acregmax = yy;
8510Sstevel@tonic-gate 				margsp->cfs_acdirmin = yy;
8520Sstevel@tonic-gate 				margsp->cfs_acdirmax = yy;
8530Sstevel@tonic-gate 			}
8540Sstevel@tonic-gate 			/*
8550Sstevel@tonic-gate 			 * Note that we do not pass the actimeo options
8560Sstevel@tonic-gate 			 * to the back file system.  This change was
8570Sstevel@tonic-gate 			 * made for Chart.  Chart needs noac or actimeo=0
8580Sstevel@tonic-gate 			 * so it makes no sense to pass these options on.
8590Sstevel@tonic-gate 			 * In theory it should be okay to not pass these
8600Sstevel@tonic-gate 			 * options on for regular cachefs mounts since
8610Sstevel@tonic-gate 			 * cachefs perform the required attribute caching.
8620Sstevel@tonic-gate 			 */
8630Sstevel@tonic-gate 			break;
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate #if 0
8660Sstevel@tonic-gate 		case CFSOPT_LAZYMOUNT:
8670Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_LAZYMOUNT;
8680Sstevel@tonic-gate 			break;
8690Sstevel@tonic-gate #endif
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 		case CFSOPT_DISCONNECTABLE:
8720Sstevel@tonic-gate 		case CFSOPT_SNR:
8730Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_DISCONNECTABLE;
8740Sstevel@tonic-gate 			break;
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 		case CFSOPT_NOFILL:
8770Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_NOFILL;
8780Sstevel@tonic-gate 			break;
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 		case CFSOPT_SOFT:
8810Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_SOFT;
8820Sstevel@tonic-gate 			break;
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 		case CFSOPT_NONOTIFY:
8850Sstevel@tonic-gate 			*notifyp = 0;
8860Sstevel@tonic-gate 			break;
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate #ifdef CFS_NFSV3_PASSTHROUGH
8890Sstevel@tonic-gate 		case CFSOPT_NFSV3PASSTHROUGH:
8900Sstevel@tonic-gate 			*nfsv3pass = 1;
8910Sstevel@tonic-gate 			break;
8920Sstevel@tonic-gate #endif /* CFS_NFSV3_PASSTHROUGH */
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 		default:
8950Sstevel@tonic-gate 			/*
8960Sstevel@tonic-gate 			 * unknown or vfs layer option, save for the back
8970Sstevel@tonic-gate 			 * file system
8980Sstevel@tonic-gate 			 */
8990Sstevel@tonic-gate 			strcat(reducep, ",");
9000Sstevel@tonic-gate 			strcat(reducep, savep);
9010Sstevel@tonic-gate 			break;
9020Sstevel@tonic-gate 		}
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 		/* if a lexical error occurred */
9050Sstevel@tonic-gate 		if (badopt) {
9060Sstevel@tonic-gate 			pr_err(gettext("invalid argument to option: \"%s\""),
9070Sstevel@tonic-gate 			    savep);
9080Sstevel@tonic-gate 			badopt = 0;
9090Sstevel@tonic-gate 			ret = -1;
9100Sstevel@tonic-gate 		}
9110Sstevel@tonic-gate 	}
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/*
9140Sstevel@tonic-gate 	 * Should mount backfs soft if disconnectable & non-shared options
9150Sstevel@tonic-gate 	 * are used. NFS soft option allows reads and writes to TIMEOUT
9160Sstevel@tonic-gate 	 * when the server is not responding, which is crucial for
9170Sstevel@tonic-gate 	 * disconnectable option to work all the time in non-shared mode.
9180Sstevel@tonic-gate 	 *
9190Sstevel@tonic-gate 	 * Should mount backfs semisoft if disconnectable & write-around
9200Sstevel@tonic-gate 	 * are used. NFS semisoft option allows reads to TIMEOUT and
9210Sstevel@tonic-gate 	 * write to block when the server is not responding, which is
9220Sstevel@tonic-gate 	 * good for write around option because it is shared.
9230Sstevel@tonic-gate 	 *
9240Sstevel@tonic-gate 	 * Since disconnectable and strict options are conflicting,
9250Sstevel@tonic-gate 	 * when disconnectable option is used, default option is set to
9260Sstevel@tonic-gate 	 * demandconst.
9270Sstevel@tonic-gate 	 */
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	if (margsp->cfs_options.opt_flags & (CFS_DISCONNECTABLE | CFS_SOFT))
9300Sstevel@tonic-gate 		if (margsp->cfs_options.opt_flags & CFS_NONSHARED) {
9310Sstevel@tonic-gate 			strcat(reducep, ",soft,noprint");
9320Sstevel@tonic-gate 			margsp->cfs_options.opt_flags |= CFS_CODCONST_MODE;
9330Sstevel@tonic-gate 		}
9340Sstevel@tonic-gate 		else
9350Sstevel@tonic-gate 			strcat(reducep, ",semisoft,noprint");
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	if (!(margsp->cfs_options.opt_flags & CFS_DISCONNECTABLE)) {
9380Sstevel@tonic-gate 		/* not snr, no need to notify the cachefsd */
9390Sstevel@tonic-gate 		*notifyp = 0;
9400Sstevel@tonic-gate 	}
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	/* additional nfs options needed so disconnectable will work */
9430Sstevel@tonic-gate 	if (margsp->cfs_options.opt_flags & CFS_DISCONNECTABLE) {
9440Sstevel@tonic-gate 		/*
9450Sstevel@tonic-gate 		 * retry=0 so cachefs can mount if nfs mount fails
9460Sstevel@tonic-gate 		 *   even with this nfs takes 3 minutes to give up
9470Sstevel@tonic-gate 		 * actimeo=0 because NFS does not pick up new ctime after
9480Sstevel@tonic-gate 		 *	rename
9490Sstevel@tonic-gate 		 */
9500Sstevel@tonic-gate 		strcat(reducep, ",retry=0");
9510Sstevel@tonic-gate 		if (margsp->cfs_options.opt_flags & CFS_NONSHARED)
9520Sstevel@tonic-gate 			strcat(reducep, ",actimeo=0");
9530Sstevel@tonic-gate 	}
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	/* check for conflicting options */
9560Sstevel@tonic-gate 	xx = margsp->cfs_options.opt_flags;
9570Sstevel@tonic-gate 	if (o_backpath & (xx & CFS_DISCONNECTABLE)) {
9580Sstevel@tonic-gate 		pr_err(gettext("backpath cannot be used with disconnectable"));
9590Sstevel@tonic-gate 		ret = -1;
9600Sstevel@tonic-gate 	}
9610Sstevel@tonic-gate 	if (margsp->cfs_acregmin > margsp->cfs_acregmax) {
9620Sstevel@tonic-gate 		pr_err(gettext("acregmin cannot be greater than acregmax"));
9630Sstevel@tonic-gate 		ret = -1;
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate 	if (margsp->cfs_acdirmin > margsp->cfs_acdirmax) {
9660Sstevel@tonic-gate 		pr_err(gettext("acdirmin cannot be greater than acdirmax"));
9670Sstevel@tonic-gate 		ret = -1;
9680Sstevel@tonic-gate 	}
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	xx = CFS_NOCONST_MODE | CFS_CODCONST_MODE;
9710Sstevel@tonic-gate 	if ((margsp->cfs_options.opt_flags & xx) == xx) {
9720Sstevel@tonic-gate 		pr_err(gettext("only one of noconst and demandconst"
9730Sstevel@tonic-gate 			" may be specified"));
9740Sstevel@tonic-gate 		ret = -1;
9750Sstevel@tonic-gate 	}
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	if (o_writemode > 1) {
9780Sstevel@tonic-gate 		pr_err(gettext(
9790Sstevel@tonic-gate 		    "only one of write-around or non-shared"
9800Sstevel@tonic-gate 		    " may be specified"));
9810Sstevel@tonic-gate 		ret = -1;
9820Sstevel@tonic-gate 	}
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	/* if an error occured */
9850Sstevel@tonic-gate 	if (ret)
9860Sstevel@tonic-gate 		return (-1);
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	/* if there are any options which are not mount specific */
9890Sstevel@tonic-gate 	if (*reducep)
9900Sstevel@tonic-gate 		*reducepp = reducep + 1;
9910Sstevel@tonic-gate 	else
9920Sstevel@tonic-gate 		*reducepp = NULL;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	/* return success */
9950Sstevel@tonic-gate 	return (0);
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate /*
9990Sstevel@tonic-gate  *
10000Sstevel@tonic-gate  *			get_mount_point
10010Sstevel@tonic-gate  *
10020Sstevel@tonic-gate  * Description:
10030Sstevel@tonic-gate  *	Makes a suitable mount point for the back file system.
10040Sstevel@tonic-gate  *	The name of the mount point created is stored in a malloced
10050Sstevel@tonic-gate  *	buffer in pathpp
10060Sstevel@tonic-gate  * Arguments:
10070Sstevel@tonic-gate  *	cachedirp	the name of the cache directory
10080Sstevel@tonic-gate  *	specp		the special name of the device for the file system
10090Sstevel@tonic-gate  *	pathpp		where to store the mount point
10100Sstevel@tonic-gate  * Returns:
10110Sstevel@tonic-gate  *	Returns 0 for success, -1 for an error.
10120Sstevel@tonic-gate  * Preconditions:
10130Sstevel@tonic-gate  *	precond(cachedirp)
10140Sstevel@tonic-gate  *	precond(specp)
10150Sstevel@tonic-gate  *	precond(pathpp)
10160Sstevel@tonic-gate  */
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate int
get_mount_point(char * cachedirp,char * specp,char ** pathpp)10190Sstevel@tonic-gate get_mount_point(char *cachedirp, char *specp, char **pathpp)
10200Sstevel@tonic-gate {
10210Sstevel@tonic-gate 	char *strp;
10220Sstevel@tonic-gate 	char *namep;
10230Sstevel@tonic-gate 	struct stat64 stat1, stat2;
10240Sstevel@tonic-gate 	int xx;
10250Sstevel@tonic-gate 	int index;
10260Sstevel@tonic-gate 	int max;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	/* make a copy of the special device name */
10290Sstevel@tonic-gate 	specp = strdup(specp);
10300Sstevel@tonic-gate 	if (specp == NULL) {
10310Sstevel@tonic-gate 		pr_err(gettext("out of memory"));
10320Sstevel@tonic-gate 		return (-1);
10330Sstevel@tonic-gate 	}
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	/* convert the special device name into a file name */
10360Sstevel@tonic-gate 	strp = specp;
10370Sstevel@tonic-gate 	while (strp = strchr(strp, '/')) {
10380Sstevel@tonic-gate 		*strp = '_';
10390Sstevel@tonic-gate 	}
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	/* get some space for the path name */
10420Sstevel@tonic-gate 	strp = malloc(MAXPATHLEN);
10430Sstevel@tonic-gate 	if (strp == NULL) {
10440Sstevel@tonic-gate 		pr_err(gettext("out of memory"));
10450Sstevel@tonic-gate 		return (-1);
10460Sstevel@tonic-gate 	}
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	/* see if the mount directory is valid */
10490Sstevel@tonic-gate 	/* backfs can contain large files */
10500Sstevel@tonic-gate 	sprintf(strp, "%s/%s", cachedirp, BACKMNT_NAME);
10510Sstevel@tonic-gate 	xx = stat64(strp, &stat1);
10520Sstevel@tonic-gate 	if ((xx == -1) || !S_ISDIR(stat1.st_mode)) {
10530Sstevel@tonic-gate 		pr_err(gettext("%s is not a valid cache."), strp);
10540Sstevel@tonic-gate 		return (-1);
10550Sstevel@tonic-gate 	}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	/* find a directory name we can use */
10580Sstevel@tonic-gate 	max = 10000;
10590Sstevel@tonic-gate 	namep = strp + strlen(strp);
10600Sstevel@tonic-gate 	for (index = 1; index < max; index++) {
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 		/* construct a directory name to consider */
10630Sstevel@tonic-gate 		if (index == 1)
10640Sstevel@tonic-gate 			sprintf(namep, "/%s", specp);
10650Sstevel@tonic-gate 		else
10660Sstevel@tonic-gate 			sprintf(namep, "/%s_%d", specp, index);
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 		/* try to create the directory */
10690Sstevel@tonic-gate 		xx = mkdir(strp, 0755);
10700Sstevel@tonic-gate 		if (xx == 0) {
10710Sstevel@tonic-gate 			/* done if the create succeeded */
10720Sstevel@tonic-gate 			break;
10730Sstevel@tonic-gate 		}
10740Sstevel@tonic-gate 	}
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	/* if the search failed */
10770Sstevel@tonic-gate 	if (index >= max) {
10780Sstevel@tonic-gate 		pr_err(gettext("could not create a directory"));
10790Sstevel@tonic-gate 		return (-1);
10800Sstevel@tonic-gate 	}
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	/* return success */
10830Sstevel@tonic-gate 	*pathpp = strp;
10840Sstevel@tonic-gate 	return (0);
10850Sstevel@tonic-gate }
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate int
dobackmnt(struct cachefs_mountargs * margsp,char * reducep,char * specp,char * backfstypep,char * mynamep,int readonly)10890Sstevel@tonic-gate dobackmnt(struct cachefs_mountargs *margsp, char *reducep, char *specp,
10900Sstevel@tonic-gate     char *backfstypep, char *mynamep, int readonly)
10910Sstevel@tonic-gate {
10920Sstevel@tonic-gate 	int xx;
10930Sstevel@tonic-gate 	pid_t pid;
10940Sstevel@tonic-gate 	char *newargv[20];
10950Sstevel@tonic-gate 	int stat_loc;
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	/* get a suitable mount point */
10980Sstevel@tonic-gate 	xx = get_mount_point(margsp->cfs_cachedir, specp, &margsp->cfs_backfs);
10990Sstevel@tonic-gate 	if (xx)
11000Sstevel@tonic-gate 		return (1);
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	/* construct argument list for mounting the back file system */
11030Sstevel@tonic-gate 	xx = 1;
11040Sstevel@tonic-gate 	newargv[xx++] = "mount";
11050Sstevel@tonic-gate 	if (readonly)
11060Sstevel@tonic-gate 		newargv[xx++] = "-r";
11070Sstevel@tonic-gate 	if (nomnttab)
11080Sstevel@tonic-gate 		newargv[xx++] = "-m";
11090Sstevel@tonic-gate 	if (quiet)
11100Sstevel@tonic-gate 		newargv[xx++] = "-q";
11110Sstevel@tonic-gate 	if (reducep) {
11120Sstevel@tonic-gate 		newargv[xx++] = "-o";
11130Sstevel@tonic-gate 		newargv[xx++] = reducep;
11140Sstevel@tonic-gate 	}
11150Sstevel@tonic-gate 	newargv[xx++] = specp;
11160Sstevel@tonic-gate 	newargv[xx++] = margsp->cfs_backfs;
11170Sstevel@tonic-gate 	newargv[xx++] = NULL;
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	/* fork */
11200Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
11210Sstevel@tonic-gate 		pr_err(gettext("could not fork %s"), strerror(errno));
11220Sstevel@tonic-gate 		return (1);
11230Sstevel@tonic-gate 	}
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	/* if the child */
11260Sstevel@tonic-gate 	if (pid == 0) {
11270Sstevel@tonic-gate 		/* do the mount */
11280Sstevel@tonic-gate 		doexec(backfstypep, newargv, mynamep);
11290Sstevel@tonic-gate 	}
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	/* else if the parent */
11320Sstevel@tonic-gate 	else {
11330Sstevel@tonic-gate 		/* wait for the child to exit */
11340Sstevel@tonic-gate 		if (wait(&stat_loc) == -1) {
11350Sstevel@tonic-gate 			pr_err(gettext("wait failed %s"), strerror(errno));
11360Sstevel@tonic-gate 			return (1);
11370Sstevel@tonic-gate 		}
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 		if (!WIFEXITED(stat_loc)) {
11400Sstevel@tonic-gate 			pr_err(gettext("back mount did not exit"));
11410Sstevel@tonic-gate 			return (1);
11420Sstevel@tonic-gate 		}
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 		xx = WEXITSTATUS(stat_loc);
11450Sstevel@tonic-gate 		if (xx) {
11460Sstevel@tonic-gate 			pr_err(gettext("back mount failed"));
11470Sstevel@tonic-gate 			return (xx);
11480Sstevel@tonic-gate 		}
11490Sstevel@tonic-gate 	}
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 	return (0);
11520Sstevel@tonic-gate }
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate /*
11550Sstevel@tonic-gate  *
11560Sstevel@tonic-gate  *			doexec
11570Sstevel@tonic-gate  *
11580Sstevel@tonic-gate  * Description:
11590Sstevel@tonic-gate  *	Execs the specified program with the specified command line arguments.
11600Sstevel@tonic-gate  *	This function never returns.
11610Sstevel@tonic-gate  * Arguments:
11620Sstevel@tonic-gate  *	fstype		type of file system
11630Sstevel@tonic-gate  *	newargv		command line arguments
11640Sstevel@tonic-gate  *	progp		name of program to exec
11650Sstevel@tonic-gate  * Returns:
11660Sstevel@tonic-gate  * Preconditions:
11670Sstevel@tonic-gate  *	precond(fstype)
11680Sstevel@tonic-gate  *	precond(newargv)
11690Sstevel@tonic-gate  */
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate void
doexec(char * fstype,char * newargv[],char * progp)11720Sstevel@tonic-gate doexec(char *fstype, char *newargv[], char *progp)
11730Sstevel@tonic-gate {
11740Sstevel@tonic-gate 	char	full_path[PATH_MAX];
11750Sstevel@tonic-gate 	char	alter_path[PATH_MAX];
11760Sstevel@tonic-gate 	char	*vfs_path = VFS_PATH;
11770Sstevel@tonic-gate 	char	*alt_path = ALT_PATH;
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	/* build the full pathname of the fstype dependent command. */
11800Sstevel@tonic-gate 	sprintf(full_path, "%s/%s/%s", vfs_path, fstype, progp);
11810Sstevel@tonic-gate 	sprintf(alter_path, "%s/%s/%s", alt_path, fstype, progp);
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	/* if the program exists */
11840Sstevel@tonic-gate 	if (access(full_path, 0) == 0) {
11850Sstevel@tonic-gate 		/* invoke the program */
11860Sstevel@tonic-gate 		execv(full_path, &newargv[1]);
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 		/* if wrong permissions */
11890Sstevel@tonic-gate 		if (errno == EACCES) {
11900Sstevel@tonic-gate 			pr_err(gettext("cannot execute %s %s"),
11910Sstevel@tonic-gate 			    full_path, strerror(errno));
11920Sstevel@tonic-gate 		}
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 		/* if it did not work and the shell might make it */
11950Sstevel@tonic-gate 		if (errno == ENOEXEC) {
11960Sstevel@tonic-gate 			newargv[0] = "sh";
11970Sstevel@tonic-gate 			newargv[1] = full_path;
11980Sstevel@tonic-gate 			execv("/sbin/sh", &newargv[0]);
11990Sstevel@tonic-gate 		}
12000Sstevel@tonic-gate 	}
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 	/* try the alternate path */
12030Sstevel@tonic-gate 	execv(alter_path, &newargv[1]);
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 	/* if wrong permissions */
12060Sstevel@tonic-gate 	if (errno == EACCES) {
12070Sstevel@tonic-gate 		pr_err(gettext("cannot execute %s %s"),
12080Sstevel@tonic-gate 		    alter_path, strerror(errno));
12090Sstevel@tonic-gate 	}
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	/* if it did not work and the shell might make it */
12120Sstevel@tonic-gate 	if (errno == ENOEXEC) {
12130Sstevel@tonic-gate 		newargv[0] = "sh";
12140Sstevel@tonic-gate 		newargv[1] = alter_path;
12150Sstevel@tonic-gate 		execv("/sbin/sh", &newargv[0]);
12160Sstevel@tonic-gate 	}
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	pr_err(gettext("operation not applicable to FSType %s"), fstype);
12190Sstevel@tonic-gate 	exit(1);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate /*
12230Sstevel@tonic-gate  *
12240Sstevel@tonic-gate  *			get_back_fsid
12250Sstevel@tonic-gate  *
12260Sstevel@tonic-gate  * Description:
12270Sstevel@tonic-gate  *	Determines a unique identifier for the back file system.
12280Sstevel@tonic-gate  * Arguments:
12290Sstevel@tonic-gate  *	specp	the special file of the back fs
12300Sstevel@tonic-gate  * Returns:
12310Sstevel@tonic-gate  *	Returns a malloc string which is the unique identifer
12320Sstevel@tonic-gate  *	or NULL on failure.  NULL is only returned if malloc fails.
12330Sstevel@tonic-gate  * Preconditions:
12340Sstevel@tonic-gate  *	precond(specp)
12350Sstevel@tonic-gate  */
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate char *
get_back_fsid(char * specp)12380Sstevel@tonic-gate get_back_fsid(char *specp)
12390Sstevel@tonic-gate {
12400Sstevel@tonic-gate 	return (strdup(specp));
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate /*
12440Sstevel@tonic-gate  *
12450Sstevel@tonic-gate  *			get_cacheid
12460Sstevel@tonic-gate  *
12470Sstevel@tonic-gate  * Description:
12480Sstevel@tonic-gate  *	Determines an identifier for the front file system cache.
12490Sstevel@tonic-gate  *	The returned string points to a static buffer which is
12500Sstevel@tonic-gate  *	overwritten on each call.
12510Sstevel@tonic-gate  *	The length of the returned string is < C_MAX_MOUNT_FSCDIRNAME.
12520Sstevel@tonic-gate  * Arguments:
12530Sstevel@tonic-gate  *	fsidp	back file system id
12540Sstevel@tonic-gate  *	mntp	front file system mount point
12550Sstevel@tonic-gate  * Returns:
12560Sstevel@tonic-gate  *	Returns a pointer to the string identifier, or NULL if the
12570Sstevel@tonic-gate  *	identifier was overflowed.
12580Sstevel@tonic-gate  * Preconditions:
12590Sstevel@tonic-gate  *	precond(fsidp)
12600Sstevel@tonic-gate  *	precond(mntp)
12610Sstevel@tonic-gate  */
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate char *
get_cacheid(char * fsidp,char * mntp)12640Sstevel@tonic-gate get_cacheid(char *fsidp, char *mntp)
12650Sstevel@tonic-gate {
12660Sstevel@tonic-gate 	char *c1;
12670Sstevel@tonic-gate 	static char buf[PATH_MAX];
12680Sstevel@tonic-gate 	char mnt_copy[PATH_MAX];
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	/* strip off trailing space in mountpoint -- autofs fallout */
12710Sstevel@tonic-gate 	if (strlen(mntp) >= sizeof (mnt_copy))
12720Sstevel@tonic-gate 		return (NULL);
12730Sstevel@tonic-gate 	(void) strcpy(mnt_copy, mntp);
12740Sstevel@tonic-gate 	c1 = mnt_copy + strlen(mnt_copy) - 1;
12750Sstevel@tonic-gate 	if (*c1 == ' ')
12760Sstevel@tonic-gate 		*c1 = '\0';
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	if ((strlen(fsidp) + strlen(mnt_copy) + 2) >=
12790Sstevel@tonic-gate 	    (size_t)C_MAX_MOUNT_FSCDIRNAME)
12800Sstevel@tonic-gate 		return (NULL);
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 	strcpy(buf, fsidp);
12830Sstevel@tonic-gate 	strcat(buf, ":");
12840Sstevel@tonic-gate 	strcat(buf, mnt_copy);
12850Sstevel@tonic-gate 	c1 = buf;
12860Sstevel@tonic-gate 	while ((c1 = strpbrk(c1, "/")) != NULL)
12870Sstevel@tonic-gate 		*c1 = '_';
12880Sstevel@tonic-gate 	return (buf);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate /*
12930Sstevel@tonic-gate  *
12940Sstevel@tonic-gate  *			check_cache
12950Sstevel@tonic-gate  *
12960Sstevel@tonic-gate  * Description:
12970Sstevel@tonic-gate  *	Checks the cache we are about to use.
12980Sstevel@tonic-gate  * Arguments:
12990Sstevel@tonic-gate  *	cachedirp	cachedirectory to check
13000Sstevel@tonic-gate  * Returns:
13010Sstevel@tonic-gate  *	Returns 0 for success, -1 for an error.
13020Sstevel@tonic-gate  * Preconditions:
13030Sstevel@tonic-gate  */
13040Sstevel@tonic-gate int
check_cache(cachedirp)13050Sstevel@tonic-gate check_cache(cachedirp)
13060Sstevel@tonic-gate 	char *cachedirp;
13070Sstevel@tonic-gate {
13080Sstevel@tonic-gate 	char *fsck_argv[4];
13090Sstevel@tonic-gate 	int status = 0;
13100Sstevel@tonic-gate 	pid_t pid;
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	fsck_argv[1] = "fsck";
13130Sstevel@tonic-gate 	fsck_argv[2] = cachedirp;
13140Sstevel@tonic-gate 	fsck_argv[3] = NULL;
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 	/* fork */
13170Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
13180Sstevel@tonic-gate 		pr_err(gettext("could not fork %s"),
13190Sstevel@tonic-gate 		    strerror(errno));
13200Sstevel@tonic-gate 		return (1);
13210Sstevel@tonic-gate 	}
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	if (pid == 0) {
13240Sstevel@tonic-gate 		/* do the fsck */
13250Sstevel@tonic-gate 		doexec("cachefs", fsck_argv, "fsck");
13260Sstevel@tonic-gate 	} else {
13270Sstevel@tonic-gate 		/* wait for the child to exit */
13280Sstevel@tonic-gate 		if (wait(&status) == -1) {
13290Sstevel@tonic-gate 			pr_err(gettext("wait failed %s"),
13300Sstevel@tonic-gate 			    strerror(errno));
13310Sstevel@tonic-gate 			return (1);
13320Sstevel@tonic-gate 		}
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 		if (!WIFEXITED(status)) {
13350Sstevel@tonic-gate 			pr_err(gettext("cache fsck did not exit"));
13360Sstevel@tonic-gate 			return (1);
13370Sstevel@tonic-gate 		}
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 		if (WEXITSTATUS(status) != 0) {
13400Sstevel@tonic-gate 			pr_err(gettext("cache fsck mount failed"));
13410Sstevel@tonic-gate 			return (1);
13420Sstevel@tonic-gate 		}
13430Sstevel@tonic-gate 	}
13440Sstevel@tonic-gate 	return (0);
13450Sstevel@tonic-gate }
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate /*
13480Sstevel@tonic-gate  *
13490Sstevel@tonic-gate  *			record_mount
13500Sstevel@tonic-gate  *
13510Sstevel@tonic-gate  * Description:
13520Sstevel@tonic-gate  *	Records mount information in a file in the fscache directory.
13530Sstevel@tonic-gate  * Arguments:
13540Sstevel@tonic-gate  * Returns:
13550Sstevel@tonic-gate  * Preconditions:
13560Sstevel@tonic-gate  */
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate void
record_mount(char * mntp,char * specp,char * backfsp,char * backfstypep,char * cachedirp,char * cacheidp,char * optionp,char * reducep)13590Sstevel@tonic-gate record_mount(char *mntp, char *specp, char *backfsp, char *backfstypep,
13600Sstevel@tonic-gate     char *cachedirp, char *cacheidp, char *optionp, char *reducep)
13610Sstevel@tonic-gate {
13620Sstevel@tonic-gate 	char buf[MAXPATHLEN*2];
13630Sstevel@tonic-gate 	FILE *fout;
13640Sstevel@tonic-gate 	time_t tval;
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	tval = time(NULL);
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	/* this file is < 2GB */
13690Sstevel@tonic-gate 	sprintf(buf, "%s/%s/%s", cachedirp, cacheidp, CACHEFS_MNT_FILE);
13700Sstevel@tonic-gate 	fout = fopen(buf, "w");
13710Sstevel@tonic-gate 	if (fout == NULL) {
13720Sstevel@tonic-gate 		pr_err(gettext("could not open %s, %d"), buf, errno);
13730Sstevel@tonic-gate 		return;
13740Sstevel@tonic-gate 	}
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	fprintf(fout, "cachedir: %s\n", cachedirp);
13770Sstevel@tonic-gate 	fprintf(fout, "mnt_point: %s\n", mntp);
13780Sstevel@tonic-gate 	if (specp) {
13790Sstevel@tonic-gate 		fprintf(fout, "special: %s\n", specp);
13800Sstevel@tonic-gate 	}
13810Sstevel@tonic-gate 	if (backfsp)
13820Sstevel@tonic-gate 		fprintf(fout, "backpath: %s\n", backfsp);
13830Sstevel@tonic-gate 	fprintf(fout, "backfstype: %s\n", backfstypep);
13840Sstevel@tonic-gate 	fprintf(fout, "cacheid: %s\n", cacheidp);
13850Sstevel@tonic-gate 	fprintf(fout, "cachefs_options: %s\n", optionp);
13860Sstevel@tonic-gate 	if (reducep)
13870Sstevel@tonic-gate 		fprintf(fout, "backfs_options: %s\n", reducep);
13880Sstevel@tonic-gate 	fprintf(fout, "mount_time: %u\n", tval);
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 	fclose(fout);
13910Sstevel@tonic-gate }
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate int
daemon_notify(char * cachedirp,char * cacheidp)13940Sstevel@tonic-gate daemon_notify(char *cachedirp, char *cacheidp)
13950Sstevel@tonic-gate {
13960Sstevel@tonic-gate 	CLIENT *clnt;
13970Sstevel@tonic-gate 	enum clnt_stat retval;
13980Sstevel@tonic-gate 	int ret;
13990Sstevel@tonic-gate 	int xx;
14000Sstevel@tonic-gate 	int result;
14010Sstevel@tonic-gate 	char *hostp;
14020Sstevel@tonic-gate 	struct utsname info;
14030Sstevel@tonic-gate 	struct cachefsd_fs_mounted args;
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 	/* get the host name */
14060Sstevel@tonic-gate 	xx = uname(&info);
14070Sstevel@tonic-gate 	if (xx == -1) {
14080Sstevel@tonic-gate 		pr_err(gettext("cannot get host name, errno %d"), errno);
14090Sstevel@tonic-gate 		return (1);
14100Sstevel@tonic-gate 	}
14110Sstevel@tonic-gate 	hostp = info.nodename;
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	/* creat the connection to the daemon */
14140Sstevel@tonic-gate 	clnt = clnt_create(hostp, CACHEFSDPROG, CACHEFSDVERS, "local");
14150Sstevel@tonic-gate 	if (clnt == NULL) {
14160Sstevel@tonic-gate 		pr_err(gettext("cachefsd is not running"));
14170Sstevel@tonic-gate 		return (1);
14180Sstevel@tonic-gate 	}
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	args.mt_cachedir = cachedirp;
14210Sstevel@tonic-gate 	args.mt_cacheid = cacheidp;
14220Sstevel@tonic-gate 	retval = cachefsd_fs_mounted_1(&args, NULL, clnt);
14230Sstevel@tonic-gate 	if (retval != RPC_SUCCESS) {
14240Sstevel@tonic-gate 		clnt_perror(clnt, gettext("cachefsd is not responding"));
14250Sstevel@tonic-gate 		clnt_destroy(clnt);
14260Sstevel@tonic-gate 		return (1);
14270Sstevel@tonic-gate 	}
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 	ret = 0;
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	clnt_destroy(clnt);
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	return (ret);
14340Sstevel@tonic-gate }
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate /* returns 0 if the server is alive, -1 if an error */
14370Sstevel@tonic-gate int
pingserver(char * backmntp)14380Sstevel@tonic-gate pingserver(char *backmntp)
14390Sstevel@tonic-gate {
14400Sstevel@tonic-gate 	CLIENT *clnt;
14410Sstevel@tonic-gate 	static struct timeval TIMEOUT = { 25, 0 };
14420Sstevel@tonic-gate 	enum clnt_stat retval;
14430Sstevel@tonic-gate 	int ret;
14440Sstevel@tonic-gate 	int xx;
14450Sstevel@tonic-gate 	char *hostp;
14460Sstevel@tonic-gate 	char buf[MAXPATHLEN];
14470Sstevel@tonic-gate 	char *pc;
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 	/* get the host name */
14500Sstevel@tonic-gate 	strcpy(buf, backmntp);
14510Sstevel@tonic-gate 	pc = strchr(buf, ':');
14520Sstevel@tonic-gate 	if (pc == NULL) {
14530Sstevel@tonic-gate 		/* no host name, pretend it works */
14540Sstevel@tonic-gate 		return (0);
14550Sstevel@tonic-gate 	}
14560Sstevel@tonic-gate 	*pc = '\0';
14570Sstevel@tonic-gate 	hostp = buf;
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	/* create the connection to the mount daemon */
14600Sstevel@tonic-gate 	clnt = clnt_create(hostp, NFS_PROGRAM, NFS_VERSION, "udp");
14610Sstevel@tonic-gate 	if (clnt == NULL) {
14620Sstevel@tonic-gate 		return (-1);
14630Sstevel@tonic-gate 	}
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	ret = 0;
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate 	/* see if the mountd responds */
14680Sstevel@tonic-gate 	retval = clnt_call(clnt, 0, xdr_void, NULL, xdr_void, NULL,
14690Sstevel@tonic-gate 	    TIMEOUT);
14700Sstevel@tonic-gate 	if (retval != RPC_SUCCESS) {
14710Sstevel@tonic-gate 		ret = -1;
14720Sstevel@tonic-gate 	}
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	clnt_destroy(clnt);
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	return (ret);
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate  * first_time_ab  : first time after boot - returns non-zero value
14810Sstevel@tonic-gate  *                  if the cachedir is being used for the first time
14820Sstevel@tonic-gate  *                  after the system reboot, otherwise zero.
14830Sstevel@tonic-gate  */
14840Sstevel@tonic-gate int
first_time_ab(char * buf)14850Sstevel@tonic-gate first_time_ab(char *buf)
14860Sstevel@tonic-gate {
14870Sstevel@tonic-gate 	struct stat sinfo;
14880Sstevel@tonic-gate 	char name[MAXPATHLEN];
14890Sstevel@tonic-gate 	int ufd;
14900Sstevel@tonic-gate 	time32_t btime;
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	sprintf(name, "%s/%s", buf, CACHEFS_UNMNT_FILE);
14930Sstevel@tonic-gate 	if (stat(name, &sinfo) != 0)
14940Sstevel@tonic-gate 		return (1);
14950Sstevel@tonic-gate 	if (sinfo.st_size == 0)
14960Sstevel@tonic-gate 		return (1);
14970Sstevel@tonic-gate 	if ((ufd = open(name, O_RDONLY)) == -1)
14980Sstevel@tonic-gate 		return (1);
14990Sstevel@tonic-gate 	if (read(ufd, &btime, sizeof (time32_t)) == -1)
15000Sstevel@tonic-gate 		return (1);
15010Sstevel@tonic-gate 	close(ufd);
15020Sstevel@tonic-gate 	if (get_boottime() != btime)
15030Sstevel@tonic-gate 		return (1);
15040Sstevel@tonic-gate 	return (0);
15050Sstevel@tonic-gate }
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate /*
15080Sstevel@tonic-gate  * cachefs_get_back_nfsvers
15090Sstevel@tonic-gate  *
15100Sstevel@tonic-gate  * Returns:	nfs version
15110Sstevel@tonic-gate  *
15120Sstevel@tonic-gate  * Params:
15130Sstevel@tonic-gate  *		cfs_backfs	- backfile system mountpoint
15140Sstevel@tonic-gate  *		nomnttab	- mnttab entry does not exist
15150Sstevel@tonic-gate  *
15160Sstevel@tonic-gate  * Uses the kstat interface to extract the nfs version for
15170Sstevel@tonic-gate  * the mount.
15180Sstevel@tonic-gate  */
15190Sstevel@tonic-gate uint32_t
cachefs_get_back_nfsvers(char * cfs_backfs,int nomnttab)15200Sstevel@tonic-gate cachefs_get_back_nfsvers(char *cfs_backfs, int nomnttab)
15210Sstevel@tonic-gate {
15220Sstevel@tonic-gate 	kstat_ctl_t *kc = NULL;
15230Sstevel@tonic-gate 	FILE *mnttab = NULL;
15240Sstevel@tonic-gate 	struct extmnttab mnt;
15250Sstevel@tonic-gate 	kstat_t *ksp;
15260Sstevel@tonic-gate 	dev_t my_fsid = NODEV;
15270Sstevel@tonic-gate 	struct mntinfo_kstat mik;
15280Sstevel@tonic-gate 	uint32_t nfsvers = 0;
15290Sstevel@tonic-gate 	struct stat64 st;
15300Sstevel@tonic-gate 
15310Sstevel@tonic-gate 	/*
15320Sstevel@tonic-gate 	 * Initialize kernel statistics facility.
15330Sstevel@tonic-gate 	 */
15340Sstevel@tonic-gate 	if ((kc = kstat_open()) == NULL) {
15350Sstevel@tonic-gate 		pr_err(gettext("kstat_open() can't open /dev/kstat: %s"),
15360Sstevel@tonic-gate 			strerror(errno));
15370Sstevel@tonic-gate 		goto end;
15380Sstevel@tonic-gate 	}
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 	/*
15410Sstevel@tonic-gate 	 * Locate the mount information in the mnttab if the nomnttab
15420Sstevel@tonic-gate 	 * flag is not set, otherwise look for the entry by doing
15430Sstevel@tonic-gate 	 * stat'ting the mountpoint.
15440Sstevel@tonic-gate 	 */
15450Sstevel@tonic-gate 	if (!nomnttab) {
15460Sstevel@tonic-gate 		if ((mnttab = fopen(MNTTAB, "r")) == NULL) {
15470Sstevel@tonic-gate 			pr_err(gettext("can't open /etc/mnttab: %s"),
15480Sstevel@tonic-gate 				strerror(errno));
15490Sstevel@tonic-gate 			goto end;
15500Sstevel@tonic-gate 		}
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 		while (getextmntent(mnttab, &mnt, sizeof (mnt)) != -1) {
15530Sstevel@tonic-gate 			if (mnt.mnt_mountp == NULL ||
15540Sstevel@tonic-gate 			    strcmp(cfs_backfs, mnt.mnt_mountp) != 0) {
15550Sstevel@tonic-gate 				continue;
15560Sstevel@tonic-gate 			}
15570Sstevel@tonic-gate 			my_fsid = makedev(mnt.mnt_major, mnt.mnt_minor);
15580Sstevel@tonic-gate 			break;
15590Sstevel@tonic-gate 		}
15600Sstevel@tonic-gate 	}
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	if (my_fsid == NODEV) {
15630Sstevel@tonic-gate 		if (stat64(cfs_backfs, &st) == -1) {
15640Sstevel@tonic-gate 			pr_err(gettext("can't stat mountpoint: %s"),
15650Sstevel@tonic-gate 				strerror(errno));
15660Sstevel@tonic-gate 			goto end;
15670Sstevel@tonic-gate 		} else {
15680Sstevel@tonic-gate 			my_fsid = st.st_dev;
15690Sstevel@tonic-gate 		}
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 	}
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	/*
15740Sstevel@tonic-gate 	 * Walk the kstat control structures to locate the
15750Sstevel@tonic-gate 	 * structure that describes the nfs module/mntinfo
15760Sstevel@tonic-gate 	 * statistics for the mounted backfilesystem.
15770Sstevel@tonic-gate 	 */
15780Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 		if (ksp->ks_type != KSTAT_TYPE_RAW)
15810Sstevel@tonic-gate 			continue;
15820Sstevel@tonic-gate 		if (strcmp(ksp->ks_module, "nfs") != 0)
15830Sstevel@tonic-gate 			continue;
15840Sstevel@tonic-gate 		if (strcmp(ksp->ks_name, "mntinfo") != 0)
15850Sstevel@tonic-gate 			continue;
15860Sstevel@tonic-gate 		if ((my_fsid & MAXMIN) != ksp->ks_instance)
15870Sstevel@tonic-gate 			continue;
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 		/*
15900Sstevel@tonic-gate 		 * At this point we have located the
15910Sstevel@tonic-gate 		 * kstat info for the mount, read the
15920Sstevel@tonic-gate 		 * statistics and return version info.
15930Sstevel@tonic-gate 		 */
15940Sstevel@tonic-gate 		if (kstat_read(kc, ksp, &mik) == -1) {
15950Sstevel@tonic-gate 			pr_err(gettext("kstat_read() can't read %s/%s: %s"),
15960Sstevel@tonic-gate 				ksp->ks_module, ksp->ks_name, strerror(errno));
15970Sstevel@tonic-gate 			goto end;
15980Sstevel@tonic-gate 		}
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate 		nfsvers = mik.mik_vers;
16010Sstevel@tonic-gate 		break;
16020Sstevel@tonic-gate 	}
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate end:
16050Sstevel@tonic-gate 	if (kc)
16060Sstevel@tonic-gate 		kstat_close(kc);
16070Sstevel@tonic-gate 	if (mnttab)
16080Sstevel@tonic-gate 		fclose(mnttab);
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	return (nfsvers);
16110Sstevel@tonic-gate }
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate /*
16140Sstevel@tonic-gate  * cfs_nfsv4_build_opts
16150Sstevel@tonic-gate  *
16160Sstevel@tonic-gate  * Returns: 0 on success, -1 on failure
16170Sstevel@tonic-gate  *
16180Sstevel@tonic-gate  * Params:
16190Sstevel@tonic-gate  *	optionp		- original option pointer
16200Sstevel@tonic-gate  *	cfs_nfsv4ops	- modified options for nfsv4 cachefs mount
16210Sstevel@tonic-gate  *
16220Sstevel@tonic-gate  * Parse the comma delimited set of options specified by optionp
16230Sstevel@tonic-gate  * and clean out options that we don't want to use with NFSv4.
16240Sstevel@tonic-gate  */
16250Sstevel@tonic-gate int
cfs_nfsv4_build_opts(char * optionp,char * cfs_nfsv4ops)16260Sstevel@tonic-gate cfs_nfsv4_build_opts(char *optionp, char *cfs_nfsv4ops)
16270Sstevel@tonic-gate {
16280Sstevel@tonic-gate 	char *optstrp;
16290Sstevel@tonic-gate 	char *strp;
16300Sstevel@tonic-gate 	char *savep;
16310Sstevel@tonic-gate 	char *valp;
16320Sstevel@tonic-gate 	uint32_t first = TRUE;
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate 	/* Make a copy of the options so we can modify it */
16350Sstevel@tonic-gate 	optstrp = strp = strdup(optionp);
16360Sstevel@tonic-gate 	if (strp == NULL) {
16370Sstevel@tonic-gate 		pr_err(gettext("out of memory"));
16380Sstevel@tonic-gate 		return (-1);
16390Sstevel@tonic-gate 	}
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	/* Parse the options, cfs_nfsv4ops is initialized in main */
16420Sstevel@tonic-gate 	while (*strp) {
16430Sstevel@tonic-gate 		savep = strp;
16440Sstevel@tonic-gate 		switch (getsubopt(&strp, cfs_opts, &valp)) {
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 		/* Ignore options that set cfs option flags */
16470Sstevel@tonic-gate 		case CFSOPT_WRITEAROUND:
16480Sstevel@tonic-gate 		case CFSOPT_NONSHARED:
16490Sstevel@tonic-gate 		case CFSOPT_NOCONST:
16500Sstevel@tonic-gate 		case CFSOPT_CODCONST:
16510Sstevel@tonic-gate 		case CFSOPT_LOCALACCESS:
16520Sstevel@tonic-gate 		case CFSOPT_NOSETSEC:
16530Sstevel@tonic-gate 		case CFSOPT_LLOCK:
16540Sstevel@tonic-gate 		case CFSOPT_SLIDE:
16550Sstevel@tonic-gate 		case CFSOPT_DISCONNECTABLE:
16560Sstevel@tonic-gate 		case CFSOPT_SNR:
16570Sstevel@tonic-gate 		case CFSOPT_NOFILL:
16580Sstevel@tonic-gate 		case CFSOPT_SOFT:
16590Sstevel@tonic-gate 			break;
16600Sstevel@tonic-gate 
16610Sstevel@tonic-gate 		default:
16620Sstevel@tonic-gate 			/*
16630Sstevel@tonic-gate 			 * Copy in option for cachefs nfsv4 mount.
16640Sstevel@tonic-gate 			 */
16650Sstevel@tonic-gate 			snprintf(cfs_nfsv4ops, MAX_MNTOPT_STR,
16660Sstevel@tonic-gate 				"%s%s%s", cfs_nfsv4ops, first ? "" : ",",
16670Sstevel@tonic-gate 				savep);
16680Sstevel@tonic-gate 			first = FALSE;
16690Sstevel@tonic-gate 			break;
16700Sstevel@tonic-gate 		}
16710Sstevel@tonic-gate 	}
16720Sstevel@tonic-gate 	free(optstrp);
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	return (0);
16750Sstevel@tonic-gate }
1676