145916cd2Sjpk /*
245916cd2Sjpk  * CDDL HEADER START
345916cd2Sjpk  *
445916cd2Sjpk  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
745916cd2Sjpk  *
845916cd2Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
945916cd2Sjpk  * or http://www.opensolaris.org/os/licensing.
1045916cd2Sjpk  * See the License for the specific language governing permissions
1145916cd2Sjpk  * and limitations under the License.
1245916cd2Sjpk  *
1345916cd2Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
1445916cd2Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1545916cd2Sjpk  * If applicable, add the following below this CDDL HEADER, with the
1645916cd2Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
1745916cd2Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
1845916cd2Sjpk  *
1945916cd2Sjpk  * CDDL HEADER END
2045916cd2Sjpk  */
2145916cd2Sjpk /*
22e1dfad11Sjparcel  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2345916cd2Sjpk  * Use is subject to license terms.
2445916cd2Sjpk  */
2545916cd2Sjpk 
2645916cd2Sjpk /*
2745916cd2Sjpk  *	Name:		getpathbylabel.c
2845916cd2Sjpk  *
2945916cd2Sjpk  *	Description:	Returns the global zone pathname corresponding
3045916cd2Sjpk  *			to the specified label. The pathname does
3145916cd2Sjpk  *			not need to match an existing file system object.
3245916cd2Sjpk  *
3345916cd2Sjpk  */
3445916cd2Sjpk #include <stdio.h>
3545916cd2Sjpk #include <string.h>
3645916cd2Sjpk #include <unistd.h>
3745916cd2Sjpk #include <errno.h>
3845916cd2Sjpk #include <sys/types.h>
3945916cd2Sjpk #include <tsol/label.h>
4045916cd2Sjpk #include <stdlib.h>
4145916cd2Sjpk #include <zone.h>
4245916cd2Sjpk #include <sys/mntent.h>
4345916cd2Sjpk #include <sys/mnttab.h>
4445916cd2Sjpk #include <stdarg.h>
4545916cd2Sjpk 
4645916cd2Sjpk /*
4745916cd2Sjpk  * This structure is used to chain mntent structures into a list
4845916cd2Sjpk  * and to cache stat information for each member of the list.
4945916cd2Sjpk  */
5045916cd2Sjpk struct mntlist {
5145916cd2Sjpk 	struct mnttab	*mntl_mnt;
5245916cd2Sjpk 	struct mntlist	*mntl_next;
5345916cd2Sjpk };
5445916cd2Sjpk 
5545916cd2Sjpk 
5645916cd2Sjpk /*
5745916cd2Sjpk  * Return a pointer to the trailing suffix of full that follows the prefix
5845916cd2Sjpk  * given by pref.  If pref isn't a prefix of full, return NULL.  Apply
5945916cd2Sjpk  * pathname semantics to the prefix test, so that pref must match at a
6045916cd2Sjpk  * component boundary.
6145916cd2Sjpk  */
6245916cd2Sjpk static char *
pathsuffix(char * full,char * pref)6345916cd2Sjpk pathsuffix(char *full, char *pref)
6445916cd2Sjpk {
6545916cd2Sjpk 	int preflen;
6645916cd2Sjpk 
6745916cd2Sjpk 	if (full == NULL || pref == NULL)
6845916cd2Sjpk 		return (NULL);
6945916cd2Sjpk 
7045916cd2Sjpk 	preflen = strlen(pref);
7145916cd2Sjpk 	if (strncmp(pref, full, preflen) != 0)
7245916cd2Sjpk 		return (NULL);
7345916cd2Sjpk 
7445916cd2Sjpk 	/*
7545916cd2Sjpk 	 * pref is a substring of full.  To be a subpath, it cannot cover a
7645916cd2Sjpk 	 * partial component of full.  The last clause of the test handles the
7745916cd2Sjpk 	 * special case of the root.
7845916cd2Sjpk 	 */
7945916cd2Sjpk 	if (full[preflen] != '\0' && full[preflen] != '/' && preflen > 1)
8045916cd2Sjpk 		return (NULL);
8145916cd2Sjpk 
8245916cd2Sjpk 	if (preflen == 1 && full[0] == '/')
8345916cd2Sjpk 		return (full);
8445916cd2Sjpk 	else
8545916cd2Sjpk 		return (full + preflen);
8645916cd2Sjpk }
8745916cd2Sjpk 
8845916cd2Sjpk /*
8945916cd2Sjpk  * Return zero iff the path named by sub is a leading subpath
9045916cd2Sjpk  * of the path named by full.
9145916cd2Sjpk  *
9245916cd2Sjpk  * Treat null paths as matching nothing.
9345916cd2Sjpk  */
9445916cd2Sjpk static int
subpath(char * full,char * sub)9545916cd2Sjpk subpath(char *full, char *sub)
9645916cd2Sjpk {
9745916cd2Sjpk 	return (pathsuffix(full, sub) == NULL);
9845916cd2Sjpk }
9945916cd2Sjpk 
10045916cd2Sjpk static void
tsol_mnt_free(struct mnttab * mnt)10145916cd2Sjpk tsol_mnt_free(struct mnttab *mnt)
10245916cd2Sjpk {
10345916cd2Sjpk 	if (mnt->mnt_special)
10445916cd2Sjpk 		free(mnt->mnt_special);
10545916cd2Sjpk 	if (mnt->mnt_mountp)
10645916cd2Sjpk 		free(mnt->mnt_mountp);
10745916cd2Sjpk 	if (mnt->mnt_fstype)
10845916cd2Sjpk 		free(mnt->mnt_fstype);
10945916cd2Sjpk 	if (mnt->mnt_mntopts)
11045916cd2Sjpk 		free(mnt->mnt_mntopts);
11145916cd2Sjpk 	free(mnt);
11245916cd2Sjpk }
11345916cd2Sjpk 
11445916cd2Sjpk static void
tsol_mlist_free(struct mntlist * mlist)11545916cd2Sjpk tsol_mlist_free(struct mntlist *mlist)
11645916cd2Sjpk {
11745916cd2Sjpk 	struct mntlist *mlp;
118e1dfad11Sjparcel 	struct mntlist *oldmlp;
11945916cd2Sjpk 
120e1dfad11Sjparcel 	mlp = mlist;
121e1dfad11Sjparcel 	while (mlp) {
12245916cd2Sjpk 		struct mnttab *mnt = mlp->mntl_mnt;
12345916cd2Sjpk 
12445916cd2Sjpk 		if (mnt)
12545916cd2Sjpk 			tsol_mnt_free(mnt);
126e1dfad11Sjparcel 		oldmlp = mlp;
127e1dfad11Sjparcel 		mlp = mlp->mntl_next;
128e1dfad11Sjparcel 		free(oldmlp);
12945916cd2Sjpk 	}
13045916cd2Sjpk }
13145916cd2Sjpk 
13245916cd2Sjpk static struct mnttab *
mntdup(struct mnttab * mnt)13345916cd2Sjpk mntdup(struct mnttab *mnt)
13445916cd2Sjpk {
13545916cd2Sjpk 	struct mnttab *new;
13645916cd2Sjpk 
13745916cd2Sjpk 	new = (struct mnttab *)malloc(sizeof (*new));
13845916cd2Sjpk 	if (new == NULL)
13945916cd2Sjpk 		return (NULL);
14045916cd2Sjpk 
14145916cd2Sjpk 	new->mnt_special = NULL;
14245916cd2Sjpk 	new->mnt_mountp = NULL;
14345916cd2Sjpk 	new->mnt_fstype = NULL;
14445916cd2Sjpk 	new->mnt_mntopts = NULL;
14545916cd2Sjpk 
14645916cd2Sjpk 	new->mnt_special = strdup(mnt->mnt_special);
14745916cd2Sjpk 	if (new->mnt_special == NULL) {
14845916cd2Sjpk 		tsol_mnt_free(new);
14945916cd2Sjpk 		return (NULL);
15045916cd2Sjpk 	}
15145916cd2Sjpk 	new->mnt_mountp = strdup(mnt->mnt_mountp);
15245916cd2Sjpk 	if (new->mnt_mountp == NULL) {
15345916cd2Sjpk 		tsol_mnt_free(new);
15445916cd2Sjpk 		return (NULL);
15545916cd2Sjpk 	}
15645916cd2Sjpk 	new->mnt_fstype = strdup(mnt->mnt_fstype);
15745916cd2Sjpk 	if (new->mnt_fstype == NULL) {
15845916cd2Sjpk 		tsol_mnt_free(new);
15945916cd2Sjpk 		return (NULL);
16045916cd2Sjpk 	}
16145916cd2Sjpk 	new->mnt_mntopts = strdup(mnt->mnt_mntopts);
16245916cd2Sjpk 	if (new->mnt_mntopts == NULL) {
16345916cd2Sjpk 		tsol_mnt_free(new);
16445916cd2Sjpk 		return (NULL);
16545916cd2Sjpk 	}
16645916cd2Sjpk 	return (new);
16745916cd2Sjpk }
16845916cd2Sjpk 
16945916cd2Sjpk static struct mntlist *
tsol_mkmntlist(void)17045916cd2Sjpk tsol_mkmntlist(void)
17145916cd2Sjpk {
17245916cd2Sjpk 	FILE *mounted;
17345916cd2Sjpk 	struct mntlist *mntl;
17445916cd2Sjpk 	struct mntlist *mntst = NULL;
17545916cd2Sjpk 	struct mnttab mnt;
17645916cd2Sjpk 
177004388ebScasper 	if ((mounted = fopen(MNTTAB, "rF")) == NULL) {
17845916cd2Sjpk 		perror(MNTTAB);
17945916cd2Sjpk 		return (NULL);
18045916cd2Sjpk 	}
18145916cd2Sjpk 	resetmnttab(mounted);
182*ce67cb24SToomas Soome 	while (getmntent(mounted, &mnt) == 0) {
18345916cd2Sjpk 		mntl = (struct mntlist *)malloc(sizeof (*mntl));
18445916cd2Sjpk 		if (mntl == NULL) {
18545916cd2Sjpk 			tsol_mlist_free(mntst);
18645916cd2Sjpk 			mntst = NULL;
18745916cd2Sjpk 			break;
18845916cd2Sjpk 		}
18945916cd2Sjpk 		mntl->mntl_mnt = mntdup((struct mnttab *)(&mnt));
19045916cd2Sjpk 		if (mntl->mntl_mnt == NULL) {
19145916cd2Sjpk 			tsol_mlist_free(mntst);
19245916cd2Sjpk 			mntst = NULL;
19345916cd2Sjpk 			break;
19445916cd2Sjpk 		}
19545916cd2Sjpk 		mntl->mntl_next = mntst;
19645916cd2Sjpk 		mntst = mntl;
19745916cd2Sjpk 	}
19845916cd2Sjpk 	(void) fclose(mounted);
19945916cd2Sjpk 	return (mntst);
20045916cd2Sjpk }
20145916cd2Sjpk 
20245916cd2Sjpk /*
20345916cd2Sjpk  * This function attempts to convert local zone NFS mounted pathnames
20445916cd2Sjpk  * into equivalent global zone NFS mounted pathnames. At present
20545916cd2Sjpk  * it only works for automounted filesystems. It depends on the
20645916cd2Sjpk  * assumption that both the local and global zone automounters
20745916cd2Sjpk  * share the same nameservices. It also assumes that any automount
20845916cd2Sjpk  * map used by a local zone is available to the global zone automounter.
20945916cd2Sjpk  *
21045916cd2Sjpk  * The algorithm used consists of three phases.
21145916cd2Sjpk  *
21245916cd2Sjpk  * 1. The local zone's mnttab is searched to find the automount map
21345916cd2Sjpk  *    with the closest matching mountpath.
21445916cd2Sjpk  *
21545916cd2Sjpk  * 2. The matching autmount map name is looked up in the global zone's
21645916cd2Sjpk  *    mnttab to determine the path where it should be mounted in the
21745916cd2Sjpk  *    global zone.
21845916cd2Sjpk  *
21945916cd2Sjpk  * 3. A pathname covered by an appropiate autofs trigger mount in
22045916cd2Sjpk  *    the global zone is generated as the resolved pathname
22145916cd2Sjpk  *
22245916cd2Sjpk  * Among the things that can go wrong is that global zone doesn't have
22345916cd2Sjpk  * a matching automount map or the mount was not done via the automounter.
22445916cd2Sjpk  * Either of these cases return a NULL path.
22545916cd2Sjpk  */
22645916cd2Sjpk #define	ZONE_OPT "zone="
22745916cd2Sjpk static int
getnfspathbyautofs(struct mntlist * mlist,zoneid_t zoneid,struct mnttab * autofs_mnt,char * globalpath,char * zonepath,int global_len)22845916cd2Sjpk getnfspathbyautofs(struct mntlist *mlist, zoneid_t zoneid,
22945916cd2Sjpk     struct mnttab *autofs_mnt, char *globalpath, char *zonepath, int global_len)
23045916cd2Sjpk {
23145916cd2Sjpk 	struct mntlist *mlp;
23245916cd2Sjpk 	char zonematch[ZONENAME_MAX + 20];
23345916cd2Sjpk 	char zonename[ZONENAME_MAX];
23445916cd2Sjpk 	int  longestmatch;
23545916cd2Sjpk 	struct	mnttab	*mountmatch;
23645916cd2Sjpk 
23745916cd2Sjpk 	if (autofs_mnt) {
23845916cd2Sjpk 		mountmatch = autofs_mnt;
23945916cd2Sjpk 		longestmatch = strlen(mountmatch->mnt_mountp);
24045916cd2Sjpk 	} else {
24145916cd2Sjpk 		/*
24245916cd2Sjpk 		 * First we need to get the zonename to look for
24345916cd2Sjpk 		 */
24445916cd2Sjpk 		if (zone_getattr(zoneid, ZONE_ATTR_NAME, zonename,
24545916cd2Sjpk 		    ZONENAME_MAX) == -1) {
24645916cd2Sjpk 			return (0);
24745916cd2Sjpk 		}
24845916cd2Sjpk 
24945916cd2Sjpk 		(void) strncpy(zonematch, ZONE_OPT, sizeof (zonematch));
25045916cd2Sjpk 		(void) strlcat(zonematch, zonename, sizeof (zonematch));
25145916cd2Sjpk 
25245916cd2Sjpk 		/*
25345916cd2Sjpk 		 * Find the best match for an automount map that
25445916cd2Sjpk 		 * corresponds to the local zone's pathname
25545916cd2Sjpk 		 */
25645916cd2Sjpk 		longestmatch = 0;
25745916cd2Sjpk 		for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
25845916cd2Sjpk 			struct mnttab *mnt = mlp->mntl_mnt;
25945916cd2Sjpk 			int	len;
26045916cd2Sjpk 			int	matchfound;
26145916cd2Sjpk 			char	*token;
26245916cd2Sjpk 			char	*lasts;
26345916cd2Sjpk 			char	mntopts[MAXPATHLEN];
26445916cd2Sjpk 
26545916cd2Sjpk 			if (subpath(globalpath, mnt->mnt_mountp) != 0)
26645916cd2Sjpk 				continue;
26745916cd2Sjpk 			if (strcmp(mnt->mnt_fstype, MNTTYPE_AUTOFS))
26845916cd2Sjpk 				continue;
26945916cd2Sjpk 
27045916cd2Sjpk 			matchfound = 0;
27145916cd2Sjpk 			(void) strncpy(mntopts, mnt->mnt_mntopts, MAXPATHLEN);
27245916cd2Sjpk 			if ((token = strtok_r(mntopts, ",", &lasts)) != NULL) {
27345916cd2Sjpk 				if (strcmp(token, zonematch) == 0) {
27445916cd2Sjpk 					matchfound = 1;
27545916cd2Sjpk 				} else while ((token = strtok_r(NULL, ",",
27645916cd2Sjpk 				    &lasts)) != NULL) {
27745916cd2Sjpk 					if (strcmp(token, zonematch) == 0) {
27845916cd2Sjpk 						matchfound = 1;
27945916cd2Sjpk 						break;
28045916cd2Sjpk 					}
28145916cd2Sjpk 				}
28245916cd2Sjpk 			}
28345916cd2Sjpk 			if (matchfound) {
28445916cd2Sjpk 				len = strlen(mnt->mnt_mountp);
28545916cd2Sjpk 				if (len > longestmatch) {
28645916cd2Sjpk 					mountmatch = mnt;
28745916cd2Sjpk 					longestmatch = len;
28845916cd2Sjpk 				}
28945916cd2Sjpk 			}
29045916cd2Sjpk 		}
29145916cd2Sjpk 	}
29245916cd2Sjpk 	if (longestmatch == 0) {
29345916cd2Sjpk 		return (0);
29445916cd2Sjpk 	} else {
29545916cd2Sjpk 		/*
29645916cd2Sjpk 		 * Now we may have found the corresponding autofs mount
29745916cd2Sjpk 		 * Try to find the matching global zone autofs entry
29845916cd2Sjpk 		 */
29945916cd2Sjpk 
30045916cd2Sjpk 		for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
30145916cd2Sjpk 			char p[MAXPATHLEN];
30245916cd2Sjpk 			size_t zp_len;
30345916cd2Sjpk 			size_t mp_len;
30445916cd2Sjpk 
30545916cd2Sjpk 			struct mnttab *mnt = mlp->mntl_mnt;
30645916cd2Sjpk 
30745916cd2Sjpk 			if (strcmp(mountmatch->mnt_special,
30845916cd2Sjpk 			    mnt->mnt_special) != 0)
30945916cd2Sjpk 				continue;
31045916cd2Sjpk 			if (strcmp(mnt->mnt_fstype, MNTTYPE_AUTOFS))
31145916cd2Sjpk 				continue;
31245916cd2Sjpk 			if (strstr(mnt->mnt_mntopts, ZONE_OPT) != NULL)
31345916cd2Sjpk 				continue;
31445916cd2Sjpk 			/*
31545916cd2Sjpk 			 * OK, we have a matching global zone automap
31645916cd2Sjpk 			 * so adjust the path for the global zone.
31745916cd2Sjpk 			 */
31845916cd2Sjpk 			zp_len = strlen(zonepath);
31945916cd2Sjpk 			mp_len = strlen(mnt->mnt_mountp);
32045916cd2Sjpk 			(void) strncpy(p, globalpath + zp_len, MAXPATHLEN);
32145916cd2Sjpk 			/*
32245916cd2Sjpk 			 * If both global zone and zone-relative
32345916cd2Sjpk 			 * mountpoint match, just use the same pathname
32445916cd2Sjpk 			 */
32545916cd2Sjpk 			if (strncmp(mnt->mnt_mountp, p, mp_len) == 0) {
32645916cd2Sjpk 				(void) strncpy(globalpath, p, global_len);
32745916cd2Sjpk 				return (1);
32845916cd2Sjpk 			} else {
32945916cd2Sjpk 				(void) strncpy(p, globalpath, MAXPATHLEN);
33045916cd2Sjpk 				(void) strncpy(globalpath, mnt->mnt_mountp,
33145916cd2Sjpk 				    global_len);
33245916cd2Sjpk 				(void) strlcat(globalpath,
33345916cd2Sjpk 				    p + strlen(mountmatch->mnt_mountp),
33445916cd2Sjpk 				    global_len);
33545916cd2Sjpk 				return (1);
33645916cd2Sjpk 			}
33745916cd2Sjpk 		}
33845916cd2Sjpk 		return (0);
33945916cd2Sjpk 	}
34045916cd2Sjpk }
34145916cd2Sjpk 
342e1dfad11Sjparcel /*
343e1dfad11Sjparcel  * Find the pathname for the entry in mlist that corresponds to the
344e1dfad11Sjparcel  * file named by path (i.e., that names a mount table entry for the
345e1dfad11Sjparcel  * file system in which path lies).
346e1dfad11Sjparcel  *
347e1dfad11Sjparcel  * Return 0 is there an error.
348e1dfad11Sjparcel  */
349e1dfad11Sjparcel static int
getglobalpath(const char * path,zoneid_t zoneid,struct mntlist * mlist,char * globalpath)350e1dfad11Sjparcel getglobalpath(const char *path, zoneid_t zoneid, struct mntlist *mlist,
351e1dfad11Sjparcel     char *globalpath)
352e1dfad11Sjparcel {
353e1dfad11Sjparcel 	struct mntlist *mlp;
354e1dfad11Sjparcel 	char		lofspath[MAXPATHLEN];
355e1dfad11Sjparcel 	char		zonepath[MAXPATHLEN];
356e1dfad11Sjparcel 	int		longestmatch;
357e1dfad11Sjparcel 	struct	mnttab	*mountmatch;
358e1dfad11Sjparcel 
359e1dfad11Sjparcel 	if (zoneid != GLOBAL_ZONEID) {
360e1dfad11Sjparcel 		char	*prefix;
361e1dfad11Sjparcel 
362e1dfad11Sjparcel 		if ((prefix = getzonerootbyid(zoneid)) == NULL) {
363e1dfad11Sjparcel 			return (0);
36445916cd2Sjpk 		}
365e1dfad11Sjparcel 		(void) strncpy(zonepath, prefix, MAXPATHLEN);
366e1dfad11Sjparcel 		(void) strlcpy(globalpath, prefix, MAXPATHLEN);
367e1dfad11Sjparcel 		(void) strlcat(globalpath, path, MAXPATHLEN);
368e1dfad11Sjparcel 		free(prefix);
369e1dfad11Sjparcel 	} else {
370e1dfad11Sjparcel 		(void) strlcpy(globalpath, path, MAXPATHLEN);
371e1dfad11Sjparcel 	}
37245916cd2Sjpk 
373e1dfad11Sjparcel 	for (;;) {
374e1dfad11Sjparcel 		longestmatch = 0;
375e1dfad11Sjparcel 		for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
376e1dfad11Sjparcel 			struct mnttab *mnt = mlp->mntl_mnt;
377e1dfad11Sjparcel 			int	len;
37845916cd2Sjpk 
37945916cd2Sjpk 			if (subpath(globalpath, mnt->mnt_mountp) != 0)
38045916cd2Sjpk 				continue;
38145916cd2Sjpk 			len = strlen(mnt->mnt_mountp);
38245916cd2Sjpk 			if (len > longestmatch) {
38345916cd2Sjpk 				mountmatch = mnt;
38445916cd2Sjpk 				longestmatch = len;
38545916cd2Sjpk 			}
38645916cd2Sjpk 		}
38745916cd2Sjpk 		/*
38845916cd2Sjpk 		 * Handle interesting mounts.
38945916cd2Sjpk 		 */
39045916cd2Sjpk 		if ((strcmp(mountmatch->mnt_fstype, MNTTYPE_NFS) == 0) ||
39145916cd2Sjpk 		    (strcmp(mountmatch->mnt_fstype, MNTTYPE_AUTOFS) == 0)) {
39245916cd2Sjpk 			if (zoneid > GLOBAL_ZONEID) {
39345916cd2Sjpk 				struct mnttab *m = NULL;
39445916cd2Sjpk 
39545916cd2Sjpk 				if (strcmp(mountmatch->mnt_fstype,
39645916cd2Sjpk 				    MNTTYPE_AUTOFS) == 0)
39745916cd2Sjpk 					m = mountmatch;
39845916cd2Sjpk 				if (getnfspathbyautofs(mlist, zoneid, m,
39945916cd2Sjpk 				    globalpath, zonepath, MAXPATHLEN) == 0) {
40045916cd2Sjpk 					return (0);
40145916cd2Sjpk 				}
40245916cd2Sjpk 			}
40345916cd2Sjpk 			break;
40445916cd2Sjpk 		} else if (strcmp(mountmatch->mnt_fstype, MNTTYPE_LOFS) == 0) {
40545916cd2Sjpk 			/*
40645916cd2Sjpk 			 * count up what's left
40745916cd2Sjpk 			 */
40845916cd2Sjpk 			int	remainder;
40945916cd2Sjpk 
41045916cd2Sjpk 			remainder = strlen(globalpath) - longestmatch;
41145916cd2Sjpk 			if (remainder > 0) {
41245916cd2Sjpk 				path = pathsuffix(globalpath,
41345916cd2Sjpk 				    mountmatch->mnt_mountp);
41445916cd2Sjpk 				(void) strlcpy(lofspath, path, MAXPATHLEN);
41545916cd2Sjpk 			}
41645916cd2Sjpk 			(void) strlcpy(globalpath, mountmatch->mnt_special,
41745916cd2Sjpk 			    MAXPATHLEN);
41845916cd2Sjpk 			if (remainder > 0) {
41945916cd2Sjpk 				(void) strlcat(globalpath, lofspath,
42045916cd2Sjpk 				    MAXPATHLEN);
42145916cd2Sjpk 			}
42245916cd2Sjpk 		} else {
42345916cd2Sjpk 			if ((zoneid > GLOBAL_ZONEID) &&
42445916cd2Sjpk 			    (strncmp(path, "/home/", strlen("/home/")) == 0)) {
42545916cd2Sjpk 				char zonename[ZONENAME_MAX];
42645916cd2Sjpk 
42745916cd2Sjpk 				/*
42845916cd2Sjpk 				 * If this is a cross-zone reference to
42945916cd2Sjpk 				 * a home directory, it must be corrected.
43045916cd2Sjpk 				 * We should only get here if the zone's
43145916cd2Sjpk 				 * automounter hasn't yet mounted its
43245916cd2Sjpk 				 * autofs trigger on /home.
43345916cd2Sjpk 				 *
43445916cd2Sjpk 				 * Since it is likely to do so in the
43545916cd2Sjpk 				 * future, we will assume that the global
43645916cd2Sjpk 				 * zone already has an equivalent autofs
43745916cd2Sjpk 				 * mount established. By convention,
43845916cd2Sjpk 				 * this should be mounted at the
43945916cd2Sjpk 				 * /zone/<zonename>
44045916cd2Sjpk 				 */
44145916cd2Sjpk 
44245916cd2Sjpk 				if (zone_getattr(zoneid, ZONE_ATTR_NAME,
44345916cd2Sjpk 				    zonename, ZONENAME_MAX) == -1) {
44445916cd2Sjpk 					return (0);
44545916cd2Sjpk 				} else {
44645916cd2Sjpk 					(void) snprintf(globalpath, MAXPATHLEN,
44745916cd2Sjpk 					    "/zone/%s%s", zonename, path);
44845916cd2Sjpk 				}
44945916cd2Sjpk 			}
45045916cd2Sjpk 			break;
45145916cd2Sjpk 		}
45245916cd2Sjpk 	}
45345916cd2Sjpk 	return (1);
45445916cd2Sjpk }
45545916cd2Sjpk 
45645916cd2Sjpk 
45745916cd2Sjpk /*
45845916cd2Sjpk  * This function is only useful for global zone callers
45945916cd2Sjpk  * It uses the global zone mnttab to translate local zone pathnames
46045916cd2Sjpk  * into global zone pathnames.
46145916cd2Sjpk  */
46245916cd2Sjpk char *
getpathbylabel(const char * path_name,char * resolved_path,size_t bufsize,const bslabel_t * sl)46345916cd2Sjpk getpathbylabel(const char *path_name, char *resolved_path, size_t bufsize,
464e1dfad11Sjparcel     const bslabel_t *sl)
465e1dfad11Sjparcel {
46645916cd2Sjpk 	char		ret_path[MAXPATHLEN];	/* pathname to return */
46745916cd2Sjpk 	zoneid_t	zoneid;
46845916cd2Sjpk 	struct mntlist *mlist;
46945916cd2Sjpk 
47045916cd2Sjpk 	if (getzoneid() != GLOBAL_ZONEID) {
47145916cd2Sjpk 		errno = EINVAL;
47245916cd2Sjpk 		return (NULL);
47345916cd2Sjpk 	}
47445916cd2Sjpk 
47545916cd2Sjpk 	if (path_name[0] != '/') {		/* need absolute pathname */
47645916cd2Sjpk 		errno = EINVAL;
47745916cd2Sjpk 		return (NULL);
47845916cd2Sjpk 	}
47945916cd2Sjpk 
48045916cd2Sjpk 	if (resolved_path == NULL) {
48145916cd2Sjpk 		errno = EINVAL;
48245916cd2Sjpk 		return (NULL);
483