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