xref: /onnv-gate/usr/src/lib/libtsol/common/getpathbylabel.c (revision 4541:62ca1e3cb5d3)
11676Sjpk /*
21676Sjpk  * CDDL HEADER START
31676Sjpk  *
41676Sjpk  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
71676Sjpk  *
81676Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91676Sjpk  * or http://www.opensolaris.org/os/licensing.
101676Sjpk  * See the License for the specific language governing permissions
111676Sjpk  * and limitations under the License.
121676Sjpk  *
131676Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
141676Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151676Sjpk  * If applicable, add the following below this CDDL HEADER, with the
161676Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
171676Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
181676Sjpk  *
191676Sjpk  * CDDL HEADER END
201676Sjpk  */
211676Sjpk /*
22*4541Sjparcel  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
231676Sjpk  * Use is subject to license terms.
241676Sjpk  */
251676Sjpk 
261676Sjpk #pragma ident	"%Z%%M%	%I%	%E% SMI"
271676Sjpk 
281676Sjpk 
291676Sjpk /*
301676Sjpk  *	Name:		getpathbylabel.c
311676Sjpk  *
321676Sjpk  *	Description:	Returns the global zone pathname corresponding
331676Sjpk  *			to the specified label. The pathname does
341676Sjpk  *			not need to match an existing file system object.
351676Sjpk  *
361676Sjpk  */
371676Sjpk #include <stdio.h>
381676Sjpk #include <string.h>
391676Sjpk #include <unistd.h>
401676Sjpk #include <errno.h>
411676Sjpk #include <sys/types.h>
421676Sjpk #include <tsol/label.h>
431676Sjpk #include <stdlib.h>
441676Sjpk #include <zone.h>
451676Sjpk #include <sys/mntent.h>
461676Sjpk #include <sys/mnttab.h>
471676Sjpk #include <stdarg.h>
481676Sjpk 
491676Sjpk /*
501676Sjpk  * This structure is used to chain mntent structures into a list
511676Sjpk  * and to cache stat information for each member of the list.
521676Sjpk  */
531676Sjpk struct mntlist {
541676Sjpk 	struct mnttab	*mntl_mnt;
551676Sjpk 	struct mntlist	*mntl_next;
561676Sjpk };
571676Sjpk 
581676Sjpk 
591676Sjpk /*
601676Sjpk  * Return a pointer to the trailing suffix of full that follows the prefix
611676Sjpk  * given by pref.  If pref isn't a prefix of full, return NULL.  Apply
621676Sjpk  * pathname semantics to the prefix test, so that pref must match at a
631676Sjpk  * component boundary.
641676Sjpk  */
651676Sjpk static char *
pathsuffix(char * full,char * pref)661676Sjpk pathsuffix(char *full, char *pref)
671676Sjpk {
681676Sjpk 	int preflen;
691676Sjpk 
701676Sjpk 	if (full == NULL || pref == NULL)
711676Sjpk 		return (NULL);
721676Sjpk 
731676Sjpk 	preflen = strlen(pref);
741676Sjpk 	if (strncmp(pref, full, preflen) != 0)
751676Sjpk 		return (NULL);
761676Sjpk 
771676Sjpk 	/*
781676Sjpk 	 * pref is a substring of full.  To be a subpath, it cannot cover a
791676Sjpk 	 * partial component of full.  The last clause of the test handles the
801676Sjpk 	 * special case of the root.
811676Sjpk 	 */
821676Sjpk 	if (full[preflen] != '\0' && full[preflen] != '/' && preflen > 1)
831676Sjpk 		return (NULL);
841676Sjpk 
851676Sjpk 	if (preflen == 1 && full[0] == '/')
861676Sjpk 		return (full);
871676Sjpk 	else
881676Sjpk 		return (full + preflen);
891676Sjpk }
901676Sjpk 
911676Sjpk /*
921676Sjpk  * Return zero iff the path named by sub is a leading subpath
931676Sjpk  * of the path named by full.
941676Sjpk  *
951676Sjpk  * Treat null paths as matching nothing.
961676Sjpk  */
971676Sjpk static int
subpath(char * full,char * sub)981676Sjpk subpath(char *full, char *sub)
991676Sjpk {
1001676Sjpk 	return (pathsuffix(full, sub) == NULL);
1011676Sjpk }
1021676Sjpk 
1031676Sjpk static void
tsol_mnt_free(struct mnttab * mnt)1041676Sjpk tsol_mnt_free(struct mnttab *mnt)
1051676Sjpk {
1061676Sjpk 	if (mnt->mnt_special)
1071676Sjpk 		free(mnt->mnt_special);
1081676Sjpk 	if (mnt->mnt_mountp)
1091676Sjpk 		free(mnt->mnt_mountp);
1101676Sjpk 	if (mnt->mnt_fstype)
1111676Sjpk 		free(mnt->mnt_fstype);
1121676Sjpk 	if (mnt->mnt_mntopts)
1131676Sjpk 		free(mnt->mnt_mntopts);
1141676Sjpk 	free(mnt);
1151676Sjpk }
1161676Sjpk 
1171676Sjpk static void
tsol_mlist_free(struct mntlist * mlist)1181676Sjpk tsol_mlist_free(struct mntlist *mlist)
1191676Sjpk {
1201676Sjpk 	struct mntlist *mlp;
121*4541Sjparcel 	struct mntlist *oldmlp;
1221676Sjpk 
123*4541Sjparcel 	mlp = mlist;
124*4541Sjparcel 	while (mlp) {
1251676Sjpk 		struct mnttab *mnt = mlp->mntl_mnt;
1261676Sjpk 
1271676Sjpk 		if (mnt)
1281676Sjpk 			tsol_mnt_free(mnt);
129*4541Sjparcel 		oldmlp = mlp;
130*4541Sjparcel 		mlp = mlp->mntl_next;
131*4541Sjparcel 		free(oldmlp);
1321676Sjpk 	}
1331676Sjpk }
1341676Sjpk 
1351676Sjpk static struct mnttab *
mntdup(struct mnttab * mnt)1361676Sjpk mntdup(struct mnttab *mnt)
1371676Sjpk {
1381676Sjpk 	struct mnttab *new;
1391676Sjpk 
1401676Sjpk 	new = (struct mnttab *)malloc(sizeof (*new));
1411676Sjpk 	if (new == NULL)
1421676Sjpk 		return (NULL);
1431676Sjpk 
1441676Sjpk 	new->mnt_special = NULL;
1451676Sjpk 	new->mnt_mountp = NULL;
1461676Sjpk 	new->mnt_fstype = NULL;
1471676Sjpk 	new->mnt_mntopts = NULL;
1481676Sjpk 
1491676Sjpk 	new->mnt_special = strdup(mnt->mnt_special);
1501676Sjpk 	if (new->mnt_special == NULL) {
1511676Sjpk 		tsol_mnt_free(new);
1521676Sjpk 		return (NULL);
1531676Sjpk 	}
1541676Sjpk 	new->mnt_mountp = strdup(mnt->mnt_mountp);
1551676Sjpk 	if (new->mnt_mountp == NULL) {
1561676Sjpk 		tsol_mnt_free(new);
1571676Sjpk 		return (NULL);
1581676Sjpk 	}
1591676Sjpk 	new->mnt_fstype = strdup(mnt->mnt_fstype);
1601676Sjpk 	if (new->mnt_fstype == NULL) {
1611676Sjpk 		tsol_mnt_free(new);
1621676Sjpk 		return (NULL);
1631676Sjpk 	}
1641676Sjpk 	new->mnt_mntopts = strdup(mnt->mnt_mntopts);
1651676Sjpk 	if (new->mnt_mntopts == NULL) {
1661676Sjpk 		tsol_mnt_free(new);
1671676Sjpk 		return (NULL);
1681676Sjpk 	}
1691676Sjpk 	return (new);
1701676Sjpk }
1711676Sjpk 
1721676Sjpk static struct mntlist *
tsol_mkmntlist(void)1731676Sjpk tsol_mkmntlist(void)
1741676Sjpk {
1751676Sjpk 	FILE *mounted;
1761676Sjpk 	struct mntlist *mntl;
1771676Sjpk 	struct mntlist *mntst = NULL;
1781676Sjpk 	struct mnttab mnt;
1791676Sjpk 
1801914Scasper 	if ((mounted = fopen(MNTTAB, "rF")) == NULL) {
1811676Sjpk 		perror(MNTTAB);
1821676Sjpk 		return (NULL);
1831676Sjpk 	}
1841676Sjpk 	resetmnttab(mounted);
1851676Sjpk 	while (getmntent(mounted, &mnt) == NULL) {
1861676Sjpk 		mntl = (struct mntlist *)malloc(sizeof (*mntl));
1871676Sjpk 		if (mntl == NULL) {
1881676Sjpk 			tsol_mlist_free(mntst);
1891676Sjpk 			mntst = NULL;
1901676Sjpk 			break;
1911676Sjpk 		}
1921676Sjpk 		mntl->mntl_mnt = mntdup((struct mnttab *)(&mnt));
1931676Sjpk 		if (mntl->mntl_mnt == NULL) {
1941676Sjpk 			tsol_mlist_free(mntst);
1951676Sjpk 			mntst = NULL;
1961676Sjpk 			break;
1971676Sjpk 		}
1981676Sjpk 		mntl->mntl_next = mntst;
1991676Sjpk 		mntst = mntl;
2001676Sjpk 	}
2011676Sjpk 	(void) fclose(mounted);
2021676Sjpk 	return (mntst);
2031676Sjpk }
2041676Sjpk 
2051676Sjpk /*
2061676Sjpk  * This function attempts to convert local zone NFS mounted pathnames
2071676Sjpk  * into equivalent global zone NFS mounted pathnames. At present
2081676Sjpk  * it only works for automounted filesystems. It depends on the
2091676Sjpk  * assumption that both the local and global zone automounters
2101676Sjpk  * share the same nameservices. It also assumes that any automount
2111676Sjpk  * map used by a local zone is available to the global zone automounter.
2121676Sjpk  *
2131676Sjpk  * The algorithm used consists of three phases.
2141676Sjpk  *
2151676Sjpk  * 1. The local zone's mnttab is searched to find the automount map
2161676Sjpk  *    with the closest matching mountpath.
2171676Sjpk  *
2181676Sjpk  * 2. The matching autmount map name is looked up in the global zone's
2191676Sjpk  *    mnttab to determine the path where it should be mounted in the
2201676Sjpk  *    global zone.
2211676Sjpk  *
2221676Sjpk  * 3. A pathname covered by an appropiate autofs trigger mount in
2231676Sjpk  *    the global zone is generated as the resolved pathname
2241676Sjpk  *
2251676Sjpk  * Among the things that can go wrong is that global zone doesn't have
2261676Sjpk  * a matching automount map or the mount was not done via the automounter.
2271676Sjpk  * Either of these cases return a NULL path.
2281676Sjpk  */
2291676Sjpk #define	ZONE_OPT "zone="
2301676Sjpk static int
getnfspathbyautofs(struct mntlist * mlist,zoneid_t zoneid,struct mnttab * autofs_mnt,char * globalpath,char * zonepath,int global_len)2311676Sjpk getnfspathbyautofs(struct mntlist *mlist, zoneid_t zoneid,
2321676Sjpk     struct mnttab *autofs_mnt, char *globalpath, char *zonepath, int global_len)
2331676Sjpk {
2341676Sjpk 	struct mntlist *mlp;
2351676Sjpk 	char zonematch[ZONENAME_MAX + 20];
2361676Sjpk 	char zonename[ZONENAME_MAX];
2371676Sjpk 	int  longestmatch;
2381676Sjpk 	struct	mnttab	*mountmatch;
2391676Sjpk 
2401676Sjpk 	if (autofs_mnt) {
2411676Sjpk 		mountmatch = autofs_mnt;
2421676Sjpk 		longestmatch = strlen(mountmatch->mnt_mountp);
2431676Sjpk 	} else {
2441676Sjpk 		/*
2451676Sjpk 		 * First we need to get the zonename to look for
2461676Sjpk 		 */
2471676Sjpk 		if (zone_getattr(zoneid, ZONE_ATTR_NAME, zonename,
2481676Sjpk 		    ZONENAME_MAX) == -1) {
2491676Sjpk 			return (0);
2501676Sjpk 		}
2511676Sjpk 
2521676Sjpk 		(void) strncpy(zonematch, ZONE_OPT, sizeof (zonematch));
2531676Sjpk 		(void) strlcat(zonematch, zonename, sizeof (zonematch));
2541676Sjpk 
2551676Sjpk 		/*
2561676Sjpk 		 * Find the best match for an automount map that
2571676Sjpk 		 * corresponds to the local zone's pathname
2581676Sjpk 		 */
2591676Sjpk 		longestmatch = 0;
2601676Sjpk 		for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
2611676Sjpk 			struct mnttab *mnt = mlp->mntl_mnt;
2621676Sjpk 			int	len;
2631676Sjpk 			int	matchfound;
2641676Sjpk 			char	*token;
2651676Sjpk 			char	*lasts;
2661676Sjpk 			char	mntopts[MAXPATHLEN];
2671676Sjpk 
2681676Sjpk 			if (subpath(globalpath, mnt->mnt_mountp) != 0)
2691676Sjpk 				continue;
2701676Sjpk 			if (strcmp(mnt->mnt_fstype, MNTTYPE_AUTOFS))
2711676Sjpk 				continue;
2721676Sjpk 
2731676Sjpk 			matchfound = 0;
2741676Sjpk 			(void) strncpy(mntopts, mnt->mnt_mntopts, MAXPATHLEN);
2751676Sjpk 			if ((token = strtok_r(mntopts, ",", &lasts)) != NULL) {
2761676Sjpk 				if (strcmp(token, zonematch) == 0) {
2771676Sjpk 					matchfound = 1;
2781676Sjpk 				} else while ((token = strtok_r(NULL, ",",
2791676Sjpk 				    &lasts)) != NULL) {
2801676Sjpk 					if (strcmp(token, zonematch) == 0) {
2811676Sjpk 						matchfound = 1;
2821676Sjpk 						break;
2831676Sjpk 					}
2841676Sjpk 				}
2851676Sjpk 			}
2861676Sjpk 			if (matchfound) {
2871676Sjpk 				len = strlen(mnt->mnt_mountp);
2881676Sjpk 				if (len > longestmatch) {
2891676Sjpk 					mountmatch = mnt;
2901676Sjpk 					longestmatch = len;
2911676Sjpk 				}
2921676Sjpk 			}
2931676Sjpk 		}
2941676Sjpk 	}
2951676Sjpk 	if (longestmatch == 0) {
2961676Sjpk 		return (0);
2971676Sjpk 	} else {
2981676Sjpk 		/*
2991676Sjpk 		 * Now we may have found the corresponding autofs mount
3001676Sjpk 		 * Try to find the matching global zone autofs entry
3011676Sjpk 		 */
3021676Sjpk 
3031676Sjpk 		for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
3041676Sjpk 			char p[MAXPATHLEN];
3051676Sjpk 			size_t zp_len;
3061676Sjpk 			size_t mp_len;
3071676Sjpk 
3081676Sjpk 			struct mnttab *mnt = mlp->mntl_mnt;
3091676Sjpk 
3101676Sjpk 			if (strcmp(mountmatch->mnt_special,
3111676Sjpk 			    mnt->mnt_special) != 0)
3121676Sjpk 				continue;
3131676Sjpk 			if (strcmp(mnt->mnt_fstype, MNTTYPE_AUTOFS))
3141676Sjpk 				continue;
3151676Sjpk 			if (strstr(mnt->mnt_mntopts, ZONE_OPT) != NULL)
3161676Sjpk 				continue;
3171676Sjpk 			/*
3181676Sjpk 			 * OK, we have a matching global zone automap
3191676Sjpk 			 * so adjust the path for the global zone.
3201676Sjpk 			 */
3211676Sjpk 			zp_len = strlen(zonepath);
3221676Sjpk 			mp_len = strlen(mnt->mnt_mountp);
3231676Sjpk 			(void) strncpy(p, globalpath + zp_len, MAXPATHLEN);
3241676Sjpk 			/*
3251676Sjpk 			 * If both global zone and zone-relative
3261676Sjpk 			 * mountpoint match, just use the same pathname
3271676Sjpk 			 */
3281676Sjpk 			if (strncmp(mnt->mnt_mountp, p, mp_len) == 0) {
3291676Sjpk 				(void) strncpy(globalpath, p, global_len);
3301676Sjpk 				return (1);
3311676Sjpk 			} else {
3321676Sjpk 				(void) strncpy(p, globalpath, MAXPATHLEN);
3331676Sjpk 				(void) strncpy(globalpath, mnt->mnt_mountp,
3341676Sjpk 				    global_len);
3351676Sjpk 				(void) strlcat(globalpath,
3361676Sjpk 				    p + strlen(mountmatch->mnt_mountp),
3371676Sjpk 				    global_len);
3381676Sjpk 				return (1);
3391676Sjpk 			}
3401676Sjpk 		}
3411676Sjpk 		return (0);
3421676Sjpk 	}
3431676Sjpk }
3441676Sjpk 
345*4541Sjparcel /*
346*4541Sjparcel  * Find the pathname for the entry in mlist that corresponds to the
347*4541Sjparcel  * file named by path (i.e., that names a mount table entry for the
348*4541Sjparcel  * file system in which path lies).
349*4541Sjparcel  *
350*4541Sjparcel  * Return 0 is there an error.
351*4541Sjparcel  */
352*4541Sjparcel static int
getglobalpath(const char * path,zoneid_t zoneid,struct mntlist * mlist,char * globalpath)353*4541Sjparcel getglobalpath(const char *path, zoneid_t zoneid, struct mntlist *mlist,
354*4541Sjparcel     char *globalpath)
355*4541Sjparcel {
356*4541Sjparcel 	struct mntlist *mlp;
357*4541Sjparcel 	char		lofspath[MAXPATHLEN];
358*4541Sjparcel 	char		zonepath[MAXPATHLEN];
359*4541Sjparcel 	int		longestmatch;
360*4541Sjparcel 	struct	mnttab	*mountmatch;
3611676Sjpk 
362*4541Sjparcel 	if (zoneid != GLOBAL_ZONEID) {
363*4541Sjparcel 		char	*prefix;
3641676Sjpk 
365*4541Sjparcel 		if ((prefix = getzonerootbyid(zoneid)) == NULL) {
366*4541Sjparcel 			return (0);
3671676Sjpk 		}
368*4541Sjparcel 		(void) strncpy(zonepath, prefix, MAXPATHLEN);
369*4541Sjparcel 		(void) strlcpy(globalpath, prefix, MAXPATHLEN);
370*4541Sjparcel 		(void) strlcat(globalpath, path, MAXPATHLEN);
371*4541Sjparcel 		free(prefix);
372*4541Sjparcel 	} else {
373*4541Sjparcel 		(void) strlcpy(globalpath, path, MAXPATHLEN);
374*4541Sjparcel 	}
3751676Sjpk 
376*4541Sjparcel 	for (;;) {
377*4541Sjparcel 		longestmatch = 0;
378*4541Sjparcel 		for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
379*4541Sjparcel 			struct mnttab *mnt = mlp->mntl_mnt;
380*4541Sjparcel 			int	len;
3811676Sjpk 
3821676Sjpk 			if (subpath(globalpath, mnt->mnt_mountp) != 0)
3831676Sjpk 				continue;
3841676Sjpk 			len = strlen(mnt->mnt_mountp);
3851676Sjpk 			if (len > longestmatch) {
3861676Sjpk 				mountmatch = mnt;
3871676Sjpk 				longestmatch = len;
3881676Sjpk 			}
3891676Sjpk 		}
3901676Sjpk 		/*
3911676Sjpk 		 * Handle interesting mounts.
3921676Sjpk 		 */
3931676Sjpk 		if ((strcmp(mountmatch->mnt_fstype, MNTTYPE_NFS) == 0) ||
3941676Sjpk 		    (strcmp(mountmatch->mnt_fstype, MNTTYPE_AUTOFS) == 0)) {
3951676Sjpk 			if (zoneid > GLOBAL_ZONEID) {
3961676Sjpk 				struct mnttab *m = NULL;
3971676Sjpk 
3981676Sjpk 				if (strcmp(mountmatch->mnt_fstype,
3991676Sjpk 				    MNTTYPE_AUTOFS) == 0)
4001676Sjpk 					m = mountmatch;
4011676Sjpk 				if (getnfspathbyautofs(mlist, zoneid, m,
4021676Sjpk 				    globalpath, zonepath, MAXPATHLEN) == 0) {
4031676Sjpk 					return (0);
4041676Sjpk 				}
4051676Sjpk 			}
4061676Sjpk 			break;
4071676Sjpk 		} else if (strcmp(mountmatch->mnt_fstype, MNTTYPE_LOFS) == 0) {
4081676Sjpk 			/*
4091676Sjpk 			 * count up what's left
4101676Sjpk 			 */
4111676Sjpk 			int	remainder;
4121676Sjpk 
4131676Sjpk 			remainder = strlen(globalpath) - longestmatch;
4141676Sjpk 			if (remainder > 0) {
4151676Sjpk 				path = pathsuffix(globalpath,
4161676Sjpk 				    mountmatch->mnt_mountp);
4171676Sjpk 				(void) strlcpy(lofspath, path, MAXPATHLEN);
4181676Sjpk 			}
4191676Sjpk 			(void) strlcpy(globalpath, mountmatch->mnt_special,
4201676Sjpk 			    MAXPATHLEN);
4211676Sjpk 			if (remainder > 0) {
4221676Sjpk 				(void) strlcat(globalpath, lofspath,
4231676Sjpk 				    MAXPATHLEN);
4241676Sjpk 			}
4251676Sjpk 		} else {
4261676Sjpk 			if ((zoneid > GLOBAL_ZONEID) &&
4271676Sjpk 			    (strncmp(path, "/home/", strlen("/home/")) == 0)) {
4281676Sjpk 				char zonename[ZONENAME_MAX];
4291676Sjpk 
4301676Sjpk 				/*
4311676Sjpk 				 * If this is a cross-zone reference to
4321676Sjpk 				 * a home directory, it must be corrected.
4331676Sjpk 				 * We should only get here if the zone's
4341676Sjpk 				 * automounter hasn't yet mounted its
4351676Sjpk 				 * autofs trigger on /home.
4361676Sjpk 				 *
4371676Sjpk 				 * Since it is likely to do so in the
4381676Sjpk 				 * future, we will assume that the global
4391676Sjpk 				 * zone already has an equivalent autofs
4401676Sjpk 				 * mount established. By convention,
4411676Sjpk 				 * this should be mounted at the
4421676Sjpk 				 * /zone/<zonename>
4431676Sjpk 				 */
4441676Sjpk 
4451676Sjpk 				if (zone_getattr(zoneid, ZONE_ATTR_NAME,
4461676Sjpk 				    zonename, ZONENAME_MAX) == -1) {
4471676Sjpk 					return (0);
4481676Sjpk 				} else {
4491676Sjpk 					(void) snprintf(globalpath, MAXPATHLEN,
4501676Sjpk 					    "/zone/%s%s", zonename, path);
4511676Sjpk 				}
4521676Sjpk 			}
4531676Sjpk 			break;
4541676Sjpk 		}
4551676Sjpk 	}
4561676Sjpk 	return (1);
4571676Sjpk }
4581676Sjpk 
4591676Sjpk 
4601676Sjpk /*
4611676Sjpk  * This function is only useful for global zone callers
4621676Sjpk  * It uses the global zone mnttab to translate local zone pathnames
4631676Sjpk  * into global zone pathnames.
4641676Sjpk  */
4651676Sjpk char *
getpathbylabel(const char * path_name,char * resolved_path,size_t bufsize,const bslabel_t * sl)4661676Sjpk getpathbylabel(const char *path_name, char *resolved_path, size_t bufsize,
467*4541Sjparcel     const bslabel_t *sl)
468*4541Sjparcel {
4691676Sjpk 	char		ret_path[MAXPATHLEN];	/* pathname to return */
4701676Sjpk 	zoneid_t	zoneid;
4711676Sjpk 	struct mntlist *mlist;
4721676Sjpk 
4731676Sjpk 	if (getzoneid() != GLOBAL_ZONEID) {
4741676Sjpk 		errno = EINVAL;
4751676Sjpk 		return (NULL);
4761676Sjpk 	}
4771676Sjpk 
4781676Sjpk 	if (path_name[0] != '/') {		/* need absolute pathname */
4791676Sjpk 		errno = EINVAL;
4801676Sjpk 		return (NULL);
4811676Sjpk 	}
4821676Sjpk 
4831676Sjpk 	if (resolved_path == NULL) {
4841676Sjpk 		errno = EINVAL;
4851676Sjpk 		return (NULL);
4861676Sjpk 	}
4871676Sjpk 
4881676Sjpk 	if ((zoneid = getzoneidbylabel(sl)) == -1)
4891676Sjpk 		return (NULL);
4901676Sjpk 
4911676Sjpk 	/*
4921676Sjpk 	 * Construct the list of mounted file systems.
4931676Sjpk 	 */
4941676Sjpk 
4951676Sjpk 	if ((mlist = tsol_mkmntlist()) == NULL) {
4961676Sjpk 		return (NULL);
4971676Sjpk 	}
4981676Sjpk 	if (getglobalpath(path_name, zoneid, mlist, ret_path) == 0) {
4991676Sjpk 		tsol_mlist_free(mlist);
5001676Sjpk 		return (NULL);
5011676Sjpk 	}
5021676Sjpk 	tsol_mlist_free(mlist);
5031676Sjpk 	if (strlen(ret_path) >= bufsize) {
5041676Sjpk 		errno = EFAULT;
5051676Sjpk 		return (NULL);
5061676Sjpk 	}
5071676Sjpk 	return (strcpy(resolved_path, ret_path));
5081676Sjpk } /* end getpathbylabel() */
509