xref: /illumos-gate/usr/src/cmd/fs.d/fslib.c (revision 8509e9caaaa43d21ab1a18a2aa45b43322c378ac)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
593239addSjohnlev  * Common Development and Distribution License (the "License").
693239addSjohnlev  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2293239addSjohnlev  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include	<stdio.h>
277c478bd9Sstevel@tonic-gate #include	<stdarg.h>
287c478bd9Sstevel@tonic-gate #include	<stdlib.h>
297c478bd9Sstevel@tonic-gate #include	<unistd.h>
307c478bd9Sstevel@tonic-gate #include	<libintl.h>
317c478bd9Sstevel@tonic-gate #include	<string.h>
327c478bd9Sstevel@tonic-gate #include	<fcntl.h>
337c478bd9Sstevel@tonic-gate #include	<errno.h>
347c478bd9Sstevel@tonic-gate #include	<syslog.h>
357c478bd9Sstevel@tonic-gate #include	<alloca.h>
367c478bd9Sstevel@tonic-gate #include	<sys/vfstab.h>
377c478bd9Sstevel@tonic-gate #include	<sys/mnttab.h>
387c478bd9Sstevel@tonic-gate #include	<sys/mntent.h>
397c478bd9Sstevel@tonic-gate #include	<sys/mount.h>
407c478bd9Sstevel@tonic-gate #include	<sys/filio.h>
417c478bd9Sstevel@tonic-gate #include	<sys/fs/ufs_filio.h>
427c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
437c478bd9Sstevel@tonic-gate #include	<sys/param.h>
447c478bd9Sstevel@tonic-gate #include	<zone.h>
457c478bd9Sstevel@tonic-gate #include	<signal.h>
467c478bd9Sstevel@tonic-gate #include	<strings.h>
477c478bd9Sstevel@tonic-gate #include	"fslib.h"
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /* LINTLIBRARY */
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #define	BUFLEN		256
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #define	TIME_MAX 16
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /*
567c478bd9Sstevel@tonic-gate  * Reads all of the entries from the in-kernel mnttab, and returns the
577c478bd9Sstevel@tonic-gate  * linked list of the entries.
587c478bd9Sstevel@tonic-gate  */
597c478bd9Sstevel@tonic-gate mntlist_t *
fsgetmntlist(void)607c478bd9Sstevel@tonic-gate fsgetmntlist(void)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate 	FILE *mfp;
637c478bd9Sstevel@tonic-gate 	mntlist_t *mntl;
647c478bd9Sstevel@tonic-gate 	char buf[BUFLEN];
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	if ((mfp = fopen(MNTTAB, "r")) == NULL) {
677c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, BUFLEN, "fsgetmntlist: fopen %s", MNTTAB);
687c478bd9Sstevel@tonic-gate 		perror(buf);
697c478bd9Sstevel@tonic-gate 		return (NULL);
707c478bd9Sstevel@tonic-gate 	}
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	mntl = fsmkmntlist(mfp);
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	(void) fclose(mfp);
757c478bd9Sstevel@tonic-gate 	return (mntl);
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static struct extmnttab zmnttab = { 0 };
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate struct extmnttab *
fsdupmnttab(struct extmnttab * mnt)827c478bd9Sstevel@tonic-gate fsdupmnttab(struct extmnttab *mnt)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate 	struct extmnttab *new;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	new = (struct extmnttab *)malloc(sizeof (*new));
877c478bd9Sstevel@tonic-gate 	if (new == NULL)
887c478bd9Sstevel@tonic-gate 		goto alloc_failed;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	*new = zmnttab;
917c478bd9Sstevel@tonic-gate 	/*
927c478bd9Sstevel@tonic-gate 	 * Allocate an extra byte for the mountpoint
937c478bd9Sstevel@tonic-gate 	 * name in case a space needs to be added.
947c478bd9Sstevel@tonic-gate 	 */
957c478bd9Sstevel@tonic-gate 	new->mnt_mountp = (char *)malloc(strlen(mnt->mnt_mountp) + 2);
967c478bd9Sstevel@tonic-gate 	if (new->mnt_mountp == NULL)
977c478bd9Sstevel@tonic-gate 		goto alloc_failed;
987c478bd9Sstevel@tonic-gate 	(void) strcpy(new->mnt_mountp, mnt->mnt_mountp);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	if ((new->mnt_special = strdup(mnt->mnt_special)) == NULL)
1017c478bd9Sstevel@tonic-gate 		goto alloc_failed;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	if ((new->mnt_fstype = strdup(mnt->mnt_fstype)) == NULL)
1047c478bd9Sstevel@tonic-gate 		goto alloc_failed;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	if (mnt->mnt_mntopts != NULL)
1077c478bd9Sstevel@tonic-gate 		if ((new->mnt_mntopts = strdup(mnt->mnt_mntopts)) == NULL)
1087c478bd9Sstevel@tonic-gate 			goto alloc_failed;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	if (mnt->mnt_time != NULL)
1117c478bd9Sstevel@tonic-gate 		if ((new->mnt_time = strdup(mnt->mnt_time)) == NULL)
1127c478bd9Sstevel@tonic-gate 			goto alloc_failed;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	new->mnt_major = mnt->mnt_major;
1157c478bd9Sstevel@tonic-gate 	new->mnt_minor = mnt->mnt_minor;
1167c478bd9Sstevel@tonic-gate 	return (new);
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate alloc_failed:
1197c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("fsdupmnttab: Out of memory\n"));
1207c478bd9Sstevel@tonic-gate 	fsfreemnttab(new);
1217c478bd9Sstevel@tonic-gate 	return (NULL);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * Free a single mnttab structure
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate void
fsfreemnttab(struct extmnttab * mnt)1287c478bd9Sstevel@tonic-gate fsfreemnttab(struct extmnttab *mnt)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	if (mnt) {
1327c478bd9Sstevel@tonic-gate 		if (mnt->mnt_special)
1337c478bd9Sstevel@tonic-gate 			free(mnt->mnt_special);
1347c478bd9Sstevel@tonic-gate 		if (mnt->mnt_mountp)
1357c478bd9Sstevel@tonic-gate 			free(mnt->mnt_mountp);
1367c478bd9Sstevel@tonic-gate 		if (mnt->mnt_fstype)
1377c478bd9Sstevel@tonic-gate 			free(mnt->mnt_fstype);
1387c478bd9Sstevel@tonic-gate 		if (mnt->mnt_mntopts)
1397c478bd9Sstevel@tonic-gate 			free(mnt->mnt_mntopts);
1407c478bd9Sstevel@tonic-gate 		if (mnt->mnt_time)
1417c478bd9Sstevel@tonic-gate 			free(mnt->mnt_time);
1427c478bd9Sstevel@tonic-gate 		free(mnt);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate void
fsfreemntlist(mntlist_t * mntl)1477c478bd9Sstevel@tonic-gate fsfreemntlist(mntlist_t *mntl)
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate 	mntlist_t *mntl_tmp;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	while (mntl) {
1527c478bd9Sstevel@tonic-gate 		fsfreemnttab(mntl->mntl_mnt);
1537c478bd9Sstevel@tonic-gate 		mntl_tmp = mntl;
1547c478bd9Sstevel@tonic-gate 		mntl = mntl->mntl_next;
1557c478bd9Sstevel@tonic-gate 		free(mntl_tmp);
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * Read the mnttab file and return it as a list of mnttab structs.
1617c478bd9Sstevel@tonic-gate  * Returns NULL if there was a memory failure.
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate mntlist_t *
fsmkmntlist(FILE * mfp)1647c478bd9Sstevel@tonic-gate fsmkmntlist(FILE *mfp)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate 	struct extmnttab	mnt;
1677c478bd9Sstevel@tonic-gate 	mntlist_t	*mhead, *mtail;
1687c478bd9Sstevel@tonic-gate 	int		ret;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	mhead = mtail = NULL;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	resetmnttab(mfp);
1737c478bd9Sstevel@tonic-gate 	while ((ret = getextmntent(mfp, &mnt, sizeof (struct extmnttab)))
1747c478bd9Sstevel@tonic-gate 	    != -1) {
1757c478bd9Sstevel@tonic-gate 		mntlist_t	*mp;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		if (ret != 0)		/* bad entry */
1787c478bd9Sstevel@tonic-gate 			continue;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 		mp = (mntlist_t *)malloc(sizeof (*mp));
1817c478bd9Sstevel@tonic-gate 		if (mp == NULL)
1827c478bd9Sstevel@tonic-gate 			goto alloc_failed;
1837c478bd9Sstevel@tonic-gate 		if (mhead == NULL)
1847c478bd9Sstevel@tonic-gate 			mhead = mp;
1857c478bd9Sstevel@tonic-gate 		else
1867c478bd9Sstevel@tonic-gate 			mtail->mntl_next = mp;
1877c478bd9Sstevel@tonic-gate 		mtail = mp;
1887c478bd9Sstevel@tonic-gate 		mp->mntl_next = NULL;
1897c478bd9Sstevel@tonic-gate 		mp->mntl_flags = 0;
1907c478bd9Sstevel@tonic-gate 		if ((mp->mntl_mnt = fsdupmnttab(&mnt)) == NULL)
1917c478bd9Sstevel@tonic-gate 			goto alloc_failed;
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 	return (mhead);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate alloc_failed:
1967c478bd9Sstevel@tonic-gate 	fsfreemntlist(mhead);
1977c478bd9Sstevel@tonic-gate 	return (NULL);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate  * Return the last entry that matches mntin's special
2027c478bd9Sstevel@tonic-gate  * device and/or mountpt.
2037c478bd9Sstevel@tonic-gate  * Helps to be robust here, so we check for NULL pointers.
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate mntlist_t *
fsgetmlast(mntlist_t * ml,struct mnttab * mntin)2067c478bd9Sstevel@tonic-gate fsgetmlast(mntlist_t *ml, struct mnttab *mntin)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	mntlist_t	*delete = NULL;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	for (; ml; ml = ml->mntl_next) {
2117c478bd9Sstevel@tonic-gate 		if (mntin->mnt_mountp && mntin->mnt_special) {
2127c478bd9Sstevel@tonic-gate 			/*
2137c478bd9Sstevel@tonic-gate 			 * match if and only if both are equal.
2147c478bd9Sstevel@tonic-gate 			 */
2157c478bd9Sstevel@tonic-gate 			if ((strcmp(ml->mntl_mnt->mnt_mountp,
2167c478bd9Sstevel@tonic-gate 			    mntin->mnt_mountp) == 0) &&
2177c478bd9Sstevel@tonic-gate 			    (strcmp(ml->mntl_mnt->mnt_special,
2187c478bd9Sstevel@tonic-gate 			    mntin->mnt_special) == 0))
2197c478bd9Sstevel@tonic-gate 				delete = ml;
2207c478bd9Sstevel@tonic-gate 		} else if (mntin->mnt_mountp) {
2217c478bd9Sstevel@tonic-gate 			if (strcmp(ml->mntl_mnt->mnt_mountp,
2227c478bd9Sstevel@tonic-gate 			    mntin->mnt_mountp) == 0)
2237c478bd9Sstevel@tonic-gate 				delete = ml;
2247c478bd9Sstevel@tonic-gate 		} else if (mntin->mnt_special) {
2257c478bd9Sstevel@tonic-gate 			if (strcmp(ml->mntl_mnt->mnt_special,
2267c478bd9Sstevel@tonic-gate 			    mntin->mnt_special) == 0)
2277c478bd9Sstevel@tonic-gate 				delete = ml;
2287c478bd9Sstevel@tonic-gate 		}
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 	return (delete);
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate  * Returns the mountlevel of the pathname in cp.  As examples,
2367c478bd9Sstevel@tonic-gate  * / => 1, /bin => 2, /bin/ => 2, ////bin////ls => 3, sdf => 0, etc...
2377c478bd9Sstevel@tonic-gate  */
2387c478bd9Sstevel@tonic-gate int
fsgetmlevel(char * cp)2397c478bd9Sstevel@tonic-gate fsgetmlevel(char *cp)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	int	mlevel;
2427c478bd9Sstevel@tonic-gate 	char	*cp1;
2437c478bd9Sstevel@tonic-gate 
244*8509e9caSToomas Soome 	if (cp == NULL || *cp == '\0' || *cp != '/')
2457c478bd9Sstevel@tonic-gate 		return (0);	/* this should never happen */
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	mlevel = 1;			/* root (/) is the minimal case */
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	for (cp1 = cp + 1; *cp1; cp++, cp1++)
2507c478bd9Sstevel@tonic-gate 		if (*cp == '/' && *cp1 != '/')	/* "///" counts as 1 */
2517c478bd9Sstevel@tonic-gate 			mlevel++;
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	return (mlevel);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate  * Returns non-zero if string s is a member of the strings in ps.
2587c478bd9Sstevel@tonic-gate  */
2597c478bd9Sstevel@tonic-gate int
fsstrinlist(const char * s,const char ** ps)2607c478bd9Sstevel@tonic-gate fsstrinlist(const char *s, const char **ps)
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate 	const char *cp;
2637c478bd9Sstevel@tonic-gate 	cp = *ps;
2647c478bd9Sstevel@tonic-gate 	while (cp) {
2657c478bd9Sstevel@tonic-gate 		if (strcmp(s, cp) == 0)
2667c478bd9Sstevel@tonic-gate 			return (1);
2677c478bd9Sstevel@tonic-gate 		ps++;
2687c478bd9Sstevel@tonic-gate 		cp = *ps;
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 	return (0);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate static char *empty_opt_vector[] = {
2747c478bd9Sstevel@tonic-gate 	NULL
2757c478bd9Sstevel@tonic-gate };
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate  * Compare the mount options that were requested by the caller to
2787c478bd9Sstevel@tonic-gate  * the options actually supported by the file system.  If any requested
2797c478bd9Sstevel@tonic-gate  * options are not supported, print a warning message.
2807c478bd9Sstevel@tonic-gate  *
2817c478bd9Sstevel@tonic-gate  * WARNING: this function modifies the string pointed to by
2827c478bd9Sstevel@tonic-gate  *	the requested_opts argument.
2837c478bd9Sstevel@tonic-gate  *
2847c478bd9Sstevel@tonic-gate  * Arguments:
2857c478bd9Sstevel@tonic-gate  *	requested_opts - the string containing the requested options.
2867c478bd9Sstevel@tonic-gate  *	actual_opts - the string returned by mount(2), which lists the
2877c478bd9Sstevel@tonic-gate  *		options actually supported.  It is normal for this
2887c478bd9Sstevel@tonic-gate  *		string to contain more options than the requested options.
2897c478bd9Sstevel@tonic-gate  *		(The actual options may contain the default options, which
2907c478bd9Sstevel@tonic-gate  *		may not have been included in the requested options.)
2917c478bd9Sstevel@tonic-gate  *	special - device being mounted (only used in error messages).
2927c478bd9Sstevel@tonic-gate  *	mountp - mount point (only used in error messages).
2937c478bd9Sstevel@tonic-gate  */
2947c478bd9Sstevel@tonic-gate void
cmp_requested_to_actual_options(char * requested_opts,char * actual_opts,char * special,char * mountp)2957c478bd9Sstevel@tonic-gate cmp_requested_to_actual_options(char *requested_opts, char *actual_opts,
2967c478bd9Sstevel@tonic-gate 	char *special, char *mountp)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	char	*option_ptr, *actopt, *equalptr;
2997c478bd9Sstevel@tonic-gate 	int	found;
3007c478bd9Sstevel@tonic-gate 	char	*actual_opt_hold, *bufp;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	if (requested_opts == NULL)
3037c478bd9Sstevel@tonic-gate 		return;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	bufp = alloca(strlen(actual_opts) + 1);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	while (*requested_opts != '\0') {
3087c478bd9Sstevel@tonic-gate 		(void) getsubopt(&requested_opts, empty_opt_vector,
3097c478bd9Sstevel@tonic-gate 		    &option_ptr);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 		/*
3127c478bd9Sstevel@tonic-gate 		 * Truncate any "=<value>" string from the end of
3137c478bd9Sstevel@tonic-gate 		 * the option.
3147c478bd9Sstevel@tonic-gate 		 */
3157c478bd9Sstevel@tonic-gate 		if ((equalptr = strchr(option_ptr, '=')) != NULL)
3167c478bd9Sstevel@tonic-gate 			*equalptr = '\0';
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 		if (*option_ptr == '\0')
3197c478bd9Sstevel@tonic-gate 			continue;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 		/*
32293239addSjohnlev 		 * Whilst we don't need this option to perform a lofi
32393239addSjohnlev 		 * mount, let's not be mendacious enough to complain
32493239addSjohnlev 		 * about it.
32593239addSjohnlev 		 */
32693239addSjohnlev 		if (strcmp(option_ptr, "loop") == 0)
32793239addSjohnlev 			continue;
32893239addSjohnlev 
32993239addSjohnlev 		/*
3307c478bd9Sstevel@tonic-gate 		 * Search for the requested option in the list of options
3317c478bd9Sstevel@tonic-gate 		 * actually supported.
3327c478bd9Sstevel@tonic-gate 		 */
3337c478bd9Sstevel@tonic-gate 		found = 0;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 		/*
3367c478bd9Sstevel@tonic-gate 		 * Need to use a copy of actual_opts because getsubopt
3377c478bd9Sstevel@tonic-gate 		 * is destructive and we need to scan the actual_opts
3387c478bd9Sstevel@tonic-gate 		 * string more than once.
3397c478bd9Sstevel@tonic-gate 		 *
3407c478bd9Sstevel@tonic-gate 		 * We also need to reset actual_opt_hold to the
3417c478bd9Sstevel@tonic-gate 		 * beginning of the buffer because getsubopt changes
3427c478bd9Sstevel@tonic-gate 		 * actual_opt_hold (the pointer).
3437c478bd9Sstevel@tonic-gate 		 */
3447c478bd9Sstevel@tonic-gate 		actual_opt_hold = bufp;
3457c478bd9Sstevel@tonic-gate 		if (actual_opts != NULL)
3467c478bd9Sstevel@tonic-gate 			(void) strcpy(actual_opt_hold, actual_opts);
3477c478bd9Sstevel@tonic-gate 		else
3487c478bd9Sstevel@tonic-gate 			*actual_opt_hold = '\0';
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 		while (*actual_opt_hold != '\0') {
3517c478bd9Sstevel@tonic-gate 			(void) getsubopt(&actual_opt_hold, empty_opt_vector,
3527c478bd9Sstevel@tonic-gate 			    &actopt);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 			/* Truncate the "=<value>", if any. */
3557c478bd9Sstevel@tonic-gate 			if ((equalptr = strchr(actopt, '=')) != NULL)
3567c478bd9Sstevel@tonic-gate 				*equalptr = '\0';
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 			if ((strcmp(option_ptr, actopt)) == 0) {
3597c478bd9Sstevel@tonic-gate 				found = 1;
3607c478bd9Sstevel@tonic-gate 				break;
3617c478bd9Sstevel@tonic-gate 			}
3627c478bd9Sstevel@tonic-gate 		}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 		if (found == 0) {
3657c478bd9Sstevel@tonic-gate 			/*
3667c478bd9Sstevel@tonic-gate 			 * That we're ignoring the option is always
3677c478bd9Sstevel@tonic-gate 			 * truthful; the old message that the option
3687c478bd9Sstevel@tonic-gate 			 * was unknown is often not correct.
3697c478bd9Sstevel@tonic-gate 			 */
3707c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
3717c478bd9Sstevel@tonic-gate 			    "mount: %s on %s - WARNING ignoring option "
3727c478bd9Sstevel@tonic-gate 			    "\"%s\"\n"), special, mountp, option_ptr);
3737c478bd9Sstevel@tonic-gate 		}
3747c478bd9Sstevel@tonic-gate 	}
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate  * FUNCTION:	fsgetmaxphys(int *, int *)
3787c478bd9Sstevel@tonic-gate  *
3797c478bd9Sstevel@tonic-gate  * INPUT:	int *maxphys - a pointer to an integer that will hold
3807c478bd9Sstevel@tonic-gate  *			the value for the system maxphys value.
3817c478bd9Sstevel@tonic-gate  *		int *error - 0 means completed successfully
3827c478bd9Sstevel@tonic-gate  *			     otherwise this indicates the errno value.
3837c478bd9Sstevel@tonic-gate  *
3847c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 if maxphys not found
3857c478bd9Sstevel@tonic-gate  *			- 1 if maxphys is found
3867c478bd9Sstevel@tonic-gate  */
3877c478bd9Sstevel@tonic-gate int
fsgetmaxphys(int * maxphys,int * error)3887c478bd9Sstevel@tonic-gate fsgetmaxphys(int *maxphys, int *error) {
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	int	gotit = 0;
3917c478bd9Sstevel@tonic-gate 	int	fp = open("/", O_RDONLY);
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	*error = 0;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/*
3967c478bd9Sstevel@tonic-gate 	 * For some reason cannot open root as read only. Need a valid file
3977c478bd9Sstevel@tonic-gate 	 * descriptor to call the ufs private ioctl. If this open failes,
3987c478bd9Sstevel@tonic-gate 	 * just assume we cannot get maxphys in this case.
3997c478bd9Sstevel@tonic-gate 	 */
4007c478bd9Sstevel@tonic-gate 	if (fp == -1) {
4017c478bd9Sstevel@tonic-gate 		return (gotit);
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	if (ioctl(fp, _FIOGETMAXPHYS, maxphys) == -1) {
4057c478bd9Sstevel@tonic-gate 		*error = errno;
4067c478bd9Sstevel@tonic-gate 		(void) close(fp);
4077c478bd9Sstevel@tonic-gate 		return (gotit);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	(void) close(fp);
4117c478bd9Sstevel@tonic-gate 	gotit = 1;
4127c478bd9Sstevel@tonic-gate 	return (gotit);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate  * The below is limited support for zone-aware commands.
4187c478bd9Sstevel@tonic-gate  */
4197c478bd9Sstevel@tonic-gate struct zone_summary {
4207c478bd9Sstevel@tonic-gate 	zoneid_t	zoneid;
4217c478bd9Sstevel@tonic-gate 	char		rootpath[MAXPATHLEN];
4227c478bd9Sstevel@tonic-gate 	size_t		rootpathlen;
4237c478bd9Sstevel@tonic-gate };
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate struct zone_summary *
fs_get_zone_summaries(void)4267c478bd9Sstevel@tonic-gate fs_get_zone_summaries(void)
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate 	uint_t numzones = 0, oldnumzones = 0;
4297c478bd9Sstevel@tonic-gate 	uint_t i, j;
4307c478bd9Sstevel@tonic-gate 	zoneid_t *ids = NULL;
4317c478bd9Sstevel@tonic-gate 	struct zone_summary *summaries;
4327c478bd9Sstevel@tonic-gate 	zoneid_t myzoneid = getzoneid();
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	for (;;) {
4357c478bd9Sstevel@tonic-gate 		if (zone_list(ids, &numzones) < 0) {
4367c478bd9Sstevel@tonic-gate 			perror("unable to retrieve list of zones");
4377c478bd9Sstevel@tonic-gate 			if (ids != NULL)
4387c478bd9Sstevel@tonic-gate 				free(ids);
4397c478bd9Sstevel@tonic-gate 			return (NULL);
4407c478bd9Sstevel@tonic-gate 		}
4417c478bd9Sstevel@tonic-gate 		if (numzones <= oldnumzones)
4427c478bd9Sstevel@tonic-gate 			break;
4437c478bd9Sstevel@tonic-gate 		if (ids != NULL)
4447c478bd9Sstevel@tonic-gate 			free(ids);
4457c478bd9Sstevel@tonic-gate 		ids = malloc(numzones * sizeof (*ids));
4467c478bd9Sstevel@tonic-gate 		if (ids == NULL) {
4477c478bd9Sstevel@tonic-gate 			perror("malloc failed");
4487c478bd9Sstevel@tonic-gate 			return (NULL);
4497c478bd9Sstevel@tonic-gate 		}
4507c478bd9Sstevel@tonic-gate 		oldnumzones = numzones;
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	summaries = malloc((numzones + 1) * sizeof (*summaries));
4547c478bd9Sstevel@tonic-gate 	if (summaries == NULL) {
4557c478bd9Sstevel@tonic-gate 		free(ids);
4567c478bd9Sstevel@tonic-gate 		perror("malloc failed");
4577c478bd9Sstevel@tonic-gate 		return (NULL);
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	for (i = 0, j = 0; i < numzones; i++) {
4627c478bd9Sstevel@tonic-gate 		ssize_t len;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 		if (ids[i] == myzoneid)
4657c478bd9Sstevel@tonic-gate 			continue;
4667c478bd9Sstevel@tonic-gate 		len = zone_getattr(ids[i], ZONE_ATTR_ROOT,
4677c478bd9Sstevel@tonic-gate 		    summaries[j].rootpath, sizeof (summaries[j].rootpath));
4687c478bd9Sstevel@tonic-gate 		if (len < 0) {
4697c478bd9Sstevel@tonic-gate 			/*
4707c478bd9Sstevel@tonic-gate 			 * Zone must have gone away. Skip.
4717c478bd9Sstevel@tonic-gate 			 */
4727c478bd9Sstevel@tonic-gate 			continue;
4737c478bd9Sstevel@tonic-gate 		}
4747c478bd9Sstevel@tonic-gate 		/*
4757c478bd9Sstevel@tonic-gate 		 * Adding a trailing '/' to the zone's rootpath allows us to
4767c478bd9Sstevel@tonic-gate 		 * use strncmp() to see if a given path resides within that
4777c478bd9Sstevel@tonic-gate 		 * zone.
4787c478bd9Sstevel@tonic-gate 		 *
4797c478bd9Sstevel@tonic-gate 		 * As an example, if the zone's rootpath is "/foo/root",
4807c478bd9Sstevel@tonic-gate 		 * "/foo/root/usr" resides within the zone, while
4817c478bd9Sstevel@tonic-gate 		 * "/foo/rootpath" doesn't.
4827c478bd9Sstevel@tonic-gate 		 */
4837c478bd9Sstevel@tonic-gate 		(void) strlcat(summaries[j].rootpath, "/",
4847c478bd9Sstevel@tonic-gate 		    sizeof (summaries[j].rootpath));
4857c478bd9Sstevel@tonic-gate 		summaries[j].rootpathlen = len;
4867c478bd9Sstevel@tonic-gate 		summaries[j].zoneid = ids[i];
4877c478bd9Sstevel@tonic-gate 		j++;
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 	summaries[j].zoneid = -1;
4907c478bd9Sstevel@tonic-gate 	free(ids);
4917c478bd9Sstevel@tonic-gate 	return (summaries);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate static zoneid_t
fs_find_zone(const struct zone_summary * summaries,const char * mntpt)4957c478bd9Sstevel@tonic-gate fs_find_zone(const struct zone_summary *summaries, const char *mntpt)
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate 	uint_t i;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	for (i = 0; summaries[i].zoneid != -1; i++) {
5007c478bd9Sstevel@tonic-gate 		if (strncmp(mntpt, summaries[i].rootpath,
5017c478bd9Sstevel@tonic-gate 		    summaries[i].rootpathlen) == 0)
5027c478bd9Sstevel@tonic-gate 			return (summaries[i].zoneid);
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 	/*
5057c478bd9Sstevel@tonic-gate 	 * (-1) is the special token we return to the caller if the mount
5067c478bd9Sstevel@tonic-gate 	 * wasn't found in any other mounts on the system.  This means it's
5077c478bd9Sstevel@tonic-gate 	 * only visible to our zone.
5087c478bd9Sstevel@tonic-gate 	 *
5097c478bd9Sstevel@tonic-gate 	 * Odd choice of constant, I know, but it beats calling getzoneid() a
5107c478bd9Sstevel@tonic-gate 	 * million times.
5117c478bd9Sstevel@tonic-gate 	 */
5127c478bd9Sstevel@tonic-gate 	return (-1);
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate boolean_t
fs_mount_in_other_zone(const struct zone_summary * summaries,const char * mntpt)5167c478bd9Sstevel@tonic-gate fs_mount_in_other_zone(const struct zone_summary *summaries, const char *mntpt)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	return (fs_find_zone(summaries, mntpt) != -1);
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate /*
5227c478bd9Sstevel@tonic-gate  * List of standard options.
5237c478bd9Sstevel@tonic-gate  */
5247c478bd9Sstevel@tonic-gate static const char *stdopts[] = {
5257c478bd9Sstevel@tonic-gate 	MNTOPT_RO,			MNTOPT_RW,
5267c478bd9Sstevel@tonic-gate 	MNTOPT_SUID,			MNTOPT_NOSUID,
5277c478bd9Sstevel@tonic-gate 	MNTOPT_DEVICES,			MNTOPT_NODEVICES,
5287c478bd9Sstevel@tonic-gate 	MNTOPT_SETUID,			MNTOPT_NOSETUID,
5297c478bd9Sstevel@tonic-gate 	MNTOPT_NBMAND,			MNTOPT_NONBMAND,
5307c478bd9Sstevel@tonic-gate 	MNTOPT_EXEC,			MNTOPT_NOEXEC,
5317c478bd9Sstevel@tonic-gate };
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate #define	NSTDOPT		(sizeof (stdopts) / sizeof (stdopts[0]))
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate static int
optindx(const char * opt)5367c478bd9Sstevel@tonic-gate optindx(const char *opt)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate 	int i;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	for (i = 0; i < NSTDOPT; i++) {
5417c478bd9Sstevel@tonic-gate 		if (strcmp(opt, stdopts[i]) == 0)
5427c478bd9Sstevel@tonic-gate 			return (i);
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 	return (-1);
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate /*
5487c478bd9Sstevel@tonic-gate  * INPUT:	filesystem option not recognized by the fs specific option
5497c478bd9Sstevel@tonic-gate  *		parsing code.
5507c478bd9Sstevel@tonic-gate  * OUTPUT:	True if and only if the option is one of the standard VFS
5517c478bd9Sstevel@tonic-gate  *		layer options.
5527c478bd9Sstevel@tonic-gate  */
5537c478bd9Sstevel@tonic-gate boolean_t
fsisstdopt(const char * opt)5547c478bd9Sstevel@tonic-gate fsisstdopt(const char *opt)
5557c478bd9Sstevel@tonic-gate {
5567c478bd9Sstevel@tonic-gate 	return (optindx(opt) != -1);
5577c478bd9Sstevel@tonic-gate }
558