#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <tsol/label.h>
#include <stdlib.h>
#include <zone.h>
#include <sys/mntent.h>
#include <sys/mnttab.h>
#include <stdarg.h>
struct mntlist {
struct mnttab *mntl_mnt;
struct mntlist *mntl_next;
};
static char *
pathsuffix(char *full, char *pref)
{
int preflen;
if (full == NULL || pref == NULL)
return (NULL);
preflen = strlen(pref);
if (strncmp(pref, full, preflen) != 0)
return (NULL);
if (full[preflen] != '\0' && full[preflen] != '/' && preflen > 1)
return (NULL);
if (preflen == 1 && full[0] == '/')
return (full);
else
return (full + preflen);
}
static int
subpath(char *full, char *sub)
{
return (pathsuffix(full, sub) == NULL);
}
static void
tsol_mnt_free(struct mnttab *mnt)
{
if (mnt->mnt_special)
free(mnt->mnt_special);
if (mnt->mnt_mountp)
free(mnt->mnt_mountp);
if (mnt->mnt_fstype)
free(mnt->mnt_fstype);
if (mnt->mnt_mntopts)
free(mnt->mnt_mntopts);
free(mnt);
}
static void
tsol_mlist_free(struct mntlist *mlist)
{
struct mntlist *mlp;
struct mntlist *oldmlp;
mlp = mlist;
while (mlp) {
struct mnttab *mnt = mlp->mntl_mnt;
if (mnt)
tsol_mnt_free(mnt);
oldmlp = mlp;
mlp = mlp->mntl_next;
free(oldmlp);
}
}
static struct mnttab *
mntdup(struct mnttab *mnt)
{
struct mnttab *new;
new = (struct mnttab *)malloc(sizeof (*new));
if (new == NULL)
return (NULL);
new->mnt_special = NULL;
new->mnt_mountp = NULL;
new->mnt_fstype = NULL;
new->mnt_mntopts = NULL;
new->mnt_special = strdup(mnt->mnt_special);
if (new->mnt_special == NULL) {
tsol_mnt_free(new);
return (NULL);
}
new->mnt_mountp = strdup(mnt->mnt_mountp);
if (new->mnt_mountp == NULL) {
tsol_mnt_free(new);
return (NULL);
}
new->mnt_fstype = strdup(mnt->mnt_fstype);
if (new->mnt_fstype == NULL) {
tsol_mnt_free(new);
return (NULL);
}
new->mnt_mntopts = strdup(mnt->mnt_mntopts);
if (new->mnt_mntopts == NULL) {
tsol_mnt_free(new);
return (NULL);
}
return (new);
}
static struct mntlist *
tsol_mkmntlist(void)
{
FILE *mounted;
struct mntlist *mntl;
struct mntlist *mntst = NULL;
struct mnttab mnt;
if ((mounted = fopen(MNTTAB, "rF")) == NULL) {
perror(MNTTAB);
return (NULL);
}
resetmnttab(mounted);
while (getmntent(mounted, &mnt) == 0) {
mntl = (struct mntlist *)malloc(sizeof (*mntl));
if (mntl == NULL) {
tsol_mlist_free(mntst);
mntst = NULL;
break;
}
mntl->mntl_mnt = mntdup((struct mnttab *)(&mnt));
if (mntl->mntl_mnt == NULL) {
tsol_mlist_free(mntst);
mntst = NULL;
break;
}
mntl->mntl_next = mntst;
mntst = mntl;
}
(void) fclose(mounted);
return (mntst);
}
#define ZONE_OPT "zone="
static int
getnfspathbyautofs(struct mntlist *mlist, zoneid_t zoneid,
struct mnttab *autofs_mnt, char *globalpath, char *zonepath, int global_len)
{
struct mntlist *mlp;
char zonematch[ZONENAME_MAX + 20];
char zonename[ZONENAME_MAX];
int longestmatch;
struct mnttab *mountmatch;
if (autofs_mnt) {
mountmatch = autofs_mnt;
longestmatch = strlen(mountmatch->mnt_mountp);
} else {
if (zone_getattr(zoneid, ZONE_ATTR_NAME, zonename,
ZONENAME_MAX) == -1) {
return (0);
}
(void) strncpy(zonematch, ZONE_OPT, sizeof (zonematch));
(void) strlcat(zonematch, zonename, sizeof (zonematch));
longestmatch = 0;
for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
struct mnttab *mnt = mlp->mntl_mnt;
int len;
int matchfound;
char *token;
char *lasts;
char mntopts[MAXPATHLEN];
if (subpath(globalpath, mnt->mnt_mountp) != 0)
continue;
if (strcmp(mnt->mnt_fstype, MNTTYPE_AUTOFS))
continue;
matchfound = 0;
(void) strncpy(mntopts, mnt->mnt_mntopts, MAXPATHLEN);
if ((token = strtok_r(mntopts, ",", &lasts)) != NULL) {
if (strcmp(token, zonematch) == 0) {
matchfound = 1;
} else while ((token = strtok_r(NULL, ",",
&lasts)) != NULL) {
if (strcmp(token, zonematch) == 0) {
matchfound = 1;
break;
}
}
}
if (matchfound) {
len = strlen(mnt->mnt_mountp);
if (len > longestmatch) {
mountmatch = mnt;
longestmatch = len;
}
}
}
}
if (longestmatch == 0) {
return (0);
} else {
for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
char p[MAXPATHLEN];
size_t zp_len;
size_t mp_len;
struct mnttab *mnt = mlp->mntl_mnt;
if (strcmp(mountmatch->mnt_special,
mnt->mnt_special) != 0)
continue;
if (strcmp(mnt->mnt_fstype, MNTTYPE_AUTOFS))
continue;
if (strstr(mnt->mnt_mntopts, ZONE_OPT) != NULL)
continue;
zp_len = strlen(zonepath);
mp_len = strlen(mnt->mnt_mountp);
(void) strncpy(p, globalpath + zp_len, MAXPATHLEN);
if (strncmp(mnt->mnt_mountp, p, mp_len) == 0) {
(void) strncpy(globalpath, p, global_len);
return (1);
} else {
(void) strncpy(p, globalpath, MAXPATHLEN);
(void) strncpy(globalpath, mnt->mnt_mountp,
global_len);
(void) strlcat(globalpath,
p + strlen(mountmatch->mnt_mountp),
global_len);
return (1);
}
}
return (0);
}
}
static int
getglobalpath(const char *path, zoneid_t zoneid, struct mntlist *mlist,
char *globalpath)
{
struct mntlist *mlp;
char lofspath[MAXPATHLEN];
char zonepath[MAXPATHLEN];
int longestmatch;
struct mnttab *mountmatch;
if (zoneid != GLOBAL_ZONEID) {
char *prefix;
if ((prefix = getzonerootbyid(zoneid)) == NULL) {
return (0);
}
(void) strncpy(zonepath, prefix, MAXPATHLEN);
(void) strlcpy(globalpath, prefix, MAXPATHLEN);
(void) strlcat(globalpath, path, MAXPATHLEN);
free(prefix);
} else {
(void) strlcpy(globalpath, path, MAXPATHLEN);
}
for (;;) {
longestmatch = 0;
for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
struct mnttab *mnt = mlp->mntl_mnt;
int len;
if (subpath(globalpath, mnt->mnt_mountp) != 0)
continue;
len = strlen(mnt->mnt_mountp);
if (len > longestmatch) {
mountmatch = mnt;
longestmatch = len;
}
}
if ((strcmp(mountmatch->mnt_fstype, MNTTYPE_NFS) == 0) ||
(strcmp(mountmatch->mnt_fstype, MNTTYPE_AUTOFS) == 0)) {
if (zoneid > GLOBAL_ZONEID) {
struct mnttab *m = NULL;
if (strcmp(mountmatch->mnt_fstype,
MNTTYPE_AUTOFS) == 0)
m = mountmatch;
if (getnfspathbyautofs(mlist, zoneid, m,
globalpath, zonepath, MAXPATHLEN) == 0) {
return (0);
}
}
break;
} else if (strcmp(mountmatch->mnt_fstype, MNTTYPE_LOFS) == 0) {
int remainder;
remainder = strlen(globalpath) - longestmatch;
if (remainder > 0) {
path = pathsuffix(globalpath,
mountmatch->mnt_mountp);
(void) strlcpy(lofspath, path, MAXPATHLEN);
}
(void) strlcpy(globalpath, mountmatch->mnt_special,
MAXPATHLEN);
if (remainder > 0) {
(void) strlcat(globalpath, lofspath,
MAXPATHLEN);
}
} else {
if ((zoneid > GLOBAL_ZONEID) &&
(strncmp(path, "/home/", strlen("/home/")) == 0)) {
char zonename[ZONENAME_MAX];
if (zone_getattr(zoneid, ZONE_ATTR_NAME,
zonename, ZONENAME_MAX) == -1) {
return (0);
} else {
(void) snprintf(globalpath, MAXPATHLEN,
"/zone/%s%s", zonename, path);
}
}
break;
}
}
return (1);
}
char *
getpathbylabel(const char *path_name, char *resolved_path, size_t bufsize,
const bslabel_t *sl)
{
char ret_path[MAXPATHLEN];
zoneid_t zoneid;
struct mntlist *mlist;
if (getzoneid() != GLOBAL_ZONEID) {
errno = EINVAL;
return (NULL);
}
if (path_name[0] != '/') {
errno = EINVAL;
return (NULL);
}
if (resolved_path == NULL) {
errno = EINVAL;
return (NULL);
}
if ((zoneid = getzoneidbylabel(sl)) == -1)
return (NULL);
if ((mlist = tsol_mkmntlist()) == NULL) {
return (NULL);
}
if (getglobalpath(path_name, zoneid, mlist, ret_path) == 0) {
tsol_mlist_free(mlist);
return (NULL);
}
tsol_mlist_free(mlist);
if (strlen(ret_path) >= bufsize) {
errno = EFAULT;
return (NULL);
}
return (strcpy(resolved_path, ret_path));
}