OpenSolaris_b135/lib/libinstzones/common/zones_lofs.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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 <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;

/*
 * 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';
	}
}