xref: /onnv-gate/usr/src/cmd/fs.d/fslib.c (revision 6734:d16dda992d39)
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
5*6734Sjohnlev  * Common Development and Distribution License (the "License").
6*6734Sjohnlev  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*6734Sjohnlev  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include	<stdio.h>
290Sstevel@tonic-gate #include	<stdarg.h>
300Sstevel@tonic-gate #include	<stdlib.h>
310Sstevel@tonic-gate #include	<unistd.h>
320Sstevel@tonic-gate #include	<libintl.h>
330Sstevel@tonic-gate #include	<string.h>
340Sstevel@tonic-gate #include	<fcntl.h>
350Sstevel@tonic-gate #include	<errno.h>
360Sstevel@tonic-gate #include	<syslog.h>
370Sstevel@tonic-gate #include	<alloca.h>
380Sstevel@tonic-gate #include	<sys/vfstab.h>
390Sstevel@tonic-gate #include	<sys/mnttab.h>
400Sstevel@tonic-gate #include	<sys/mntent.h>
410Sstevel@tonic-gate #include	<sys/mount.h>
420Sstevel@tonic-gate #include	<sys/filio.h>
430Sstevel@tonic-gate #include	<sys/fs/ufs_filio.h>
440Sstevel@tonic-gate #include	<sys/stat.h>
450Sstevel@tonic-gate #include	<sys/param.h>
460Sstevel@tonic-gate #include	<zone.h>
470Sstevel@tonic-gate #include	<signal.h>
480Sstevel@tonic-gate #include	<strings.h>
490Sstevel@tonic-gate #include	"fslib.h"
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /* LINTLIBRARY */
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #define	BUFLEN		256
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #define	TIME_MAX 16
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * Reads all of the entries from the in-kernel mnttab, and returns the
590Sstevel@tonic-gate  * linked list of the entries.
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate mntlist_t *
fsgetmntlist(void)620Sstevel@tonic-gate fsgetmntlist(void)
630Sstevel@tonic-gate {
640Sstevel@tonic-gate 	FILE *mfp;
650Sstevel@tonic-gate 	mntlist_t *mntl;
660Sstevel@tonic-gate 	char buf[BUFLEN];
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	if ((mfp = fopen(MNTTAB, "r")) == NULL) {
690Sstevel@tonic-gate 		(void) snprintf(buf, BUFLEN, "fsgetmntlist: fopen %s", MNTTAB);
700Sstevel@tonic-gate 		perror(buf);
710Sstevel@tonic-gate 		return (NULL);
720Sstevel@tonic-gate 	}
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	mntl = fsmkmntlist(mfp);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	(void) fclose(mfp);
770Sstevel@tonic-gate 	return (mntl);
780Sstevel@tonic-gate }
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 
810Sstevel@tonic-gate static struct extmnttab zmnttab = { 0 };
820Sstevel@tonic-gate 
830Sstevel@tonic-gate struct extmnttab *
fsdupmnttab(struct extmnttab * mnt)840Sstevel@tonic-gate fsdupmnttab(struct extmnttab *mnt)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	struct extmnttab *new;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	new = (struct extmnttab *)malloc(sizeof (*new));
890Sstevel@tonic-gate 	if (new == NULL)
900Sstevel@tonic-gate 		goto alloc_failed;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	*new = zmnttab;
930Sstevel@tonic-gate 	/*
940Sstevel@tonic-gate 	 * Allocate an extra byte for the mountpoint
950Sstevel@tonic-gate 	 * name in case a space needs to be added.
960Sstevel@tonic-gate 	 */
970Sstevel@tonic-gate 	new->mnt_mountp = (char *)malloc(strlen(mnt->mnt_mountp) + 2);
980Sstevel@tonic-gate 	if (new->mnt_mountp == NULL)
990Sstevel@tonic-gate 		goto alloc_failed;
1000Sstevel@tonic-gate 	(void) strcpy(new->mnt_mountp, mnt->mnt_mountp);
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	if ((new->mnt_special = strdup(mnt->mnt_special)) == NULL)
1030Sstevel@tonic-gate 		goto alloc_failed;
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	if ((new->mnt_fstype = strdup(mnt->mnt_fstype)) == NULL)
1060Sstevel@tonic-gate 		goto alloc_failed;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	if (mnt->mnt_mntopts != NULL)
1090Sstevel@tonic-gate 		if ((new->mnt_mntopts = strdup(mnt->mnt_mntopts)) == NULL)
1100Sstevel@tonic-gate 			goto alloc_failed;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	if (mnt->mnt_time != NULL)
1130Sstevel@tonic-gate 		if ((new->mnt_time = strdup(mnt->mnt_time)) == NULL)
1140Sstevel@tonic-gate 			goto alloc_failed;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	new->mnt_major = mnt->mnt_major;
1170Sstevel@tonic-gate 	new->mnt_minor = mnt->mnt_minor;
1180Sstevel@tonic-gate 	return (new);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate alloc_failed:
1210Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("fsdupmnttab: Out of memory\n"));
1220Sstevel@tonic-gate 	fsfreemnttab(new);
1230Sstevel@tonic-gate 	return (NULL);
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate  * Free a single mnttab structure
1280Sstevel@tonic-gate  */
1290Sstevel@tonic-gate void
fsfreemnttab(struct extmnttab * mnt)1300Sstevel@tonic-gate fsfreemnttab(struct extmnttab *mnt)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	if (mnt) {
1340Sstevel@tonic-gate 		if (mnt->mnt_special)
1350Sstevel@tonic-gate 			free(mnt->mnt_special);
1360Sstevel@tonic-gate 		if (mnt->mnt_mountp)
1370Sstevel@tonic-gate 			free(mnt->mnt_mountp);
1380Sstevel@tonic-gate 		if (mnt->mnt_fstype)
1390Sstevel@tonic-gate 			free(mnt->mnt_fstype);
1400Sstevel@tonic-gate 		if (mnt->mnt_mntopts)
1410Sstevel@tonic-gate 			free(mnt->mnt_mntopts);
1420Sstevel@tonic-gate 		if (mnt->mnt_time)
1430Sstevel@tonic-gate 			free(mnt->mnt_time);
1440Sstevel@tonic-gate 		free(mnt);
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate void
fsfreemntlist(mntlist_t * mntl)1490Sstevel@tonic-gate fsfreemntlist(mntlist_t *mntl)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 	mntlist_t *mntl_tmp;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	while (mntl) {
1540Sstevel@tonic-gate 		fsfreemnttab(mntl->mntl_mnt);
1550Sstevel@tonic-gate 		mntl_tmp = mntl;
1560Sstevel@tonic-gate 		mntl = mntl->mntl_next;
1570Sstevel@tonic-gate 		free(mntl_tmp);
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate  * Read the mnttab file and return it as a list of mnttab structs.
1630Sstevel@tonic-gate  * Returns NULL if there was a memory failure.
1640Sstevel@tonic-gate  */
1650Sstevel@tonic-gate mntlist_t *
fsmkmntlist(FILE * mfp)1660Sstevel@tonic-gate fsmkmntlist(FILE *mfp)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate 	struct extmnttab 	mnt;
1690Sstevel@tonic-gate 	mntlist_t 	*mhead, *mtail;
1700Sstevel@tonic-gate 	int 		ret;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	mhead = mtail = NULL;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	resetmnttab(mfp);
1750Sstevel@tonic-gate 	while ((ret = getextmntent(mfp, &mnt, sizeof (struct extmnttab)))
176*6734Sjohnlev 	    != -1) {
1770Sstevel@tonic-gate 		mntlist_t	*mp;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 		if (ret != 0)		/* bad entry */
1800Sstevel@tonic-gate 			continue;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 		mp = (mntlist_t *)malloc(sizeof (*mp));
1830Sstevel@tonic-gate 		if (mp == NULL)
1840Sstevel@tonic-gate 			goto alloc_failed;
1850Sstevel@tonic-gate 		if (mhead == NULL)
1860Sstevel@tonic-gate 			mhead = mp;
1870Sstevel@tonic-gate 		else
1880Sstevel@tonic-gate 			mtail->mntl_next = mp;
1890Sstevel@tonic-gate 		mtail = mp;
1900Sstevel@tonic-gate 		mp->mntl_next = NULL;
1910Sstevel@tonic-gate 		mp->mntl_flags = 0;
1920Sstevel@tonic-gate 		if ((mp->mntl_mnt = fsdupmnttab(&mnt)) == NULL)
1930Sstevel@tonic-gate 			goto alloc_failed;
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate 	return (mhead);
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate alloc_failed:
1980Sstevel@tonic-gate 	fsfreemntlist(mhead);
1990Sstevel@tonic-gate 	return (NULL);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate  * Return the last entry that matches mntin's special
2040Sstevel@tonic-gate  * device and/or mountpt.
2050Sstevel@tonic-gate  * Helps to be robust here, so we check for NULL pointers.
2060Sstevel@tonic-gate  */
2070Sstevel@tonic-gate mntlist_t *
fsgetmlast(mntlist_t * ml,struct mnttab * mntin)2080Sstevel@tonic-gate fsgetmlast(mntlist_t *ml, struct mnttab *mntin)
2090Sstevel@tonic-gate {
2100Sstevel@tonic-gate 	mntlist_t 	*delete = NULL;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	for (; ml; ml = ml->mntl_next) {
2130Sstevel@tonic-gate 		if (mntin->mnt_mountp && mntin->mnt_special) {
2140Sstevel@tonic-gate 			/*
2150Sstevel@tonic-gate 			 * match if and only if both are equal.
2160Sstevel@tonic-gate 			 */
2170Sstevel@tonic-gate 			if ((strcmp(ml->mntl_mnt->mnt_mountp,
218*6734Sjohnlev 			    mntin->mnt_mountp) == 0) &&
2190Sstevel@tonic-gate 			    (strcmp(ml->mntl_mnt->mnt_special,
220*6734Sjohnlev 			    mntin->mnt_special) == 0))
2210Sstevel@tonic-gate 				delete = ml;
2220Sstevel@tonic-gate 		} else if (mntin->mnt_mountp) {
2230Sstevel@tonic-gate 			if (strcmp(ml->mntl_mnt->mnt_mountp,
224*6734Sjohnlev 			    mntin->mnt_mountp) == 0)
2250Sstevel@tonic-gate 				delete = ml;
2260Sstevel@tonic-gate 		} else if (mntin->mnt_special) {
2270Sstevel@tonic-gate 			if (strcmp(ml->mntl_mnt->mnt_special,
228*6734Sjohnlev 			    mntin->mnt_special) == 0)
2290Sstevel@tonic-gate 				delete = ml;
230*6734Sjohnlev 		}
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 	return (delete);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate /*
2370Sstevel@tonic-gate  * Returns the mountlevel of the pathname in cp.  As examples,
2380Sstevel@tonic-gate  * / => 1, /bin => 2, /bin/ => 2, ////bin////ls => 3, sdf => 0, etc...
2390Sstevel@tonic-gate  */
2400Sstevel@tonic-gate int
fsgetmlevel(char * cp)2410Sstevel@tonic-gate fsgetmlevel(char *cp)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate 	int	mlevel;
2440Sstevel@tonic-gate 	char	*cp1;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	if (cp == NULL || *cp == NULL || *cp != '/')
2470Sstevel@tonic-gate 		return (0);	/* this should never happen */
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	mlevel = 1;			/* root (/) is the minimal case */
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	for (cp1 = cp + 1; *cp1; cp++, cp1++)
2520Sstevel@tonic-gate 		if (*cp == '/' && *cp1 != '/')	/* "///" counts as 1 */
2530Sstevel@tonic-gate 			mlevel++;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	return (mlevel);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate /*
2590Sstevel@tonic-gate  * Returns non-zero if string s is a member of the strings in ps.
2600Sstevel@tonic-gate  */
2610Sstevel@tonic-gate int
fsstrinlist(const char * s,const char ** ps)2620Sstevel@tonic-gate fsstrinlist(const char *s, const char **ps)
2630Sstevel@tonic-gate {
2640Sstevel@tonic-gate 	const char *cp;
2650Sstevel@tonic-gate 	cp = *ps;
2660Sstevel@tonic-gate 	while (cp) {
2670Sstevel@tonic-gate 		if (strcmp(s, cp) == 0)
2680Sstevel@tonic-gate 			return (1);
2690Sstevel@tonic-gate 		ps++;
2700Sstevel@tonic-gate 		cp = *ps;
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 	return (0);
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate static char *empty_opt_vector[] = {
2760Sstevel@tonic-gate 	NULL
2770Sstevel@tonic-gate };
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate  * Compare the mount options that were requested by the caller to
2800Sstevel@tonic-gate  * the options actually supported by the file system.  If any requested
2810Sstevel@tonic-gate  * options are not supported, print a warning message.
2820Sstevel@tonic-gate  *
2830Sstevel@tonic-gate  * WARNING: this function modifies the string pointed to by
2840Sstevel@tonic-gate  *	the requested_opts argument.
2850Sstevel@tonic-gate  *
2860Sstevel@tonic-gate  * Arguments:
2870Sstevel@tonic-gate  *	requested_opts - the string containing the requested options.
2880Sstevel@tonic-gate  *	actual_opts - the string returned by mount(2), which lists the
2890Sstevel@tonic-gate  *		options actually supported.  It is normal for this
2900Sstevel@tonic-gate  *		string to contain more options than the requested options.
2910Sstevel@tonic-gate  *		(The actual options may contain the default options, which
2920Sstevel@tonic-gate  *		may not have been included in the requested options.)
2930Sstevel@tonic-gate  *	special - device being mounted (only used in error messages).
2940Sstevel@tonic-gate  *	mountp - mount point (only used in error messages).
2950Sstevel@tonic-gate  */
2960Sstevel@tonic-gate void
cmp_requested_to_actual_options(char * requested_opts,char * actual_opts,char * special,char * mountp)2970Sstevel@tonic-gate cmp_requested_to_actual_options(char *requested_opts, char *actual_opts,
2980Sstevel@tonic-gate 	char *special, char *mountp)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	char	*option_ptr, *actopt, *equalptr;
3010Sstevel@tonic-gate 	int	found;
3020Sstevel@tonic-gate 	char	*actual_opt_hold, *bufp;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	if (requested_opts == NULL)
3050Sstevel@tonic-gate 		return;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	bufp = alloca(strlen(actual_opts) + 1);
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	while (*requested_opts != '\0') {
3100Sstevel@tonic-gate 		(void) getsubopt(&requested_opts, empty_opt_vector,
311*6734Sjohnlev 		    &option_ptr);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 		/*
3140Sstevel@tonic-gate 		 * Truncate any "=<value>" string from the end of
3150Sstevel@tonic-gate 		 * the option.
3160Sstevel@tonic-gate 		 */
3170Sstevel@tonic-gate 		if ((equalptr = strchr(option_ptr, '=')) != NULL)
3180Sstevel@tonic-gate 			*equalptr = '\0';
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 		if (*option_ptr == '\0')
3210Sstevel@tonic-gate 			continue;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 		/*
324*6734Sjohnlev 		 * Whilst we don't need this option to perform a lofi
325*6734Sjohnlev 		 * mount, let's not be mendacious enough to complain
326*6734Sjohnlev 		 * about it.
327*6734Sjohnlev 		 */
328*6734Sjohnlev 		if (strcmp(option_ptr, "loop") == 0)
329*6734Sjohnlev 			continue;
330*6734Sjohnlev 
331*6734Sjohnlev 		/*
3320Sstevel@tonic-gate 		 * Search for the requested option in the list of options
3330Sstevel@tonic-gate 		 * actually supported.
3340Sstevel@tonic-gate 		 */
3350Sstevel@tonic-gate 		found = 0;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 		/*
3380Sstevel@tonic-gate 		 * Need to use a copy of actual_opts because getsubopt
3390Sstevel@tonic-gate 		 * is destructive and we need to scan the actual_opts
3400Sstevel@tonic-gate 		 * string more than once.
3410Sstevel@tonic-gate 		 *
3420Sstevel@tonic-gate 		 * We also need to reset actual_opt_hold to the
3430Sstevel@tonic-gate 		 * beginning of the buffer because getsubopt changes
3440Sstevel@tonic-gate 		 * actual_opt_hold (the pointer).
3450Sstevel@tonic-gate 		 */
3460Sstevel@tonic-gate 		actual_opt_hold = bufp;
3470Sstevel@tonic-gate 		if (actual_opts != NULL)
3480Sstevel@tonic-gate 			(void) strcpy(actual_opt_hold, actual_opts);
3490Sstevel@tonic-gate 		else
3500Sstevel@tonic-gate 			*actual_opt_hold = '\0';
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		while (*actual_opt_hold != '\0') {
3530Sstevel@tonic-gate 			(void) getsubopt(&actual_opt_hold, empty_opt_vector,
354*6734Sjohnlev 			    &actopt);
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 			/* Truncate the "=<value>", if any. */
3570Sstevel@tonic-gate 			if ((equalptr = strchr(actopt, '=')) != NULL)
3580Sstevel@tonic-gate 				*equalptr = '\0';
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 			if ((strcmp(option_ptr, actopt)) == 0) {
3610Sstevel@tonic-gate 				found = 1;
3620Sstevel@tonic-gate 				break;
3630Sstevel@tonic-gate 			}
3640Sstevel@tonic-gate 		}
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 		if (found == 0) {
3670Sstevel@tonic-gate 			/*
3680Sstevel@tonic-gate 			 * That we're ignoring the option is always
3690Sstevel@tonic-gate 			 * truthful; the old message that the option
3700Sstevel@tonic-gate 			 * was unknown is often not correct.
3710Sstevel@tonic-gate 			 */
3720Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
3730Sstevel@tonic-gate 			    "mount: %s on %s - WARNING ignoring option "
3740Sstevel@tonic-gate 			    "\"%s\"\n"), special, mountp, option_ptr);
3750Sstevel@tonic-gate 		}
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate /*
3790Sstevel@tonic-gate  * FUNCTION:	fsgetmaxphys(int *, int *)
3800Sstevel@tonic-gate  *
3810Sstevel@tonic-gate  * INPUT:	int *maxphys - a pointer to an integer that will hold
3820Sstevel@tonic-gate  *			the value for the system maxphys value.
3830Sstevel@tonic-gate  *		int *error - 0 means completed successfully
3840Sstevel@tonic-gate  *			     otherwise this indicates the errno value.
3850Sstevel@tonic-gate  *
3860Sstevel@tonic-gate  * RETURNS:	int	- 0 if maxphys not found
3870Sstevel@tonic-gate  *			- 1 if maxphys is found
3880Sstevel@tonic-gate  */
3890Sstevel@tonic-gate int
fsgetmaxphys(int * maxphys,int * error)3900Sstevel@tonic-gate fsgetmaxphys(int *maxphys, int *error) {
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	int	gotit = 0;
3930Sstevel@tonic-gate 	int	fp = open("/", O_RDONLY);
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	*error = 0;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	/*
3980Sstevel@tonic-gate 	 * For some reason cannot open root as read only. Need a valid file
3990Sstevel@tonic-gate 	 * descriptor to call the ufs private ioctl. If this open failes,
4000Sstevel@tonic-gate 	 * just assume we cannot get maxphys in this case.
4010Sstevel@tonic-gate 	 */
4020Sstevel@tonic-gate 	if (fp == -1) {
4030Sstevel@tonic-gate 		return (gotit);
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	if (ioctl(fp, _FIOGETMAXPHYS, maxphys) == -1) {
4070Sstevel@tonic-gate 		*error = errno;
4080Sstevel@tonic-gate 		(void) close(fp);
4090Sstevel@tonic-gate 		return (gotit);
4100Sstevel@tonic-gate 	}
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	(void) close(fp);
4130Sstevel@tonic-gate 	gotit = 1;
4140Sstevel@tonic-gate 	return (gotit);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate /*
4190Sstevel@tonic-gate  * The below is limited support for zone-aware commands.
4200Sstevel@tonic-gate  */
4210Sstevel@tonic-gate struct zone_summary {
4220Sstevel@tonic-gate 	zoneid_t	zoneid;
4230Sstevel@tonic-gate 	char		rootpath[MAXPATHLEN];
4240Sstevel@tonic-gate 	size_t		rootpathlen;
4250Sstevel@tonic-gate };
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate struct zone_summary *
fs_get_zone_summaries(void)4280Sstevel@tonic-gate fs_get_zone_summaries(void)
4290Sstevel@tonic-gate {
4300Sstevel@tonic-gate 	uint_t numzones = 0, oldnumzones = 0;
4310Sstevel@tonic-gate 	uint_t i, j;
4320Sstevel@tonic-gate 	zoneid_t *ids = NULL;
4330Sstevel@tonic-gate 	struct zone_summary *summaries;
4340Sstevel@tonic-gate 	zoneid_t myzoneid = getzoneid();
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	for (;;) {
4370Sstevel@tonic-gate 		if (zone_list(ids, &numzones) < 0) {
438*6734Sjohnlev 			perror("unable to retrieve list of zones");
439*6734Sjohnlev 			if (ids != NULL)
440*6734Sjohnlev 				free(ids);
441*6734Sjohnlev 			return (NULL);
4420Sstevel@tonic-gate 		}
4430Sstevel@tonic-gate 		if (numzones <= oldnumzones)
4440Sstevel@tonic-gate 			break;
4450Sstevel@tonic-gate 		if (ids != NULL)
4460Sstevel@tonic-gate 			free(ids);
4470Sstevel@tonic-gate 		ids = malloc(numzones * sizeof (*ids));
4480Sstevel@tonic-gate 		if (ids == NULL) {
4490Sstevel@tonic-gate 			perror("malloc failed");
4500Sstevel@tonic-gate 			return (NULL);
4510Sstevel@tonic-gate 		}
4520Sstevel@tonic-gate 		oldnumzones = numzones;
4530Sstevel@tonic-gate 	}
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	summaries = malloc((numzones + 1) * sizeof (*summaries));
4560Sstevel@tonic-gate 	if (summaries == NULL) {
4570Sstevel@tonic-gate 		free(ids);
4580Sstevel@tonic-gate 		perror("malloc failed");
4590Sstevel@tonic-gate 		return (NULL);
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	for (i = 0, j = 0; i < numzones; i++) {
4640Sstevel@tonic-gate 		ssize_t len;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		if (ids[i] == myzoneid)
4670Sstevel@tonic-gate 			continue;
4680Sstevel@tonic-gate 		len = zone_getattr(ids[i], ZONE_ATTR_ROOT,
4690Sstevel@tonic-gate 		    summaries[j].rootpath, sizeof (summaries[j].rootpath));
4700Sstevel@tonic-gate 		if (len < 0) {
4710Sstevel@tonic-gate 			/*
4720Sstevel@tonic-gate 			 * Zone must have gone away. Skip.
4730Sstevel@tonic-gate 			 */
4740Sstevel@tonic-gate 			continue;
4750Sstevel@tonic-gate 		}
4760Sstevel@tonic-gate 		/*
4770Sstevel@tonic-gate 		 * Adding a trailing '/' to the zone's rootpath allows us to
4780Sstevel@tonic-gate 		 * use strncmp() to see if a given path resides within that
4790Sstevel@tonic-gate 		 * zone.
4800Sstevel@tonic-gate 		 *
4810Sstevel@tonic-gate 		 * As an example, if the zone's rootpath is "/foo/root",
4820Sstevel@tonic-gate 		 * "/foo/root/usr" resides within the zone, while
4830Sstevel@tonic-gate 		 * "/foo/rootpath" doesn't.
4840Sstevel@tonic-gate 		 */
4850Sstevel@tonic-gate 		(void) strlcat(summaries[j].rootpath, "/",
4860Sstevel@tonic-gate 		    sizeof (summaries[j].rootpath));
4870Sstevel@tonic-gate 		summaries[j].rootpathlen = len;
4880Sstevel@tonic-gate 		summaries[j].zoneid = ids[i];
4890Sstevel@tonic-gate 		j++;
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 	summaries[j].zoneid = -1;
4920Sstevel@tonic-gate 	free(ids);
4930Sstevel@tonic-gate 	return (summaries);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate static zoneid_t
fs_find_zone(const struct zone_summary * summaries,const char * mntpt)4970Sstevel@tonic-gate fs_find_zone(const struct zone_summary *summaries, const char *mntpt)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	uint_t i;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	for (i = 0; summaries[i].zoneid != -1; i++) {
5020Sstevel@tonic-gate 		if (strncmp(mntpt, summaries[i].rootpath,
5030Sstevel@tonic-gate 		    summaries[i].rootpathlen) == 0)
5040Sstevel@tonic-gate 			return (summaries[i].zoneid);
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate 	/*
5070Sstevel@tonic-gate 	 * (-1) is the special token we return to the caller if the mount
5080Sstevel@tonic-gate 	 * wasn't found in any other mounts on the system.  This means it's
5090Sstevel@tonic-gate 	 * only visible to our zone.
5100Sstevel@tonic-gate 	 *
5110Sstevel@tonic-gate 	 * Odd choice of constant, I know, but it beats calling getzoneid() a
5120Sstevel@tonic-gate 	 * million times.
5130Sstevel@tonic-gate 	 */
5140Sstevel@tonic-gate 	return (-1);
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate boolean_t
fs_mount_in_other_zone(const struct zone_summary * summaries,const char * mntpt)5180Sstevel@tonic-gate fs_mount_in_other_zone(const struct zone_summary *summaries, const char *mntpt)
5190Sstevel@tonic-gate {
5200Sstevel@tonic-gate 	return (fs_find_zone(summaries, mntpt) != -1);
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate /*
5240Sstevel@tonic-gate  * List of standard options.
5250Sstevel@tonic-gate  */
5260Sstevel@tonic-gate static const char *stdopts[] = {
5270Sstevel@tonic-gate 	MNTOPT_RO,			MNTOPT_RW,
5280Sstevel@tonic-gate 	MNTOPT_SUID,			MNTOPT_NOSUID,
5290Sstevel@tonic-gate 	MNTOPT_DEVICES,			MNTOPT_NODEVICES,
5300Sstevel@tonic-gate 	MNTOPT_SETUID,			MNTOPT_NOSETUID,
5310Sstevel@tonic-gate 	MNTOPT_NBMAND,			MNTOPT_NONBMAND,
5320Sstevel@tonic-gate 	MNTOPT_EXEC,			MNTOPT_NOEXEC,
5330Sstevel@tonic-gate };
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate #define	NSTDOPT		(sizeof (stdopts) / sizeof (stdopts[0]))
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate static int
optindx(const char * opt)5380Sstevel@tonic-gate optindx(const char *opt)
5390Sstevel@tonic-gate {
5400Sstevel@tonic-gate 	int i;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	for (i = 0; i < NSTDOPT; i++) {
5430Sstevel@tonic-gate 		if (strcmp(opt, stdopts[i]) == 0)
5440Sstevel@tonic-gate 			return (i);
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate 	return (-1);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate /*
5500Sstevel@tonic-gate  * INPUT:	filesystem option not recognized by the fs specific option
5510Sstevel@tonic-gate  *		parsing code.
5520Sstevel@tonic-gate  * OUTPUT:	True if and only if the option is one of the standard VFS
5530Sstevel@tonic-gate  *		layer options.
5540Sstevel@tonic-gate  */
5550Sstevel@tonic-gate boolean_t
fsisstdopt(const char * opt)5560Sstevel@tonic-gate fsisstdopt(const char *opt)
5570Sstevel@tonic-gate {
5580Sstevel@tonic-gate 	return (optindx(opt) != -1);
5590Sstevel@tonic-gate }
560