#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <libintl.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <syslog.h>
#include <alloca.h>
#include <sys/vfstab.h>
#include <sys/mnttab.h>
#include <sys/mntent.h>
#include <sys/mount.h>
#include <sys/filio.h>
#include <sys/fs/ufs_filio.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <zone.h>
#include <signal.h>
#include <strings.h>
#include "fslib.h"
#define BUFLEN 256
#define TIME_MAX 16
mntlist_t *
fsgetmntlist(void)
{
FILE *mfp;
mntlist_t *mntl;
char buf[BUFLEN];
if ((mfp = fopen(MNTTAB, "r")) == NULL) {
(void) snprintf(buf, BUFLEN, "fsgetmntlist: fopen %s", MNTTAB);
perror(buf);
return (NULL);
}
mntl = fsmkmntlist(mfp);
(void) fclose(mfp);
return (mntl);
}
static struct extmnttab zmnttab = { 0 };
struct extmnttab *
fsdupmnttab(struct extmnttab *mnt)
{
struct extmnttab *new;
new = (struct extmnttab *)malloc(sizeof (*new));
if (new == NULL)
goto alloc_failed;
*new = zmnttab;
new->mnt_mountp = (char *)malloc(strlen(mnt->mnt_mountp) + 2);
if (new->mnt_mountp == NULL)
goto alloc_failed;
(void) strcpy(new->mnt_mountp, mnt->mnt_mountp);
if ((new->mnt_special = strdup(mnt->mnt_special)) == NULL)
goto alloc_failed;
if ((new->mnt_fstype = strdup(mnt->mnt_fstype)) == NULL)
goto alloc_failed;
if (mnt->mnt_mntopts != NULL)
if ((new->mnt_mntopts = strdup(mnt->mnt_mntopts)) == NULL)
goto alloc_failed;
if (mnt->mnt_time != NULL)
if ((new->mnt_time = strdup(mnt->mnt_time)) == NULL)
goto alloc_failed;
new->mnt_major = mnt->mnt_major;
new->mnt_minor = mnt->mnt_minor;
return (new);
alloc_failed:
(void) fprintf(stderr, gettext("fsdupmnttab: Out of memory\n"));
fsfreemnttab(new);
return (NULL);
}
void
fsfreemnttab(struct extmnttab *mnt)
{
if (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);
if (mnt->mnt_time)
free(mnt->mnt_time);
free(mnt);
}
}
void
fsfreemntlist(mntlist_t *mntl)
{
mntlist_t *mntl_tmp;
while (mntl) {
fsfreemnttab(mntl->mntl_mnt);
mntl_tmp = mntl;
mntl = mntl->mntl_next;
free(mntl_tmp);
}
}
mntlist_t *
fsmkmntlist(FILE *mfp)
{
struct extmnttab mnt;
mntlist_t *mhead, *mtail;
int ret;
mhead = mtail = NULL;
resetmnttab(mfp);
while ((ret = getextmntent(mfp, &mnt, sizeof (struct extmnttab)))
!= -1) {
mntlist_t *mp;
if (ret != 0)
continue;
mp = (mntlist_t *)malloc(sizeof (*mp));
if (mp == NULL)
goto alloc_failed;
if (mhead == NULL)
mhead = mp;
else
mtail->mntl_next = mp;
mtail = mp;
mp->mntl_next = NULL;
mp->mntl_flags = 0;
if ((mp->mntl_mnt = fsdupmnttab(&mnt)) == NULL)
goto alloc_failed;
}
return (mhead);
alloc_failed:
fsfreemntlist(mhead);
return (NULL);
}
mntlist_t *
fsgetmlast(mntlist_t *ml, struct mnttab *mntin)
{
mntlist_t *delete = NULL;
for (; ml; ml = ml->mntl_next) {
if (mntin->mnt_mountp && mntin->mnt_special) {
if ((strcmp(ml->mntl_mnt->mnt_mountp,
mntin->mnt_mountp) == 0) &&
(strcmp(ml->mntl_mnt->mnt_special,
mntin->mnt_special) == 0))
delete = ml;
} else if (mntin->mnt_mountp) {
if (strcmp(ml->mntl_mnt->mnt_mountp,
mntin->mnt_mountp) == 0)
delete = ml;
} else if (mntin->mnt_special) {
if (strcmp(ml->mntl_mnt->mnt_special,
mntin->mnt_special) == 0)
delete = ml;
}
}
return (delete);
}
int
fsgetmlevel(char *cp)
{
int mlevel;
char *cp1;
if (cp == NULL || *cp == '\0' || *cp != '/')
return (0);
mlevel = 1;
for (cp1 = cp + 1; *cp1; cp++, cp1++)
if (*cp == '/' && *cp1 != '/')
mlevel++;
return (mlevel);
}
int
fsstrinlist(const char *s, const char **ps)
{
const char *cp;
cp = *ps;
while (cp) {
if (strcmp(s, cp) == 0)
return (1);
ps++;
cp = *ps;
}
return (0);
}
static char *empty_opt_vector[] = {
NULL
};
void
cmp_requested_to_actual_options(char *requested_opts, char *actual_opts,
char *special, char *mountp)
{
char *option_ptr, *actopt, *equalptr;
int found;
char *actual_opt_hold, *bufp;
if (requested_opts == NULL)
return;
if (actual_opts == NULL)
bufp = alloca(1);
else
bufp = alloca(strlen(actual_opts) + 1);
while (*requested_opts != '\0') {
(void) getsubopt(&requested_opts, empty_opt_vector,
&option_ptr);
if ((equalptr = strchr(option_ptr, '=')) != NULL)
*equalptr = '\0';
if (*option_ptr == '\0')
continue;
if (strcmp(option_ptr, "loop") == 0)
continue;
found = 0;
actual_opt_hold = bufp;
if (actual_opts != NULL)
(void) strcpy(actual_opt_hold, actual_opts);
else
*actual_opt_hold = '\0';
while (*actual_opt_hold != '\0') {
(void) getsubopt(&actual_opt_hold, empty_opt_vector,
&actopt);
if ((equalptr = strchr(actopt, '=')) != NULL)
*equalptr = '\0';
if ((strcmp(option_ptr, actopt)) == 0) {
found = 1;
break;
}
}
if (found == 0) {
(void) fprintf(stderr, gettext(
"mount: %s on %s - WARNING ignoring option "
"\"%s\"\n"), special, mountp, option_ptr);
}
}
}
int
fsgetmaxphys(int *maxphys, int *error)
{
int gotit = 0;
int fp = open("/", O_RDONLY);
*error = 0;
if (fp == -1) {
return (gotit);
}
if (ioctl(fp, _FIOGETMAXPHYS, maxphys) == -1) {
*error = errno;
(void) close(fp);
return (gotit);
}
(void) close(fp);
gotit = 1;
return (gotit);
}
struct zone_summary {
zoneid_t zoneid;
char rootpath[MAXPATHLEN];
size_t rootpathlen;
};
struct zone_summary *
fs_get_zone_summaries(void)
{
uint_t numzones = 0, oldnumzones = 0;
uint_t i, j;
zoneid_t *ids = NULL;
struct zone_summary *summaries;
zoneid_t myzoneid = getzoneid();
for (;;) {
if (zone_list(ids, &numzones) < 0) {
perror("unable to retrieve list of zones");
if (ids != NULL)
free(ids);
return (NULL);
}
if (numzones <= oldnumzones)
break;
if (ids != NULL)
free(ids);
ids = malloc(numzones * sizeof (*ids));
if (ids == NULL) {
perror("malloc failed");
return (NULL);
}
oldnumzones = numzones;
}
summaries = malloc((numzones + 1) * sizeof (*summaries));
if (summaries == NULL) {
free(ids);
perror("malloc failed");
return (NULL);
}
for (i = 0, j = 0; i < numzones; i++) {
ssize_t len;
if (ids[i] == myzoneid)
continue;
len = zone_getattr(ids[i], ZONE_ATTR_ROOT,
summaries[j].rootpath, sizeof (summaries[j].rootpath));
if (len < 0) {
continue;
}
(void) strlcat(summaries[j].rootpath, "/",
sizeof (summaries[j].rootpath));
summaries[j].rootpathlen = len;
summaries[j].zoneid = ids[i];
j++;
}
summaries[j].zoneid = -1;
free(ids);
return (summaries);
}
static zoneid_t
fs_find_zone(const struct zone_summary *summaries, const char *mntpt)
{
uint_t i;
for (i = 0; summaries[i].zoneid != -1; i++) {
if (strncmp(mntpt, summaries[i].rootpath,
summaries[i].rootpathlen) == 0)
return (summaries[i].zoneid);
}
return (-1);
}
boolean_t
fs_mount_in_other_zone(const struct zone_summary *summaries, const char *mntpt)
{
return (fs_find_zone(summaries, mntpt) != -1);
}
static const char *stdopts[] = {
MNTOPT_RO, MNTOPT_RW,
MNTOPT_SUID, MNTOPT_NOSUID,
MNTOPT_DEVICES, MNTOPT_NODEVICES,
MNTOPT_SETUID, MNTOPT_NOSETUID,
MNTOPT_NBMAND, MNTOPT_NONBMAND,
MNTOPT_EXEC, MNTOPT_NOEXEC,
};
#define NSTDOPT (sizeof (stdopts) / sizeof (stdopts[0]))
static int
optindx(const char *opt)
{
int i;
for (i = 0; i < NSTDOPT; i++) {
if (strcmp(opt, stdopts[i]) == 0)
return (i);
}
return (-1);
}
boolean_t
fsisstdopt(const char *opt)
{
return (optindx(opt) != -1);
}