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 ¬ify, &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