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