OpenSolaris_b135/lib/libinstzones/common/zones_states.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.
 */


/*
 * Module:	zones_states.c
 * Group:	libinstzones
 * Description:	Provide "zones" state interfaces for install consolidation code
 *
 * Public Methods:
 *
 *  z_make_zone_running - change state of non-global zone to "running"
 * _z_make_zone_ready - change state of non-global zone to "ready"
 * _z_make_zone_down - change state of non-global zone to "down"
 */

/*
 * System includes
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/param.h>
#include <string.h>
#include <strings.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <limits.h>
#include <errno.h>
#include <stropts.h>
#include <libintl.h>
#include <locale.h>
#include <assert.h>

/*
 * local includes
 */

#include "instzones_lib.h"
#include "zones_strings.h"

/*
 * Private structures
 */

/*
 * Library Function Prototypes
 */

/*
 * Local Function Prototypes
 */

/*
 * global internal (private) declarations
 */

/*
 * *****************************************************************************
 * global external (public) functions
 * *****************************************************************************
 */

/*
 * Name:	_z_make_zone_running
 * Description:	Given a zone element entry for the non-global zone to affect,
 *		change the state of that non-global zone to "running"
 * Arguments:	a_zlem - [RO, *RW] - (zoneListElement_t)
 *			Zone list element describing the non-global zone to
 *			make running
 * Returns:	boolean_t
 *			B_TRUE - non-global zone state changed successfully
 *			B_FALSE - failed to make the non-global zone run
 */

boolean_t
_z_make_zone_running(zoneListElement_t *a_zlem)
{
	FILE		*fp;
	argArray_t	*args;
	char		 zonename[ZONENAME_MAX];
	char		*results = (char *)NULL;
	int		ret;
	int		status = 0;

	/* entry assertions */

	assert(a_zlem != NULL);

	/* act based on the zone's current kernel state */

	switch (a_zlem->_zlCurrKernelStatus) {
	case ZONE_STATE_RUNNING:
	case ZONE_STATE_MOUNTED:
		/* already running */
		return (B_TRUE);

	case ZONE_STATE_READY:
		/* This should never happen */
		if (zonecfg_in_alt_root())
			return (B_FALSE);

		/*
		 * We're going to upset the zone anyway, so might as well just
		 * halt it now and fall through to normal mounting.
		 */

		_z_echoDebug(DBG_TO_ZONEHALT, a_zlem->_zlName);

		args = _z_new_args(5);		/* generate new arg list */
		(void) _z_add_arg(args, ZONEADM_CMD);
		(void) _z_add_arg(args, "-z");
		(void) _z_add_arg(args, a_zlem->_zlName);
		(void) _z_add_arg(args, "halt");

		ret = z_ExecCmdArray(&status, &results, (char *)NULL,
		    ZONEADM_CMD, _z_get_argv(args));

		/* free generated argument list */

		_z_free_args(args);

		if (ret != 0) {
			_z_program_error(ERR_ZONEHALT_EXEC, ZONEADM_CMD,
			    strerror(errno));
			free(results);
			return (B_FALSE);
		}
		if (status != 0) {
			if (status == -1) {
				_z_program_error(ERR_ZONEBOOT_CMD_SIGNAL,
				    ZONEADM_CMD, a_zlem->_zlName);
			} else {
				_z_program_error(ERR_ZONEBOOT_CMD_ERROR,
				    ZONEADM_CMD, a_zlem->_zlName, status,
				    results == NULL ? "" : "\n",
				    results == NULL ? "" : results);
			}
			free(results);
			return (B_FALSE);
		}

		free(results);

		a_zlem->_zlCurrKernelStatus = ZONE_STATE_INSTALLED;
		/* FALLTHROUGH */

	case ZONE_STATE_INSTALLED:
	case ZONE_STATE_DOWN:
		/* return false if the zone cannot be booted */

		if (a_zlem->_zlStatus & ZST_NOT_BOOTABLE) {
			return (B_FALSE);
		}

		_z_echoDebug(DBG_TO_ZONERUNNING, a_zlem->_zlName);

		/* these states can be booted - do so */

		args = _z_new_args(10);		/* generate new arg list */
		(void) _z_add_arg(args, ZONEADM_CMD);
		if (zonecfg_in_alt_root()) {
			(void) _z_add_arg(args, "-R");
			(void) _z_add_arg(args, "%s",
			    (char *)zonecfg_get_root());
		}

		(void) _z_add_arg(args, "-z");
		(void) _z_add_arg(args, "%s", a_zlem->_zlName);
		(void) _z_add_arg(args, "mount");

		ret = z_ExecCmdArray(&status, &results, (char *)NULL,
		    ZONEADM_CMD, _z_get_argv(args));

		/* free generated argument list */

		_z_free_args(args);

		if (ret != 0) {
			_z_program_error(ERR_ZONEBOOT_EXEC, ZONEADM_CMD,
			    strerror(errno));
			free(results);
			return (B_FALSE);
		}

		if (status != 0) {
			if (status == -1) {
				_z_program_error(ERR_ZONEBOOT_CMD_SIGNAL,
				    ZONEADM_CMD, a_zlem->_zlName);
			} else {
				_z_program_error(ERR_ZONEBOOT_CMD_ERROR,
				    ZONEADM_CMD, a_zlem->_zlName, status,
				    results == NULL ? "" : "\n",
				    results == NULL ? "" : results);
			}
			free(results);

			/* remember this zone cannot be booted */

			a_zlem->_zlStatus |= ZST_NOT_BOOTABLE;

			return (B_FALSE);
		}
		free(results);

		if (zonecfg_in_alt_root()) {
			if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL ||
			    zonecfg_find_scratch(fp, a_zlem->_zlName,
			    zonecfg_get_root(), zonename,
			    sizeof (zonename)) == -1) {
				_z_program_error(ERR_ZONEBOOT_DIDNT_BOOT,
				    a_zlem->_zlName);
				if (fp != NULL)
					zonecfg_close_scratch(fp);
				return (B_FALSE);
			}
			zonecfg_close_scratch(fp);
			free(a_zlem->_zlScratchName);
			a_zlem->_zlScratchName = _z_strdup(zonename);
		}
		a_zlem->_zlCurrKernelStatus = ZONE_STATE_MOUNTED;
		return (B_TRUE);

	case ZONE_STATE_CONFIGURED:
	case ZONE_STATE_INCOMPLETE:
	case ZONE_STATE_SHUTTING_DOWN:
	default:
		/* cannot transition (boot) these states */
		return (B_FALSE);
	}
}

/*
 * Name:	_z_make_zone_ready
 * Description:	Given a zone element entry for the non-global zone to affect,
 *		restore the ready state of the zone when the zone is currently
 *		in the running state.
 * Arguments:	a_zlem - [RO, *RW] - (zoneListElement_t)
 *			Zone list element describing the non-global zone to
 *			make ready
 * Returns:	boolean_t
 *			B_TRUE - non-global zone state changed successfully
 *			B_FALSE - failed to make the non-global zone ready
 */

boolean_t
_z_make_zone_ready(zoneListElement_t *a_zlem)
{
	argArray_t	*args;
	char		*results = (char *)NULL;
	int		status = 0;
	int		i;
	int		ret;
	zone_state_t	st;

	/* entry assertions */

	assert(a_zlem != (zoneListElement_t *)NULL);

	/* act based on the zone's current kernel state */

	switch (a_zlem->_zlCurrKernelStatus) {
	case ZONE_STATE_DOWN:
	case ZONE_STATE_READY:
		/* already down */
		return (B_TRUE);

	case ZONE_STATE_MOUNTED:
		_z_echoDebug(DBG_TO_ZONEUNMOUNT, a_zlem->_zlName);

		args = _z_new_args(10);		/* generate new arg list */
		(void) _z_add_arg(args, ZONEADM_CMD);
		(void) _z_add_arg(args, "-z");
		(void) _z_add_arg(args, "%s", a_zlem->_zlName);
		(void) _z_add_arg(args, "unmount");
		ret = z_ExecCmdArray(&status, &results, NULL,
		    ZONEADM_CMD, _z_get_argv(args));
		if (ret != 0) {
			_z_program_error(ERR_ZONEUNMOUNT_EXEC,
			    ZONEADM_CMD, strerror(errno));
			free(results);
			_z_free_args(args);
			return (B_FALSE);
		}
		if (status != 0) {
			if (status == -1) {
				_z_program_error(ERR_ZONEUNMOUNT_CMD_SIGNAL,
				    ZONEADM_CMD, a_zlem->_zlName);
			} else {
				_z_program_error(ERR_ZONEUNMOUNT_CMD_ERROR,
				    ZONEADM_CMD, a_zlem->_zlName, status,
				    results == NULL ? "" : "\n",
				    results == NULL ? "" : results);
			}
			if (results != NULL) {
				free(results);
			}
			_z_free_args(args);
			return (B_FALSE);
		}
		if (results != NULL) {
			free(results);
		}
		_z_free_args(args);
		a_zlem->_zlCurrKernelStatus = ZONE_STATE_INSTALLED;
		_z_echoDebug(DBG_TO_ZONEREADY, a_zlem->_zlName);

		args = _z_new_args(10);		/* generate new arg list */
		(void) _z_add_arg(args, ZONEADM_CMD);
		(void) _z_add_arg(args, "-z");
		(void) _z_add_arg(args, "%s", a_zlem->_zlName);
		(void) _z_add_arg(args, "ready");

		ret = z_ExecCmdArray(&status, &results, NULL,
		    ZONEADM_CMD, _z_get_argv(args));
		if (ret != 0) {
			_z_program_error(ERR_ZONEREADY_EXEC, ZONEADM_CMD,
			    strerror(errno));
			free(results);
			_z_free_args(args);
			return (B_FALSE);
		}
		if (status != 0) {
			_z_program_error(ERR_ZONEREADY_CMDFAIL, ZONEADM_CMD,
			    a_zlem->_zlName, strerror(errno),
			    results == NULL ? "" : "\n",
			    results == NULL ? "" : results);
			if (results != NULL) {
				free(results);
			}
			_z_free_args(args);
			return (B_FALSE);
		}
		if (results != NULL) {
			free(results);
		}
		/* success - zone is now in the ready state */
		a_zlem->_zlCurrKernelStatus = ZONE_STATE_READY;
		return (B_TRUE);

	case ZONE_STATE_RUNNING:

		_z_echoDebug(DBG_TO_ZONEREADY, a_zlem->_zlName);

		args = _z_new_args(10);		/* generate new arg list */
		(void) _z_add_arg(args, ZONEADM_CMD);
		(void) _z_add_arg(args, "-z");
		(void) _z_add_arg(args, "%s", a_zlem->_zlName);
		(void) _z_add_arg(args, "ready");

		ret = z_ExecCmdArray(&status, &results, (char *)NULL,
		    ZONEADM_CMD, _z_get_argv(args));

		/* free generated argument list */

		_z_free_args(args);

		if (ret != 0) {
			_z_program_error(ERR_ZONEREADY_EXEC, ZONEADM_CMD,
			    strerror(errno));
			free(results);
			_z_free_args(args);
			return (B_FALSE);
		}
		if (status != 0) {
			_z_program_error(ERR_ZONEREADY_CMDFAIL, ZONEADM_CMD,
			    a_zlem->_zlName, strerror(errno),
			    results == (char *)NULL ? "" : "\n",
			    results == (char *)NULL ? "" : results);
			if (results != (char *)NULL) {
				(void) free(results);
			}
			return (B_FALSE);
		}

		if (results != (char *)NULL) {
			(void) free(results);
		}

		for (i = 0; i < MAX_RETRIES; i++) {
			if (zone_get_state(a_zlem->_zlName, &st) != Z_OK) {
				break;
			}
			if ((st == ZONE_STATE_DOWN) ||
			    (st == ZONE_STATE_INSTALLED)||
			    (st == ZONE_STATE_READY)) {
				break;
			}
			(void) sleep(RETRY_DELAY_SECS);
		}

		/* failure if maximum retries reached */

		if (i >= MAX_RETRIES) {
			_z_program_error(ERR_ZONEREADY_DIDNT_READY,
			    a_zlem->_zlName);
			a_zlem->_zlCurrKernelStatus = st;
			return (B_FALSE);
		}

		/* success - zone is now in the ready state  */

		a_zlem->_zlCurrKernelStatus = ZONE_STATE_READY;

		return (B_TRUE);

	case ZONE_STATE_INSTALLED:
	case ZONE_STATE_CONFIGURED:
	case ZONE_STATE_INCOMPLETE:
	case ZONE_STATE_SHUTTING_DOWN:
	default:
		return (B_FALSE);
	}
}

/*
 * Name:	_z_make_zone_down
 * Description:	Given a zone element entry for the non-global zone to affect,
 *		change the state of that non-global zone to "down"
 * Arguments:	a_zlem - [RO, *RW] - (zoneListElement_t)
 *			Zone list element describing the non-global zone to
 *			make down
 * Returns:	boolean_t
 *			B_TRUE - non-global zone state changed successfully
 *			B_FALSE - failed to make the non-global zone down
 */

boolean_t
_z_make_zone_down(zoneListElement_t *a_zlem)
{
	argArray_t	*args;
	char		*results = (char *)NULL;
	int		status = 0;
	int		ret;

	/* entry assertions */

	assert(a_zlem != NULL);

	/* act based on the zone's current kernel state */

	switch (a_zlem->_zlCurrKernelStatus) {
	case ZONE_STATE_DOWN:
	case ZONE_STATE_READY:
	case ZONE_STATE_RUNNING:
		/* shouldn't be touched */
		return (B_TRUE);

	case ZONE_STATE_MOUNTED:

		_z_echoDebug(DBG_TO_ZONEHALT, a_zlem->_zlName);

		/* these states can be halted - do so */

		args = _z_new_args(10);		/* generate new arg list */
		(void) _z_add_arg(args, ZONEADM_CMD);

		if (zonecfg_in_alt_root()) {
			(void) _z_add_arg(args, "-R");
			(void) _z_add_arg(args, "%s",
			    (char *)zonecfg_get_root());
		}

		(void) _z_add_arg(args, "-z");
		(void) _z_add_arg(args, "%s", a_zlem->_zlName);
		(void) _z_add_arg(args, "unmount");

		ret = z_ExecCmdArray(&status, &results, (char *)NULL,
		    ZONEADM_CMD, _z_get_argv(args));

		/* free generated argument list */

		_z_free_args(args);

		if (ret != 0) {
			_z_program_error(ERR_ZONEHALT_EXEC, ZONEADM_CMD,
			    strerror(errno));
			free(results);
			return (B_FALSE);
		}
		if (status != 0) {
			if (status == -1) {
				_z_program_error(ERR_ZONEBOOT_CMD_SIGNAL,
				    ZONEADM_CMD, a_zlem->_zlName);
			} else {
				_z_program_error(ERR_ZONEBOOT_CMD_ERROR,
				    ZONEADM_CMD, a_zlem->_zlName, status,
				    results == NULL ? "" : "\n",
				    results == NULL ? "" : results);
			}
			free(results);
			return (B_FALSE);
		}

		free(results);

		a_zlem->_zlCurrKernelStatus = ZONE_STATE_INSTALLED;
		/*
		 * Leave the scratch name in place because the upper level
		 * software may have used it to construct file names and the
		 * like.
		 */
		return (B_TRUE);

	case ZONE_STATE_INSTALLED:
	case ZONE_STATE_CONFIGURED:
	case ZONE_STATE_INCOMPLETE:
	case ZONE_STATE_SHUTTING_DOWN:
	default:
		return (B_FALSE);
	}
}

/*
 * Function:    UmountAllZones
 * Description: Unmount all mounted zones under a specified directory.
 *
 * Scope:   public
 * Parameters:  mntpnt  [RO, *RO]
 *          Non-NULL pointer to name of directory to be unmounted.
 * Return:   0  - successfull
 *      -1  - unmount failed; see errno for reason
 */
int
UmountAllZones(char *mntpnt) {

	zoneList_t  zlst;
	int	 k;
	int  ret = 0;

	if (z_zones_are_implemented()) {

		z_set_zone_root(mntpnt);

		zlst = z_get_nonglobal_zone_list();
		if (zlst == (zoneList_t)NULL) {
			return (0);
		}

		for (k = 0; z_zlist_get_zonename(zlst, k) != (char *)NULL;
		    k++) {
			if (z_zlist_get_current_state(zlst, k) >
			    ZONE_STATE_INSTALLED) {
				if (!z_zlist_change_zone_state(zlst, k,
				    ZONE_STATE_INSTALLED)) {
					ret = -1;
					break;
				}
			}
		}

		/* Free zlst */
		z_free_zone_list(zlst);
	}

	return (ret);

}