4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * Name: getpathbylabel.c
30 * Description: Returns the global zone pathname corresponding
31 * to the specified label. The pathname does
32 * not need to match an existing file system object.
39 #include <sys/types.h>
40 #include <tsol/label.h>
43 #include <sys/mntent.h>
44 #include <sys/mnttab.h>
48 * This structure is used to chain mntent structures into a list
49 * and to cache stat information for each member of the list.
52 struct mnttab
*mntl_mnt
;
53 struct mntlist
*mntl_next
;
58 * Return a pointer to the trailing suffix of full that follows the prefix
59 * given by pref. If pref isn't a prefix of full, return NULL. Apply
60 * pathname semantics to the prefix test, so that pref must match at a
64 pathsuffix(char *full
, char *pref
)
68 if (full
== NULL
|| pref
== NULL
)
71 preflen
= strlen(pref
);
72 if (strncmp(pref
, full
, preflen
) != 0)
76 * pref is a substring of full. To be a subpath, it cannot cover a
77 * partial component of full. The last clause of the test handles the
78 * special case of the root.
80 if (full
[preflen
] != '\0' && full
[preflen
] != '/' && preflen
> 1)
83 if (preflen
== 1 && full
[0] == '/')
86 return (full
+ preflen
);
90 * Return zero iff the path named by sub is a leading subpath
91 * of the path named by full.
93 * Treat null paths as matching nothing.
96 subpath(char *full
, char *sub
)
98 return (pathsuffix(full
, sub
) == NULL
);
102 tsol_mnt_free(struct mnttab
*mnt
)
104 free(mnt
->mnt_special
);
105 free(mnt
->mnt_mountp
);
106 free(mnt
->mnt_fstype
);
107 free(mnt
->mnt_mntopts
);
112 tsol_mlist_free(struct mntlist
*mlist
)
115 struct mntlist
*oldmlp
;
119 struct mnttab
*mnt
= mlp
->mntl_mnt
;
124 mlp
= mlp
->mntl_next
;
129 static struct mnttab
*
130 mntdup(struct mnttab
*mnt
)
134 new = (struct mnttab
*)malloc(sizeof (*new));
138 new->mnt_special
= NULL
;
139 new->mnt_mountp
= NULL
;
140 new->mnt_fstype
= NULL
;
141 new->mnt_mntopts
= NULL
;
143 new->mnt_special
= strdup(mnt
->mnt_special
);
144 if (new->mnt_special
== NULL
) {
148 new->mnt_mountp
= strdup(mnt
->mnt_mountp
);
149 if (new->mnt_mountp
== NULL
) {
153 new->mnt_fstype
= strdup(mnt
->mnt_fstype
);
154 if (new->mnt_fstype
== NULL
) {
158 new->mnt_mntopts
= strdup(mnt
->mnt_mntopts
);
159 if (new->mnt_mntopts
== NULL
) {
166 static struct mntlist
*
170 struct mntlist
*mntl
;
171 struct mntlist
*mntst
= NULL
;
174 if ((mounted
= fopen(MNTTAB
, "rF")) == NULL
) {
178 resetmnttab(mounted
);
179 while (getmntent(mounted
, &mnt
) == NULL
) {
180 mntl
= (struct mntlist
*)malloc(sizeof (*mntl
));
182 tsol_mlist_free(mntst
);
186 mntl
->mntl_mnt
= mntdup((struct mnttab
*)(&mnt
));
187 if (mntl
->mntl_mnt
== NULL
) {
188 tsol_mlist_free(mntst
);
192 mntl
->mntl_next
= mntst
;
195 (void) fclose(mounted
);
200 * This function attempts to convert local zone NFS mounted pathnames
201 * into equivalent global zone NFS mounted pathnames. At present
202 * it only works for automounted filesystems. It depends on the
203 * assumption that both the local and global zone automounters
204 * share the same nameservices. It also assumes that any automount
205 * map used by a local zone is available to the global zone automounter.
207 * The algorithm used consists of three phases.
209 * 1. The local zone's mnttab is searched to find the automount map
210 * with the closest matching mountpath.
212 * 2. The matching autmount map name is looked up in the global zone's
213 * mnttab to determine the path where it should be mounted in the
216 * 3. A pathname covered by an appropiate autofs trigger mount in
217 * the global zone is generated as the resolved pathname
219 * Among the things that can go wrong is that global zone doesn't have
220 * a matching automount map or the mount was not done via the automounter.
221 * Either of these cases return a NULL path.
223 #define ZONE_OPT "zone="
225 getnfspathbyautofs(struct mntlist
*mlist
, zoneid_t zoneid
,
226 struct mnttab
*autofs_mnt
, char *globalpath
, char *zonepath
, int global_len
)
229 char zonematch
[ZONENAME_MAX
+ 20];
230 char zonename
[ZONENAME_MAX
];
232 struct mnttab
*mountmatch
;
235 mountmatch
= autofs_mnt
;
236 longestmatch
= strlen(mountmatch
->mnt_mountp
);
239 * First we need to get the zonename to look for
241 if (zone_getattr(zoneid
, ZONE_ATTR_NAME
, zonename
,
242 ZONENAME_MAX
) == -1) {
246 (void) strncpy(zonematch
, ZONE_OPT
, sizeof (zonematch
));
247 (void) strlcat(zonematch
, zonename
, sizeof (zonematch
));
250 * Find the best match for an automount map that
251 * corresponds to the local zone's pathname
254 for (mlp
= mlist
; mlp
; mlp
= mlp
->mntl_next
) {
255 struct mnttab
*mnt
= mlp
->mntl_mnt
;
260 char mntopts
[MAXPATHLEN
];
262 if (subpath(globalpath
, mnt
->mnt_mountp
) != 0)
264 if (strcmp(mnt
->mnt_fstype
, MNTTYPE_AUTOFS
))
268 (void) strncpy(mntopts
, mnt
->mnt_mntopts
, MAXPATHLEN
);
269 if ((token
= strtok_r(mntopts
, ",", &lasts
)) != NULL
) {
270 if (strcmp(token
, zonematch
) == 0) {
272 } else while ((token
= strtok_r(NULL
, ",",
274 if (strcmp(token
, zonematch
) == 0) {
281 len
= strlen(mnt
->mnt_mountp
);
282 if (len
> longestmatch
) {
289 if (longestmatch
== 0) {
293 * Now we may have found the corresponding autofs mount
294 * Try to find the matching global zone autofs entry
297 for (mlp
= mlist
; mlp
; mlp
= mlp
->mntl_next
) {
302 struct mnttab
*mnt
= mlp
->mntl_mnt
;
304 if (strcmp(mountmatch
->mnt_special
,
305 mnt
->mnt_special
) != 0)
307 if (strcmp(mnt
->mnt_fstype
, MNTTYPE_AUTOFS
))
309 if (strstr(mnt
->mnt_mntopts
, ZONE_OPT
) != NULL
)
312 * OK, we have a matching global zone automap
313 * so adjust the path for the global zone.
315 zp_len
= strlen(zonepath
);
316 mp_len
= strlen(mnt
->mnt_mountp
);
317 (void) strncpy(p
, globalpath
+ zp_len
, MAXPATHLEN
);
319 * If both global zone and zone-relative
320 * mountpoint match, just use the same pathname
322 if (strncmp(mnt
->mnt_mountp
, p
, mp_len
) == 0) {
323 (void) strncpy(globalpath
, p
, global_len
);
326 (void) strncpy(p
, globalpath
, MAXPATHLEN
);
327 (void) strncpy(globalpath
, mnt
->mnt_mountp
,
329 (void) strlcat(globalpath
,
330 p
+ strlen(mountmatch
->mnt_mountp
),
340 * Find the pathname for the entry in mlist that corresponds to the
341 * file named by path (i.e., that names a mount table entry for the
342 * file system in which path lies).
344 * Return 0 is there an error.
347 getglobalpath(const char *path
, zoneid_t zoneid
, struct mntlist
*mlist
,
351 char lofspath
[MAXPATHLEN
];
352 char zonepath
[MAXPATHLEN
];
354 struct mnttab
*mountmatch
;
356 if (zoneid
!= GLOBAL_ZONEID
) {
359 if ((prefix
= getzonerootbyid(zoneid
)) == NULL
) {
362 (void) strncpy(zonepath
, prefix
, MAXPATHLEN
);
363 (void) strlcpy(globalpath
, prefix
, MAXPATHLEN
);
364 (void) strlcat(globalpath
, path
, MAXPATHLEN
);
367 (void) strlcpy(globalpath
, path
, MAXPATHLEN
);
372 for (mlp
= mlist
; mlp
; mlp
= mlp
->mntl_next
) {
373 struct mnttab
*mnt
= mlp
->mntl_mnt
;
376 if (subpath(globalpath
, mnt
->mnt_mountp
) != 0)
378 len
= strlen(mnt
->mnt_mountp
);
379 if (len
> longestmatch
) {
385 * Handle interesting mounts.
387 if ((strcmp(mountmatch
->mnt_fstype
, MNTTYPE_NFS
) == 0) ||
388 (strcmp(mountmatch
->mnt_fstype
, MNTTYPE_AUTOFS
) == 0)) {
389 if (zoneid
> GLOBAL_ZONEID
) {
390 struct mnttab
*m
= NULL
;
392 if (strcmp(mountmatch
->mnt_fstype
,
393 MNTTYPE_AUTOFS
) == 0)
395 if (getnfspathbyautofs(mlist
, zoneid
, m
,
396 globalpath
, zonepath
, MAXPATHLEN
) == 0) {
401 } else if (strcmp(mountmatch
->mnt_fstype
, MNTTYPE_LOFS
) == 0) {
403 * count up what's left
407 remainder
= strlen(globalpath
) - longestmatch
;
409 path
= pathsuffix(globalpath
,
410 mountmatch
->mnt_mountp
);
411 (void) strlcpy(lofspath
, path
, MAXPATHLEN
);
413 (void) strlcpy(globalpath
, mountmatch
->mnt_special
,
416 (void) strlcat(globalpath
, lofspath
,
420 if ((zoneid
> GLOBAL_ZONEID
) &&
421 (strncmp(path
, "/home/", strlen("/home/")) == 0)) {
422 char zonename
[ZONENAME_MAX
];
425 * If this is a cross-zone reference to
426 * a home directory, it must be corrected.
427 * We should only get here if the zone's
428 * automounter hasn't yet mounted its
429 * autofs trigger on /home.
431 * Since it is likely to do so in the
432 * future, we will assume that the global
433 * zone already has an equivalent autofs
434 * mount established. By convention,
435 * this should be mounted at the
439 if (zone_getattr(zoneid
, ZONE_ATTR_NAME
,
440 zonename
, ZONENAME_MAX
) == -1) {
443 (void) snprintf(globalpath
, MAXPATHLEN
,
444 "/zone/%s%s", zonename
, path
);
455 * This function is only useful for global zone callers
456 * It uses the global zone mnttab to translate local zone pathnames
457 * into global zone pathnames.
460 getpathbylabel(const char *path_name
, char *resolved_path
, size_t bufsize
,
463 char ret_path
[MAXPATHLEN
]; /* pathname to return */
465 struct mntlist
*mlist
;
467 if (getzoneid() != GLOBAL_ZONEID
) {
472 if (path_name
[0] != '/') { /* need absolute pathname */
477 if (resolved_path
== NULL
) {
482 if ((zoneid
= getzoneidbylabel(sl
)) == -1)
486 * Construct the list of mounted file systems.
489 if ((mlist
= tsol_mkmntlist()) == NULL
) {
492 if (getglobalpath(path_name
, zoneid
, mlist
, ret_path
) == 0) {
493 tsol_mlist_free(mlist
);
496 tsol_mlist_free(mlist
);
497 if (strlen(ret_path
) >= bufsize
) {
501 return (strcpy(resolved_path
, ret_path
));
502 } /* end getpathbylabel() */