#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libintl.h>
#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/mntent.h>
#include <sys/mnttab.h>
#include <sys/param.h>
#include <libzonecfg.h>
#include "zones_strings.h"
#include "instzones_lib.h"
#define MNTTAB "/etc/mnttab"
#define MNTTAB_HUNK 32
static struct mnttab *mountTable;
static size_t mountTableSize = 0;
static boolean_t createdFlag = B_FALSE;
int
z_createMountTable(void)
{
FILE *fp;
struct mnttab ent;
struct mnttab *entp;
if (createdFlag) {
return (0);
}
fp = fopen(MNTTAB, "r");
if (fp == NULL) {
_z_program_error(ERR_OPEN_READ, MNTTAB, errno,
strerror(errno));
return (-1);
}
mountTable = NULL;
mountTableSize = 0;
createdFlag = B_TRUE;
while (getmntent(fp, &ent) == 0) {
if (mountTableSize % MNTTAB_HUNK == 0) {
mountTable = _z_realloc(mountTable,
(mountTableSize + MNTTAB_HUNK) * sizeof (ent));
}
entp = &mountTable[mountTableSize++];
(void) memset(entp, 0, sizeof (*entp));
if (ent.mnt_special != NULL)
entp->mnt_special = _z_strdup(ent.mnt_special);
if (ent.mnt_mntopts != NULL)
entp->mnt_mntopts = _z_strdup(ent.mnt_mntopts);
entp->mnt_mountp = _z_strdup(ent.mnt_mountp);
entp->mnt_fstype = _z_strdup(ent.mnt_fstype);
}
(void) fclose(fp);
return (0);
}
static int
findPathRWStatus(const char *a_path)
{
int i;
for (i = 0; i < mountTableSize; i++) {
if (strcmp(a_path, mountTable[i].mnt_mountp) == 0) {
if (hasmntopt(&mountTable[i], MNTOPT_RO) != NULL) {
return (0);
} else {
return (1);
}
}
}
return (-1);
}
int
z_isPathWritable(const char *a_str)
{
int i, result, slen;
char a_path[MAXPATHLEN];
if (!createdFlag) {
if (z_createMountTable() != 0) {
return (1);
}
}
(void) strlcpy(a_path, a_str, sizeof (a_path));
slen = strlen(a_path);
for (i = slen; i > 0; i--) {
if ((a_path[i] == '/') || (a_path[i] == '\0')) {
a_path[i] = '\0';
result = findPathRWStatus(a_path);
if (result != -1) {
return (result);
}
}
}
return (1);
}
void
z_destroyMountTable(void)
{
int i;
if (!createdFlag) {
return;
}
if (mountTable == NULL) {
return;
}
for (i = 0; i < mountTableSize; i++) {
free(mountTable[i].mnt_mountp);
free(mountTable[i].mnt_fstype);
free(mountTable[i].mnt_special);
free(mountTable[i].mnt_mntopts);
assert(mountTable[i].mnt_time == NULL);
}
free(mountTable);
mountTable = NULL;
mountTableSize = 0;
createdFlag = B_FALSE;
}
void
z_resolve_lofs(char *path, size_t pathlen)
{
int len, arlen, i;
const char *altroot;
char tmppath[MAXPATHLEN];
boolean_t outside_altroot;
if ((len = resolvepath(path, tmppath, sizeof (tmppath))) == -1)
return;
tmppath[len] = '\0';
(void) strlcpy(path, tmppath, pathlen);
if (z_createMountTable() == -1)
return;
altroot = zonecfg_get_root();
arlen = strlen(altroot);
outside_altroot = B_FALSE;
for (;;) {
struct mnttab *mnp;
for (i = mountTableSize; i > 0; i--) {
mnp = &mountTable[i - 1];
if (mnp->mnt_fstype == NULL ||
mnp->mnt_mountp == NULL ||
mnp->mnt_special == NULL)
continue;
len = strlen(mnp->mnt_mountp);
if (strncmp(mnp->mnt_mountp, path, len) == 0 &&
(path[len] == '/' || path[len] == '\0'))
break;
}
if (i <= 0)
break;
if (strcmp(mnp->mnt_fstype, MNTTYPE_LOFS) != 0)
break;
if (outside_altroot) {
char *cp;
int olen = sizeof (MNTOPT_RO) - 1;
if (mnp->mnt_mntopts != NULL &&
(cp = strstr(mnp->mnt_mntopts, MNTOPT_RO)) !=
NULL &&
(cp == mnp->mnt_mntopts || cp[-1] == ',') &&
(cp[olen] == '\0' || cp[olen] == ',')) {
break;
}
} else if (arlen > 0 &&
(strncmp(mnp->mnt_special, altroot, arlen) != 0 ||
(mnp->mnt_special[arlen] != '\0' &&
mnp->mnt_special[arlen] != '/'))) {
outside_altroot = B_TRUE;
}
(void) snprintf(tmppath, sizeof (tmppath), "%s%s",
mnp->mnt_special, path + len);
if ((len = resolvepath(tmppath, path, pathlen)) == -1)
break;
path[len] = '\0';
}
}