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 
103 boolean_t
_z_make_zone_running(zoneListElement_t * a_zlem)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 
273 boolean_t
_z_make_zone_ready(zoneListElement_t * a_zlem)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 
455 boolean_t
_z_make_zone_down(zoneListElement_t * a_zlem)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  */
551 int
UmountAllZones(char * mntpnt)552 UmountAllZones(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