/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * 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); }