xref: /titanic_53/usr/src/cmd/fs.d/fslib.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include	<stdio.h>
30*7c478bd9Sstevel@tonic-gate #include	<stdarg.h>
31*7c478bd9Sstevel@tonic-gate #include	<stdlib.h>
32*7c478bd9Sstevel@tonic-gate #include	<unistd.h>
33*7c478bd9Sstevel@tonic-gate #include	<libintl.h>
34*7c478bd9Sstevel@tonic-gate #include	<string.h>
35*7c478bd9Sstevel@tonic-gate #include	<fcntl.h>
36*7c478bd9Sstevel@tonic-gate #include	<errno.h>
37*7c478bd9Sstevel@tonic-gate #include	<syslog.h>
38*7c478bd9Sstevel@tonic-gate #include	<alloca.h>
39*7c478bd9Sstevel@tonic-gate #include	<sys/vfstab.h>
40*7c478bd9Sstevel@tonic-gate #include	<sys/mnttab.h>
41*7c478bd9Sstevel@tonic-gate #include	<sys/mntent.h>
42*7c478bd9Sstevel@tonic-gate #include	<sys/mount.h>
43*7c478bd9Sstevel@tonic-gate #include	<sys/filio.h>
44*7c478bd9Sstevel@tonic-gate #include	<sys/fs/ufs_filio.h>
45*7c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
46*7c478bd9Sstevel@tonic-gate #include	<sys/param.h>
47*7c478bd9Sstevel@tonic-gate #include	<zone.h>
48*7c478bd9Sstevel@tonic-gate #include	<signal.h>
49*7c478bd9Sstevel@tonic-gate #include	<strings.h>
50*7c478bd9Sstevel@tonic-gate #include	"fslib.h"
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /* LINTLIBRARY */
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #define	BUFLEN		256
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #define	TIME_MAX 16
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate /*
59*7c478bd9Sstevel@tonic-gate  * Reads all of the entries from the in-kernel mnttab, and returns the
60*7c478bd9Sstevel@tonic-gate  * linked list of the entries.
61*7c478bd9Sstevel@tonic-gate  */
62*7c478bd9Sstevel@tonic-gate mntlist_t *
63*7c478bd9Sstevel@tonic-gate fsgetmntlist(void)
64*7c478bd9Sstevel@tonic-gate {
65*7c478bd9Sstevel@tonic-gate 	FILE *mfp;
66*7c478bd9Sstevel@tonic-gate 	mntlist_t *mntl;
67*7c478bd9Sstevel@tonic-gate 	char buf[BUFLEN];
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 	if ((mfp = fopen(MNTTAB, "r")) == NULL) {
70*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, BUFLEN, "fsgetmntlist: fopen %s", MNTTAB);
71*7c478bd9Sstevel@tonic-gate 		perror(buf);
72*7c478bd9Sstevel@tonic-gate 		return (NULL);
73*7c478bd9Sstevel@tonic-gate 	}
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 	mntl = fsmkmntlist(mfp);
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 	(void) fclose(mfp);
78*7c478bd9Sstevel@tonic-gate 	return (mntl);
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate static struct extmnttab zmnttab = { 0 };
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate struct extmnttab *
85*7c478bd9Sstevel@tonic-gate fsdupmnttab(struct extmnttab *mnt)
86*7c478bd9Sstevel@tonic-gate {
87*7c478bd9Sstevel@tonic-gate 	struct extmnttab *new;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	new = (struct extmnttab *)malloc(sizeof (*new));
90*7c478bd9Sstevel@tonic-gate 	if (new == NULL)
91*7c478bd9Sstevel@tonic-gate 		goto alloc_failed;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	*new = zmnttab;
94*7c478bd9Sstevel@tonic-gate 	/*
95*7c478bd9Sstevel@tonic-gate 	 * Allocate an extra byte for the mountpoint
96*7c478bd9Sstevel@tonic-gate 	 * name in case a space needs to be added.
97*7c478bd9Sstevel@tonic-gate 	 */
98*7c478bd9Sstevel@tonic-gate 	new->mnt_mountp = (char *)malloc(strlen(mnt->mnt_mountp) + 2);
99*7c478bd9Sstevel@tonic-gate 	if (new->mnt_mountp == NULL)
100*7c478bd9Sstevel@tonic-gate 		goto alloc_failed;
101*7c478bd9Sstevel@tonic-gate 	(void) strcpy(new->mnt_mountp, mnt->mnt_mountp);
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	if ((new->mnt_special = strdup(mnt->mnt_special)) == NULL)
104*7c478bd9Sstevel@tonic-gate 		goto alloc_failed;
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	if ((new->mnt_fstype = strdup(mnt->mnt_fstype)) == NULL)
107*7c478bd9Sstevel@tonic-gate 		goto alloc_failed;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	if (mnt->mnt_mntopts != NULL)
110*7c478bd9Sstevel@tonic-gate 		if ((new->mnt_mntopts = strdup(mnt->mnt_mntopts)) == NULL)
111*7c478bd9Sstevel@tonic-gate 			goto alloc_failed;
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	if (mnt->mnt_time != NULL)
114*7c478bd9Sstevel@tonic-gate 		if ((new->mnt_time = strdup(mnt->mnt_time)) == NULL)
115*7c478bd9Sstevel@tonic-gate 			goto alloc_failed;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	new->mnt_major = mnt->mnt_major;
118*7c478bd9Sstevel@tonic-gate 	new->mnt_minor = mnt->mnt_minor;
119*7c478bd9Sstevel@tonic-gate 	return (new);
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate alloc_failed:
122*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("fsdupmnttab: Out of memory\n"));
123*7c478bd9Sstevel@tonic-gate 	fsfreemnttab(new);
124*7c478bd9Sstevel@tonic-gate 	return (NULL);
125*7c478bd9Sstevel@tonic-gate }
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /*
128*7c478bd9Sstevel@tonic-gate  * Free a single mnttab structure
129*7c478bd9Sstevel@tonic-gate  */
130*7c478bd9Sstevel@tonic-gate void
131*7c478bd9Sstevel@tonic-gate fsfreemnttab(struct extmnttab *mnt)
132*7c478bd9Sstevel@tonic-gate {
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	if (mnt) {
135*7c478bd9Sstevel@tonic-gate 		if (mnt->mnt_special)
136*7c478bd9Sstevel@tonic-gate 			free(mnt->mnt_special);
137*7c478bd9Sstevel@tonic-gate 		if (mnt->mnt_mountp)
138*7c478bd9Sstevel@tonic-gate 			free(mnt->mnt_mountp);
139*7c478bd9Sstevel@tonic-gate 		if (mnt->mnt_fstype)
140*7c478bd9Sstevel@tonic-gate 			free(mnt->mnt_fstype);
141*7c478bd9Sstevel@tonic-gate 		if (mnt->mnt_mntopts)
142*7c478bd9Sstevel@tonic-gate 			free(mnt->mnt_mntopts);
143*7c478bd9Sstevel@tonic-gate 		if (mnt->mnt_time)
144*7c478bd9Sstevel@tonic-gate 			free(mnt->mnt_time);
145*7c478bd9Sstevel@tonic-gate 		free(mnt);
146*7c478bd9Sstevel@tonic-gate 	}
147*7c478bd9Sstevel@tonic-gate }
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate void
150*7c478bd9Sstevel@tonic-gate fsfreemntlist(mntlist_t *mntl)
151*7c478bd9Sstevel@tonic-gate {
152*7c478bd9Sstevel@tonic-gate 	mntlist_t *mntl_tmp;
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	while (mntl) {
155*7c478bd9Sstevel@tonic-gate 		fsfreemnttab(mntl->mntl_mnt);
156*7c478bd9Sstevel@tonic-gate 		mntl_tmp = mntl;
157*7c478bd9Sstevel@tonic-gate 		mntl = mntl->mntl_next;
158*7c478bd9Sstevel@tonic-gate 		free(mntl_tmp);
159*7c478bd9Sstevel@tonic-gate 	}
160*7c478bd9Sstevel@tonic-gate }
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate /*
163*7c478bd9Sstevel@tonic-gate  * Read the mnttab file and return it as a list of mnttab structs.
164*7c478bd9Sstevel@tonic-gate  * Returns NULL if there was a memory failure.
165*7c478bd9Sstevel@tonic-gate  */
166*7c478bd9Sstevel@tonic-gate mntlist_t *
167*7c478bd9Sstevel@tonic-gate fsmkmntlist(FILE *mfp)
168*7c478bd9Sstevel@tonic-gate {
169*7c478bd9Sstevel@tonic-gate 	struct extmnttab 	mnt;
170*7c478bd9Sstevel@tonic-gate 	mntlist_t 	*mhead, *mtail;
171*7c478bd9Sstevel@tonic-gate 	int 		ret;
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 	mhead = mtail = NULL;
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	resetmnttab(mfp);
176*7c478bd9Sstevel@tonic-gate 	while ((ret = getextmntent(mfp, &mnt, sizeof (struct extmnttab)))
177*7c478bd9Sstevel@tonic-gate 		!= -1) {
178*7c478bd9Sstevel@tonic-gate 		mntlist_t	*mp;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 		if (ret != 0)		/* bad entry */
181*7c478bd9Sstevel@tonic-gate 			continue;
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 		mp = (mntlist_t *)malloc(sizeof (*mp));
184*7c478bd9Sstevel@tonic-gate 		if (mp == NULL)
185*7c478bd9Sstevel@tonic-gate 			goto alloc_failed;
186*7c478bd9Sstevel@tonic-gate 		if (mhead == NULL)
187*7c478bd9Sstevel@tonic-gate 			mhead = mp;
188*7c478bd9Sstevel@tonic-gate 		else
189*7c478bd9Sstevel@tonic-gate 			mtail->mntl_next = mp;
190*7c478bd9Sstevel@tonic-gate 		mtail = mp;
191*7c478bd9Sstevel@tonic-gate 		mp->mntl_next = NULL;
192*7c478bd9Sstevel@tonic-gate 		mp->mntl_flags = 0;
193*7c478bd9Sstevel@tonic-gate 		if ((mp->mntl_mnt = fsdupmnttab(&mnt)) == NULL)
194*7c478bd9Sstevel@tonic-gate 			goto alloc_failed;
195*7c478bd9Sstevel@tonic-gate 	}
196*7c478bd9Sstevel@tonic-gate 	return (mhead);
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate alloc_failed:
199*7c478bd9Sstevel@tonic-gate 	fsfreemntlist(mhead);
200*7c478bd9Sstevel@tonic-gate 	return (NULL);
201*7c478bd9Sstevel@tonic-gate }
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate /*
204*7c478bd9Sstevel@tonic-gate  * Return the last entry that matches mntin's special
205*7c478bd9Sstevel@tonic-gate  * device and/or mountpt.
206*7c478bd9Sstevel@tonic-gate  * Helps to be robust here, so we check for NULL pointers.
207*7c478bd9Sstevel@tonic-gate  */
208*7c478bd9Sstevel@tonic-gate mntlist_t *
209*7c478bd9Sstevel@tonic-gate fsgetmlast(mntlist_t *ml, struct mnttab *mntin)
210*7c478bd9Sstevel@tonic-gate {
211*7c478bd9Sstevel@tonic-gate 	mntlist_t 	*delete = NULL;
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	for (; ml; ml = ml->mntl_next) {
214*7c478bd9Sstevel@tonic-gate 		if (mntin->mnt_mountp && mntin->mnt_special) {
215*7c478bd9Sstevel@tonic-gate 			/*
216*7c478bd9Sstevel@tonic-gate 			 * match if and only if both are equal.
217*7c478bd9Sstevel@tonic-gate 			 */
218*7c478bd9Sstevel@tonic-gate 			if ((strcmp(ml->mntl_mnt->mnt_mountp,
219*7c478bd9Sstevel@tonic-gate 					mntin->mnt_mountp) == 0) &&
220*7c478bd9Sstevel@tonic-gate 			    (strcmp(ml->mntl_mnt->mnt_special,
221*7c478bd9Sstevel@tonic-gate 					mntin->mnt_special) == 0))
222*7c478bd9Sstevel@tonic-gate 				delete = ml;
223*7c478bd9Sstevel@tonic-gate 		} else if (mntin->mnt_mountp) {
224*7c478bd9Sstevel@tonic-gate 			if (strcmp(ml->mntl_mnt->mnt_mountp,
225*7c478bd9Sstevel@tonic-gate 					mntin->mnt_mountp) == 0)
226*7c478bd9Sstevel@tonic-gate 				delete = ml;
227*7c478bd9Sstevel@tonic-gate 		} else if (mntin->mnt_special) {
228*7c478bd9Sstevel@tonic-gate 			if (strcmp(ml->mntl_mnt->mnt_special,
229*7c478bd9Sstevel@tonic-gate 					mntin->mnt_special) == 0)
230*7c478bd9Sstevel@tonic-gate 				delete = ml;
231*7c478bd9Sstevel@tonic-gate 	    }
232*7c478bd9Sstevel@tonic-gate 	}
233*7c478bd9Sstevel@tonic-gate 	return (delete);
234*7c478bd9Sstevel@tonic-gate }
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate /*
238*7c478bd9Sstevel@tonic-gate  * Returns the mountlevel of the pathname in cp.  As examples,
239*7c478bd9Sstevel@tonic-gate  * / => 1, /bin => 2, /bin/ => 2, ////bin////ls => 3, sdf => 0, etc...
240*7c478bd9Sstevel@tonic-gate  */
241*7c478bd9Sstevel@tonic-gate int
242*7c478bd9Sstevel@tonic-gate fsgetmlevel(char *cp)
243*7c478bd9Sstevel@tonic-gate {
244*7c478bd9Sstevel@tonic-gate 	int	mlevel;
245*7c478bd9Sstevel@tonic-gate 	char	*cp1;
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	if (cp == NULL || *cp == NULL || *cp != '/')
248*7c478bd9Sstevel@tonic-gate 		return (0);	/* this should never happen */
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	mlevel = 1;			/* root (/) is the minimal case */
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	for (cp1 = cp + 1; *cp1; cp++, cp1++)
253*7c478bd9Sstevel@tonic-gate 		if (*cp == '/' && *cp1 != '/')	/* "///" counts as 1 */
254*7c478bd9Sstevel@tonic-gate 			mlevel++;
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	return (mlevel);
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate /*
260*7c478bd9Sstevel@tonic-gate  * Returns non-zero if string s is a member of the strings in ps.
261*7c478bd9Sstevel@tonic-gate  */
262*7c478bd9Sstevel@tonic-gate int
263*7c478bd9Sstevel@tonic-gate fsstrinlist(const char *s, const char **ps)
264*7c478bd9Sstevel@tonic-gate {
265*7c478bd9Sstevel@tonic-gate 	const char *cp;
266*7c478bd9Sstevel@tonic-gate 	cp = *ps;
267*7c478bd9Sstevel@tonic-gate 	while (cp) {
268*7c478bd9Sstevel@tonic-gate 		if (strcmp(s, cp) == 0)
269*7c478bd9Sstevel@tonic-gate 			return (1);
270*7c478bd9Sstevel@tonic-gate 		ps++;
271*7c478bd9Sstevel@tonic-gate 		cp = *ps;
272*7c478bd9Sstevel@tonic-gate 	}
273*7c478bd9Sstevel@tonic-gate 	return (0);
274*7c478bd9Sstevel@tonic-gate }
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate static char *empty_opt_vector[] = {
277*7c478bd9Sstevel@tonic-gate 	NULL
278*7c478bd9Sstevel@tonic-gate };
279*7c478bd9Sstevel@tonic-gate /*
280*7c478bd9Sstevel@tonic-gate  * Compare the mount options that were requested by the caller to
281*7c478bd9Sstevel@tonic-gate  * the options actually supported by the file system.  If any requested
282*7c478bd9Sstevel@tonic-gate  * options are not supported, print a warning message.
283*7c478bd9Sstevel@tonic-gate  *
284*7c478bd9Sstevel@tonic-gate  * WARNING: this function modifies the string pointed to by
285*7c478bd9Sstevel@tonic-gate  *	the requested_opts argument.
286*7c478bd9Sstevel@tonic-gate  *
287*7c478bd9Sstevel@tonic-gate  * Arguments:
288*7c478bd9Sstevel@tonic-gate  *	requested_opts - the string containing the requested options.
289*7c478bd9Sstevel@tonic-gate  *	actual_opts - the string returned by mount(2), which lists the
290*7c478bd9Sstevel@tonic-gate  *		options actually supported.  It is normal for this
291*7c478bd9Sstevel@tonic-gate  *		string to contain more options than the requested options.
292*7c478bd9Sstevel@tonic-gate  *		(The actual options may contain the default options, which
293*7c478bd9Sstevel@tonic-gate  *		may not have been included in the requested options.)
294*7c478bd9Sstevel@tonic-gate  *	special - device being mounted (only used in error messages).
295*7c478bd9Sstevel@tonic-gate  *	mountp - mount point (only used in error messages).
296*7c478bd9Sstevel@tonic-gate  */
297*7c478bd9Sstevel@tonic-gate void
298*7c478bd9Sstevel@tonic-gate cmp_requested_to_actual_options(char *requested_opts, char *actual_opts,
299*7c478bd9Sstevel@tonic-gate 	char *special, char *mountp)
300*7c478bd9Sstevel@tonic-gate {
301*7c478bd9Sstevel@tonic-gate 	char	*option_ptr, *actopt, *equalptr;
302*7c478bd9Sstevel@tonic-gate 	int	found;
303*7c478bd9Sstevel@tonic-gate 	char	*actual_opt_hold, *bufp;
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	if (requested_opts == NULL)
306*7c478bd9Sstevel@tonic-gate 		return;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	bufp = alloca(strlen(actual_opts) + 1);
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	while (*requested_opts != '\0') {
311*7c478bd9Sstevel@tonic-gate 		(void) getsubopt(&requested_opts, empty_opt_vector,
312*7c478bd9Sstevel@tonic-gate 			&option_ptr);
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 		/*
315*7c478bd9Sstevel@tonic-gate 		 * Truncate any "=<value>" string from the end of
316*7c478bd9Sstevel@tonic-gate 		 * the option.
317*7c478bd9Sstevel@tonic-gate 		 */
318*7c478bd9Sstevel@tonic-gate 		if ((equalptr = strchr(option_ptr, '=')) != NULL)
319*7c478bd9Sstevel@tonic-gate 			*equalptr = '\0';
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 		if (*option_ptr == '\0')
322*7c478bd9Sstevel@tonic-gate 			continue;
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 		/*
325*7c478bd9Sstevel@tonic-gate 		 * Search for the requested option in the list of options
326*7c478bd9Sstevel@tonic-gate 		 * actually supported.
327*7c478bd9Sstevel@tonic-gate 		 */
328*7c478bd9Sstevel@tonic-gate 		found = 0;
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 		/*
331*7c478bd9Sstevel@tonic-gate 		 * Need to use a copy of actual_opts because getsubopt
332*7c478bd9Sstevel@tonic-gate 		 * is destructive and we need to scan the actual_opts
333*7c478bd9Sstevel@tonic-gate 		 * string more than once.
334*7c478bd9Sstevel@tonic-gate 		 *
335*7c478bd9Sstevel@tonic-gate 		 * We also need to reset actual_opt_hold to the
336*7c478bd9Sstevel@tonic-gate 		 * beginning of the buffer because getsubopt changes
337*7c478bd9Sstevel@tonic-gate 		 * actual_opt_hold (the pointer).
338*7c478bd9Sstevel@tonic-gate 		 */
339*7c478bd9Sstevel@tonic-gate 		actual_opt_hold = bufp;
340*7c478bd9Sstevel@tonic-gate 		if (actual_opts != NULL)
341*7c478bd9Sstevel@tonic-gate 			(void) strcpy(actual_opt_hold, actual_opts);
342*7c478bd9Sstevel@tonic-gate 		else
343*7c478bd9Sstevel@tonic-gate 			*actual_opt_hold = '\0';
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 		while (*actual_opt_hold != '\0') {
346*7c478bd9Sstevel@tonic-gate 			(void) getsubopt(&actual_opt_hold, empty_opt_vector,
347*7c478bd9Sstevel@tonic-gate 				&actopt);
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 			/* Truncate the "=<value>", if any. */
350*7c478bd9Sstevel@tonic-gate 			if ((equalptr = strchr(actopt, '=')) != NULL)
351*7c478bd9Sstevel@tonic-gate 				*equalptr = '\0';
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 			if ((strcmp(option_ptr, actopt)) == 0) {
354*7c478bd9Sstevel@tonic-gate 				found = 1;
355*7c478bd9Sstevel@tonic-gate 				break;
356*7c478bd9Sstevel@tonic-gate 			}
357*7c478bd9Sstevel@tonic-gate 		}
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 		if (found == 0) {
360*7c478bd9Sstevel@tonic-gate 			/*
361*7c478bd9Sstevel@tonic-gate 			 * That we're ignoring the option is always
362*7c478bd9Sstevel@tonic-gate 			 * truthful; the old message that the option
363*7c478bd9Sstevel@tonic-gate 			 * was unknown is often not correct.
364*7c478bd9Sstevel@tonic-gate 			 */
365*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
366*7c478bd9Sstevel@tonic-gate 			    "mount: %s on %s - WARNING ignoring option "
367*7c478bd9Sstevel@tonic-gate 			    "\"%s\"\n"), special, mountp, option_ptr);
368*7c478bd9Sstevel@tonic-gate 		}
369*7c478bd9Sstevel@tonic-gate 	}
370*7c478bd9Sstevel@tonic-gate }
371*7c478bd9Sstevel@tonic-gate /*
372*7c478bd9Sstevel@tonic-gate  * FUNCTION:	fsgetmaxphys(int *, int *)
373*7c478bd9Sstevel@tonic-gate  *
374*7c478bd9Sstevel@tonic-gate  * INPUT:	int *maxphys - a pointer to an integer that will hold
375*7c478bd9Sstevel@tonic-gate  *			the value for the system maxphys value.
376*7c478bd9Sstevel@tonic-gate  *		int *error - 0 means completed successfully
377*7c478bd9Sstevel@tonic-gate  *			     otherwise this indicates the errno value.
378*7c478bd9Sstevel@tonic-gate  *
379*7c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 if maxphys not found
380*7c478bd9Sstevel@tonic-gate  *			- 1 if maxphys is found
381*7c478bd9Sstevel@tonic-gate  */
382*7c478bd9Sstevel@tonic-gate int
383*7c478bd9Sstevel@tonic-gate fsgetmaxphys(int *maxphys, int *error) {
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	int	gotit = 0;
386*7c478bd9Sstevel@tonic-gate 	int	fp = open("/", O_RDONLY);
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	*error = 0;
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	/*
391*7c478bd9Sstevel@tonic-gate 	 * For some reason cannot open root as read only. Need a valid file
392*7c478bd9Sstevel@tonic-gate 	 * descriptor to call the ufs private ioctl. If this open failes,
393*7c478bd9Sstevel@tonic-gate 	 * just assume we cannot get maxphys in this case.
394*7c478bd9Sstevel@tonic-gate 	 */
395*7c478bd9Sstevel@tonic-gate 	if (fp == -1) {
396*7c478bd9Sstevel@tonic-gate 		return (gotit);
397*7c478bd9Sstevel@tonic-gate 	}
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	if (ioctl(fp, _FIOGETMAXPHYS, maxphys) == -1) {
400*7c478bd9Sstevel@tonic-gate 		*error = errno;
401*7c478bd9Sstevel@tonic-gate 		(void) close(fp);
402*7c478bd9Sstevel@tonic-gate 		return (gotit);
403*7c478bd9Sstevel@tonic-gate 	}
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	(void) close(fp);
406*7c478bd9Sstevel@tonic-gate 	gotit = 1;
407*7c478bd9Sstevel@tonic-gate 	return (gotit);
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate }
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate /*
412*7c478bd9Sstevel@tonic-gate  * The below is limited support for zone-aware commands.
413*7c478bd9Sstevel@tonic-gate  */
414*7c478bd9Sstevel@tonic-gate struct zone_summary {
415*7c478bd9Sstevel@tonic-gate 	zoneid_t	zoneid;
416*7c478bd9Sstevel@tonic-gate 	char		rootpath[MAXPATHLEN];
417*7c478bd9Sstevel@tonic-gate 	size_t		rootpathlen;
418*7c478bd9Sstevel@tonic-gate };
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate struct zone_summary *
421*7c478bd9Sstevel@tonic-gate fs_get_zone_summaries(void)
422*7c478bd9Sstevel@tonic-gate {
423*7c478bd9Sstevel@tonic-gate 	uint_t numzones = 0, oldnumzones = 0;
424*7c478bd9Sstevel@tonic-gate 	uint_t i, j;
425*7c478bd9Sstevel@tonic-gate 	zoneid_t *ids = NULL;
426*7c478bd9Sstevel@tonic-gate 	struct zone_summary *summaries;
427*7c478bd9Sstevel@tonic-gate 	zoneid_t myzoneid = getzoneid();
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	for (;;) {
430*7c478bd9Sstevel@tonic-gate 		if (zone_list(ids, &numzones) < 0) {
431*7c478bd9Sstevel@tonic-gate 			    perror("unable to retrieve list of zones");
432*7c478bd9Sstevel@tonic-gate 			    if (ids != NULL)
433*7c478bd9Sstevel@tonic-gate 				    free(ids);
434*7c478bd9Sstevel@tonic-gate 			    return (NULL);
435*7c478bd9Sstevel@tonic-gate 		}
436*7c478bd9Sstevel@tonic-gate 		if (numzones <= oldnumzones)
437*7c478bd9Sstevel@tonic-gate 			break;
438*7c478bd9Sstevel@tonic-gate 		if (ids != NULL)
439*7c478bd9Sstevel@tonic-gate 			free(ids);
440*7c478bd9Sstevel@tonic-gate 		ids = malloc(numzones * sizeof (*ids));
441*7c478bd9Sstevel@tonic-gate 		if (ids == NULL) {
442*7c478bd9Sstevel@tonic-gate 			perror("malloc failed");
443*7c478bd9Sstevel@tonic-gate 			return (NULL);
444*7c478bd9Sstevel@tonic-gate 		}
445*7c478bd9Sstevel@tonic-gate 		oldnumzones = numzones;
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	summaries = malloc((numzones + 1) * sizeof (*summaries));
449*7c478bd9Sstevel@tonic-gate 	if (summaries == NULL) {
450*7c478bd9Sstevel@tonic-gate 		free(ids);
451*7c478bd9Sstevel@tonic-gate 		perror("malloc failed");
452*7c478bd9Sstevel@tonic-gate 		return (NULL);
453*7c478bd9Sstevel@tonic-gate 	}
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	for (i = 0, j = 0; i < numzones; i++) {
457*7c478bd9Sstevel@tonic-gate 		ssize_t len;
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 		if (ids[i] == myzoneid)
460*7c478bd9Sstevel@tonic-gate 			continue;
461*7c478bd9Sstevel@tonic-gate 		len = zone_getattr(ids[i], ZONE_ATTR_ROOT,
462*7c478bd9Sstevel@tonic-gate 		    summaries[j].rootpath, sizeof (summaries[j].rootpath));
463*7c478bd9Sstevel@tonic-gate 		if (len < 0) {
464*7c478bd9Sstevel@tonic-gate 			/*
465*7c478bd9Sstevel@tonic-gate 			 * Zone must have gone away. Skip.
466*7c478bd9Sstevel@tonic-gate 			 */
467*7c478bd9Sstevel@tonic-gate 			continue;
468*7c478bd9Sstevel@tonic-gate 		}
469*7c478bd9Sstevel@tonic-gate 		/*
470*7c478bd9Sstevel@tonic-gate 		 * Adding a trailing '/' to the zone's rootpath allows us to
471*7c478bd9Sstevel@tonic-gate 		 * use strncmp() to see if a given path resides within that
472*7c478bd9Sstevel@tonic-gate 		 * zone.
473*7c478bd9Sstevel@tonic-gate 		 *
474*7c478bd9Sstevel@tonic-gate 		 * As an example, if the zone's rootpath is "/foo/root",
475*7c478bd9Sstevel@tonic-gate 		 * "/foo/root/usr" resides within the zone, while
476*7c478bd9Sstevel@tonic-gate 		 * "/foo/rootpath" doesn't.
477*7c478bd9Sstevel@tonic-gate 		 */
478*7c478bd9Sstevel@tonic-gate 		(void) strlcat(summaries[j].rootpath, "/",
479*7c478bd9Sstevel@tonic-gate 		    sizeof (summaries[j].rootpath));
480*7c478bd9Sstevel@tonic-gate 		summaries[j].rootpathlen = len;
481*7c478bd9Sstevel@tonic-gate 		summaries[j].zoneid = ids[i];
482*7c478bd9Sstevel@tonic-gate 		j++;
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 	summaries[j].zoneid = -1;
485*7c478bd9Sstevel@tonic-gate 	free(ids);
486*7c478bd9Sstevel@tonic-gate 	return (summaries);
487*7c478bd9Sstevel@tonic-gate }
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate static zoneid_t
490*7c478bd9Sstevel@tonic-gate fs_find_zone(const struct zone_summary *summaries, const char *mntpt)
491*7c478bd9Sstevel@tonic-gate {
492*7c478bd9Sstevel@tonic-gate 	uint_t i;
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	for (i = 0; summaries[i].zoneid != -1; i++) {
495*7c478bd9Sstevel@tonic-gate 		if (strncmp(mntpt, summaries[i].rootpath,
496*7c478bd9Sstevel@tonic-gate 		    summaries[i].rootpathlen) == 0)
497*7c478bd9Sstevel@tonic-gate 			return (summaries[i].zoneid);
498*7c478bd9Sstevel@tonic-gate 	}
499*7c478bd9Sstevel@tonic-gate 	/*
500*7c478bd9Sstevel@tonic-gate 	 * (-1) is the special token we return to the caller if the mount
501*7c478bd9Sstevel@tonic-gate 	 * wasn't found in any other mounts on the system.  This means it's
502*7c478bd9Sstevel@tonic-gate 	 * only visible to our zone.
503*7c478bd9Sstevel@tonic-gate 	 *
504*7c478bd9Sstevel@tonic-gate 	 * Odd choice of constant, I know, but it beats calling getzoneid() a
505*7c478bd9Sstevel@tonic-gate 	 * million times.
506*7c478bd9Sstevel@tonic-gate 	 */
507*7c478bd9Sstevel@tonic-gate 	return (-1);
508*7c478bd9Sstevel@tonic-gate }
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate boolean_t
511*7c478bd9Sstevel@tonic-gate fs_mount_in_other_zone(const struct zone_summary *summaries, const char *mntpt)
512*7c478bd9Sstevel@tonic-gate {
513*7c478bd9Sstevel@tonic-gate 	return (fs_find_zone(summaries, mntpt) != -1);
514*7c478bd9Sstevel@tonic-gate }
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate /*
517*7c478bd9Sstevel@tonic-gate  * List of standard options.
518*7c478bd9Sstevel@tonic-gate  */
519*7c478bd9Sstevel@tonic-gate static const char *stdopts[] = {
520*7c478bd9Sstevel@tonic-gate 	MNTOPT_RO,			MNTOPT_RW,
521*7c478bd9Sstevel@tonic-gate 	MNTOPT_SUID,			MNTOPT_NOSUID,
522*7c478bd9Sstevel@tonic-gate 	MNTOPT_DEVICES,			MNTOPT_NODEVICES,
523*7c478bd9Sstevel@tonic-gate 	MNTOPT_SETUID,			MNTOPT_NOSETUID,
524*7c478bd9Sstevel@tonic-gate 	MNTOPT_NBMAND,			MNTOPT_NONBMAND,
525*7c478bd9Sstevel@tonic-gate 	MNTOPT_EXEC,			MNTOPT_NOEXEC,
526*7c478bd9Sstevel@tonic-gate };
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate #define	NSTDOPT		(sizeof (stdopts) / sizeof (stdopts[0]))
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate static int
531*7c478bd9Sstevel@tonic-gate optindx(const char *opt)
532*7c478bd9Sstevel@tonic-gate {
533*7c478bd9Sstevel@tonic-gate 	int i;
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NSTDOPT; i++) {
536*7c478bd9Sstevel@tonic-gate 		if (strcmp(opt, stdopts[i]) == 0)
537*7c478bd9Sstevel@tonic-gate 			return (i);
538*7c478bd9Sstevel@tonic-gate 	}
539*7c478bd9Sstevel@tonic-gate 	return (-1);
540*7c478bd9Sstevel@tonic-gate }
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate /*
543*7c478bd9Sstevel@tonic-gate  * INPUT:	filesystem option not recognized by the fs specific option
544*7c478bd9Sstevel@tonic-gate  *		parsing code.
545*7c478bd9Sstevel@tonic-gate  * OUTPUT:	True if and only if the option is one of the standard VFS
546*7c478bd9Sstevel@tonic-gate  *		layer options.
547*7c478bd9Sstevel@tonic-gate  */
548*7c478bd9Sstevel@tonic-gate boolean_t
549*7c478bd9Sstevel@tonic-gate fsisstdopt(const char *opt)
550*7c478bd9Sstevel@tonic-gate {
551*7c478bd9Sstevel@tonic-gate 	return (optindx(opt) != -1);
552*7c478bd9Sstevel@tonic-gate }
553