/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #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; /* * Name : z_createMountTable * Description : Populate the mountTable Array with mnttab entries * Arguments : void * Returns : int * 0: The Mount Table was succesfully initialized * -1: There was an error during initialisation */ 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); } /* Put the entries into the table */ 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++]; /* * Zero out any fields we're not using. */ (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); } /* * Name : findPathRWStatus * Description : Check whether the given path is an mnttab entry * Arguments : char * - The Path to be verified * Returns : int * -1: The Path is NOT present in the table (mnttab) * 0: The Path is present in the table and is mounted read-only * 1: The Path is present in the table and is mounted read-write */ 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); } /* * Name : z_isPathWritable * Description : Check if the given path is in a writable area * Arguments : char * - The Path to be verified * Returns : int * 0: The Path is under a read-only mount * 1: The Path is under a read-write mount * NOTE : This funcion automatically initialises * the mountPoint table if needed. */ 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); /* * This for loop traverses Path backwards, incrementally removing the * basename of Path and looking for the resultant directory in the * mnttab. Once found, it returns the rw status of that file system. */ 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); } /* * Name : z_destroyMountTable * Description : Clear the entries in the mount table * Arguments : void * Returns : void */ 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; } /* * Name : z_resolve_lofs * Description : Loop over potential loopback mounts and symlinks in a * given path and resolve them all down to an absolute path. * Arguments : char * - path to resolve. path is in writable storage. * size_t - length of path storage. * Returns : void */ 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; /* Search in reverse order to find longest match */ 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 it's not a lofs then we're done */ if (strcmp(mnp->mnt_fstype, MNTTYPE_LOFS) != 0) break; if (outside_altroot) { char *cp; int olen = sizeof (MNTOPT_RO) - 1; /* * If we run into a read-only mount outside of the * alternate root environment, then the user doesn't * want this path to be made read-write. */ 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; } /* use temporary buffer because new path might be longer */ (void) snprintf(tmppath, sizeof (tmppath), "%s%s", mnp->mnt_special, path + len); if ((len = resolvepath(tmppath, path, pathlen)) == -1) break; path[len] = '\0'; } }