zones_states.c revision 9781:ccf49524d5dc
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28/*
29 * Module:	zones_states.c
30 * Group:	libinstzones
31 * Description:	Provide "zones" state interfaces for install consolidation code
32 *
33 * Public Methods:
34 *
35 *  z_make_zone_running - change state of non-global zone to "running"
36 * _z_make_zone_ready - change state of non-global zone to "ready"
37 * _z_make_zone_down - change state of non-global zone to "down"
38 */
39
40/*
41 * System includes
42 */
43
44#include <stdio.h>
45#include <stdlib.h>
46#include <unistd.h>
47#include <fcntl.h>
48#include <ctype.h>
49#include <sys/types.h>
50#include <sys/param.h>
51#include <string.h>
52#include <strings.h>
53#include <sys/stat.h>
54#include <stdarg.h>
55#include <limits.h>
56#include <errno.h>
57#include <stropts.h>
58#include <libintl.h>
59#include <locale.h>
60#include <assert.h>
61
62/*
63 * local includes
64 */
65
66#include "instzones_lib.h"
67#include "zones_strings.h"
68
69/*
70 * Private structures
71 */
72
73/*
74 * Library Function Prototypes
75 */
76
77/*
78 * Local Function Prototypes
79 */
80
81/*
82 * global internal (private) declarations
83 */
84
85/*
86 * *****************************************************************************
87 * global external (public) functions
88 * *****************************************************************************
89 */
90
91/*
92 * Name:	_z_make_zone_running
93 * Description:	Given a zone element entry for the non-global zone to affect,
94 *		change the state of that non-global zone to "running"
95 * Arguments:	a_zlem - [RO, *RW] - (zoneListElement_t)
96 *			Zone list element describing the non-global zone to
97 *			make running
98 * Returns:	boolean_t
99 *			B_TRUE - non-global zone state changed successfully
100 *			B_FALSE - failed to make the non-global zone run
101 */
102
103boolean_t
104_z_make_zone_running(zoneListElement_t *a_zlem)
105{
106	FILE		*fp;
107	argArray_t	*args;
108	char		 zonename[ZONENAME_MAX];
109	char		*results = (char *)NULL;
110	int		ret;
111	int		status = 0;
112
113	/* entry assertions */
114
115	assert(a_zlem != NULL);
116
117	/* act based on the zone's current kernel state */
118
119	switch (a_zlem->_zlCurrKernelStatus) {
120	case ZONE_STATE_RUNNING:
121	case ZONE_STATE_MOUNTED:
122		/* already running */
123		return (B_TRUE);
124
125	case ZONE_STATE_READY:
126		/* This should never happen */
127		if (zonecfg_in_alt_root())
128			return (B_FALSE);
129
130		/*
131		 * We're going to upset the zone anyway, so might as well just
132		 * halt it now and fall through to normal mounting.
133		 */
134
135		_z_echoDebug(DBG_TO_ZONEHALT, a_zlem->_zlName);
136
137		args = _z_new_args(5);		/* generate new arg list */
138		(void) _z_add_arg(args, ZONEADM_CMD);
139		(void) _z_add_arg(args, "-z");
140		(void) _z_add_arg(args, a_zlem->_zlName);
141		(void) _z_add_arg(args, "halt");
142
143		ret = z_ExecCmdArray(&status, &results, (char *)NULL,
144		    ZONEADM_CMD, _z_get_argv(args));
145
146		/* free generated argument list */
147
148		_z_free_args(args);
149
150		if (ret != 0) {
151			_z_program_error(ERR_ZONEHALT_EXEC, ZONEADM_CMD,
152			    strerror(errno));
153			free(results);
154			return (B_FALSE);
155		}
156		if (status != 0) {
157			if (status == -1) {
158				_z_program_error(ERR_ZONEBOOT_CMD_SIGNAL,
159				    ZONEADM_CMD, a_zlem->_zlName);
160			} else {
161				_z_program_error(ERR_ZONEBOOT_CMD_ERROR,
162				    ZONEADM_CMD, a_zlem->_zlName, status,
163				    results == NULL ? "" : "\n",
164				    results == NULL ? "" : results);
165			}
166			free(results);
167			return (B_FALSE);
168		}
169
170		free(results);
171
172		a_zlem->_zlCurrKernelStatus = ZONE_STATE_INSTALLED;
173		/* FALLTHROUGH */
174
175	case ZONE_STATE_INSTALLED:
176	case ZONE_STATE_DOWN:
177		/* return false if the zone cannot be booted */
178
179		if (a_zlem->_zlStatus & ZST_NOT_BOOTABLE) {
180			return (B_FALSE);
181		}
182
183		_z_echoDebug(DBG_TO_ZONERUNNING, a_zlem->_zlName);
184
185		/* these states can be booted - do so */
186
187		args = _z_new_args(10);		/* generate new arg list */
188		(void) _z_add_arg(args, ZONEADM_CMD);
189		if (zonecfg_in_alt_root()) {
190			(void) _z_add_arg(args, "-R");
191			(void) _z_add_arg(args, "%s",
192			    (char *)zonecfg_get_root());
193		}
194
195		(void) _z_add_arg(args, "-z");
196		(void) _z_add_arg(args, "%s", a_zlem->_zlName);
197		(void) _z_add_arg(args, "mount");
198
199		ret = z_ExecCmdArray(&status, &results, (char *)NULL,
200		    ZONEADM_CMD, _z_get_argv(args));
201
202		/* free generated argument list */
203
204		_z_free_args(args);
205
206		if (ret != 0) {
207			_z_program_error(ERR_ZONEBOOT_EXEC, ZONEADM_CMD,
208			    strerror(errno));
209			free(results);
210			return (B_FALSE);
211		}
212
213		if (status != 0) {
214			if (status == -1) {
215				_z_program_error(ERR_ZONEBOOT_CMD_SIGNAL,
216				    ZONEADM_CMD, a_zlem->_zlName);
217			} else {
218				_z_program_error(ERR_ZONEBOOT_CMD_ERROR,
219				    ZONEADM_CMD, a_zlem->_zlName, status,
220				    results == NULL ? "" : "\n",
221				    results == NULL ? "" : results);
222			}
223			free(results);
224
225			/* remember this zone cannot be booted */
226
227			a_zlem->_zlStatus |= ZST_NOT_BOOTABLE;
228
229			return (B_FALSE);
230		}
231		free(results);
232
233		if (zonecfg_in_alt_root()) {
234			if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL ||
235			    zonecfg_find_scratch(fp, a_zlem->_zlName,
236			    zonecfg_get_root(), zonename,
237			    sizeof (zonename)) == -1) {
238				_z_program_error(ERR_ZONEBOOT_DIDNT_BOOT,
239				    a_zlem->_zlName);
240				if (fp != NULL)
241					zonecfg_close_scratch(fp);
242				return (B_FALSE);
243			}
244			zonecfg_close_scratch(fp);
245			free(a_zlem->_zlScratchName);
246			a_zlem->_zlScratchName = _z_strdup(zonename);
247		}
248		a_zlem->_zlCurrKernelStatus = ZONE_STATE_MOUNTED;
249		return (B_TRUE);
250
251	case ZONE_STATE_CONFIGURED:
252	case ZONE_STATE_INCOMPLETE:
253	case ZONE_STATE_SHUTTING_DOWN:
254	default:
255		/* cannot transition (boot) these states */
256		return (B_FALSE);
257	}
258}
259
260/*
261 * Name:	_z_make_zone_ready
262 * Description:	Given a zone element entry for the non-global zone to affect,
263 *		restore the ready state of the zone when the zone is currently
264 *		in the running state.
265 * Arguments:	a_zlem - [RO, *RW] - (zoneListElement_t)
266 *			Zone list element describing the non-global zone to
267 *			make ready
268 * Returns:	boolean_t
269 *			B_TRUE - non-global zone state changed successfully
270 *			B_FALSE - failed to make the non-global zone ready
271 */
272
273boolean_t
274_z_make_zone_ready(zoneListElement_t *a_zlem)
275{
276	argArray_t	*args;
277	char		*results = (char *)NULL;
278	int		status = 0;
279	int		i;
280	int		ret;
281	zone_state_t	st;
282
283	/* entry assertions */
284
285	assert(a_zlem != (zoneListElement_t *)NULL);
286
287	/* act based on the zone's current kernel state */
288
289	switch (a_zlem->_zlCurrKernelStatus) {
290	case ZONE_STATE_DOWN:
291	case ZONE_STATE_READY:
292		/* already down */
293		return (B_TRUE);
294
295	case ZONE_STATE_MOUNTED:
296		_z_echoDebug(DBG_TO_ZONEUNMOUNT, a_zlem->_zlName);
297
298		args = _z_new_args(10);		/* generate new arg list */
299		(void) _z_add_arg(args, ZONEADM_CMD);
300		(void) _z_add_arg(args, "-z");
301		(void) _z_add_arg(args, "%s", a_zlem->_zlName);
302		(void) _z_add_arg(args, "unmount");
303		ret = z_ExecCmdArray(&status, &results, NULL,
304		    ZONEADM_CMD, _z_get_argv(args));
305		if (ret != 0) {
306			_z_program_error(ERR_ZONEUNMOUNT_EXEC,
307			    ZONEADM_CMD, strerror(errno));
308			free(results);
309			_z_free_args(args);
310			return (B_FALSE);
311		}
312		if (status != 0) {
313			if (status == -1) {
314				_z_program_error(ERR_ZONEUNMOUNT_CMD_SIGNAL,
315				    ZONEADM_CMD, a_zlem->_zlName);
316			} else {
317				_z_program_error(ERR_ZONEUNMOUNT_CMD_ERROR,
318				    ZONEADM_CMD, a_zlem->_zlName, status,
319				    results == NULL ? "" : "\n",
320				    results == NULL ? "" : results);
321			}
322			if (results != NULL) {
323				free(results);
324			}
325			_z_free_args(args);
326			return (B_FALSE);
327		}
328		if (results != NULL) {
329			free(results);
330		}
331		_z_free_args(args);
332		a_zlem->_zlCurrKernelStatus = ZONE_STATE_INSTALLED;
333		_z_echoDebug(DBG_TO_ZONEREADY, a_zlem->_zlName);
334
335		args = _z_new_args(10);		/* generate new arg list */
336		(void) _z_add_arg(args, ZONEADM_CMD);
337		(void) _z_add_arg(args, "-z");
338		(void) _z_add_arg(args, "%s", a_zlem->_zlName);
339		(void) _z_add_arg(args, "ready");
340
341		ret = z_ExecCmdArray(&status, &results, NULL,
342		    ZONEADM_CMD, _z_get_argv(args));
343		if (ret != 0) {
344			_z_program_error(ERR_ZONEREADY_EXEC, ZONEADM_CMD,
345			    strerror(errno));
346			free(results);
347			_z_free_args(args);
348			return (B_FALSE);
349		}
350		if (status != 0) {
351			_z_program_error(ERR_ZONEREADY_CMDFAIL, ZONEADM_CMD,
352			    a_zlem->_zlName, strerror(errno),
353			    results == NULL ? "" : "\n",
354			    results == NULL ? "" : results);
355			if (results != NULL) {
356				free(results);
357			}
358			_z_free_args(args);
359			return (B_FALSE);
360		}
361		if (results != NULL) {
362			free(results);
363		}
364		/* success - zone is now in the ready state */
365		a_zlem->_zlCurrKernelStatus = ZONE_STATE_READY;
366		return (B_TRUE);
367
368	case ZONE_STATE_RUNNING:
369
370		_z_echoDebug(DBG_TO_ZONEREADY, a_zlem->_zlName);
371
372		args = _z_new_args(10);		/* generate new arg list */
373		(void) _z_add_arg(args, ZONEADM_CMD);
374		(void) _z_add_arg(args, "-z");
375		(void) _z_add_arg(args, "%s", a_zlem->_zlName);
376		(void) _z_add_arg(args, "ready");
377
378		ret = z_ExecCmdArray(&status, &results, (char *)NULL,
379		    ZONEADM_CMD, _z_get_argv(args));
380
381		/* free generated argument list */
382
383		_z_free_args(args);
384
385		if (ret != 0) {
386			_z_program_error(ERR_ZONEREADY_EXEC, ZONEADM_CMD,
387			    strerror(errno));
388			free(results);
389			_z_free_args(args);
390			return (B_FALSE);
391		}
392		if (status != 0) {
393			_z_program_error(ERR_ZONEREADY_CMDFAIL, ZONEADM_CMD,
394			    a_zlem->_zlName, strerror(errno),
395			    results == (char *)NULL ? "" : "\n",
396			    results == (char *)NULL ? "" : results);
397			if (results != (char *)NULL) {
398				(void) free(results);
399			}
400			return (B_FALSE);
401		}
402
403		if (results != (char *)NULL) {
404			(void) free(results);
405		}
406
407		for (i = 0; i < MAX_RETRIES; i++) {
408			if (zone_get_state(a_zlem->_zlName, &st) != Z_OK) {
409				break;
410			}
411			if ((st == ZONE_STATE_DOWN) ||
412			    (st == ZONE_STATE_INSTALLED)||
413			    (st == ZONE_STATE_READY)) {
414				break;
415			}
416			(void) sleep(RETRY_DELAY_SECS);
417		}
418
419		/* failure if maximum retries reached */
420
421		if (i >= MAX_RETRIES) {
422			_z_program_error(ERR_ZONEREADY_DIDNT_READY,
423			    a_zlem->_zlName);
424			a_zlem->_zlCurrKernelStatus = st;
425			return (B_FALSE);
426		}
427
428		/* success - zone is now in the ready state  */
429
430		a_zlem->_zlCurrKernelStatus = ZONE_STATE_READY;
431
432		return (B_TRUE);
433
434	case ZONE_STATE_INSTALLED:
435	case ZONE_STATE_CONFIGURED:
436	case ZONE_STATE_INCOMPLETE:
437	case ZONE_STATE_SHUTTING_DOWN:
438	default:
439		return (B_FALSE);
440	}
441}
442
443/*
444 * Name:	_z_make_zone_down
445 * Description:	Given a zone element entry for the non-global zone to affect,
446 *		change the state of that non-global zone to "down"
447 * Arguments:	a_zlem - [RO, *RW] - (zoneListElement_t)
448 *			Zone list element describing the non-global zone to
449 *			make down
450 * Returns:	boolean_t
451 *			B_TRUE - non-global zone state changed successfully
452 *			B_FALSE - failed to make the non-global zone down
453 */
454
455boolean_t
456_z_make_zone_down(zoneListElement_t *a_zlem)
457{
458	argArray_t	*args;
459	char		*results = (char *)NULL;
460	int		status = 0;
461	int		ret;
462
463	/* entry assertions */
464
465	assert(a_zlem != NULL);
466
467	/* act based on the zone's current kernel state */
468
469	switch (a_zlem->_zlCurrKernelStatus) {
470	case ZONE_STATE_DOWN:
471	case ZONE_STATE_READY:
472	case ZONE_STATE_RUNNING:
473		/* shouldn't be touched */
474		return (B_TRUE);
475
476	case ZONE_STATE_MOUNTED:
477
478		_z_echoDebug(DBG_TO_ZONEHALT, a_zlem->_zlName);
479
480		/* these states can be halted - do so */
481
482		args = _z_new_args(10);		/* generate new arg list */
483		(void) _z_add_arg(args, ZONEADM_CMD);
484
485		if (zonecfg_in_alt_root()) {
486			(void) _z_add_arg(args, "-R");
487			(void) _z_add_arg(args, "%s",
488			    (char *)zonecfg_get_root());
489		}
490
491		(void) _z_add_arg(args, "-z");
492		(void) _z_add_arg(args, "%s", a_zlem->_zlName);
493		(void) _z_add_arg(args, "unmount");
494
495		ret = z_ExecCmdArray(&status, &results, (char *)NULL,
496		    ZONEADM_CMD, _z_get_argv(args));
497
498		/* free generated argument list */
499
500		_z_free_args(args);
501
502		if (ret != 0) {
503			_z_program_error(ERR_ZONEHALT_EXEC, ZONEADM_CMD,
504			    strerror(errno));
505			free(results);
506			return (B_FALSE);
507		}
508		if (status != 0) {
509			if (status == -1) {
510				_z_program_error(ERR_ZONEBOOT_CMD_SIGNAL,
511				    ZONEADM_CMD, a_zlem->_zlName);
512			} else {
513				_z_program_error(ERR_ZONEBOOT_CMD_ERROR,
514				    ZONEADM_CMD, a_zlem->_zlName, status,
515				    results == NULL ? "" : "\n",
516				    results == NULL ? "" : results);
517			}
518			free(results);
519			return (B_FALSE);
520		}
521
522		free(results);
523
524		a_zlem->_zlCurrKernelStatus = ZONE_STATE_INSTALLED;
525		/*
526		 * Leave the scratch name in place because the upper level
527		 * software may have used it to construct file names and the
528		 * like.
529		 */
530		return (B_TRUE);
531
532	case ZONE_STATE_INSTALLED:
533	case ZONE_STATE_CONFIGURED:
534	case ZONE_STATE_INCOMPLETE:
535	case ZONE_STATE_SHUTTING_DOWN:
536	default:
537		return (B_FALSE);
538	}
539}
540
541/*
542 * Function:    UmountAllZones
543 * Description: Unmount all mounted zones under a specified directory.
544 *
545 * Scope:   public
546 * Parameters:  mntpnt  [RO, *RO]
547 *          Non-NULL pointer to name of directory to be unmounted.
548 * Return:   0  - successfull
549 *      -1  - unmount failed; see errno for reason
550 */
551int
552UmountAllZones(char *mntpnt) {
553
554	zoneList_t  zlst;
555	int	 k;
556	int  ret = 0;
557
558	if (z_zones_are_implemented()) {
559
560		z_set_zone_root(mntpnt);
561
562		zlst = z_get_nonglobal_zone_list();
563		if (zlst == (zoneList_t)NULL) {
564			return (0);
565		}
566
567		for (k = 0; z_zlist_get_zonename(zlst, k) != (char *)NULL;
568		    k++) {
569			if (z_zlist_get_current_state(zlst, k) >
570			    ZONE_STATE_INSTALLED) {
571				if (!z_zlist_change_zone_state(zlst, k,
572				    ZONE_STATE_INSTALLED)) {
573					ret = -1;
574					break;
575				}
576			}
577		}
578
579		/* Free zlst */
580		z_free_zone_list(zlst);
581	}
582
583	return (ret);
584
585}
586