xref: /titanic_44/usr/src/lib/libinstzones/common/zones.c (revision cd3e933325e68e23516a196a8fea7f49b1e497c3)
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.c
30  * Group:	libinstzones
31  * Description:	Provide "zones" interface for install consolidation code
32  *
33  * Public Methods:
34  *  z_create_zone_admin_file - Given a location to create the file, and
35  *	optionally an existing administration file, generate an
36  *	administration file that can be used to perform "non-interactive"
37  *	operations in a non-global zone.
38  *  z_free_zone_list - free contents of zoneList_t object
39  *  z_get_nonglobal_zone_list - return zoneList_t object describing all
40  *	non-global native zones
41  *  z_get_nonglobal_zone_list_by_brand - return zoneList_t object describing
42  *      all non-global zones matching the list of zone brands passed in.
43  *  z_free_brand_list - free contents of a zoneBrandList_t object
44  *  z_make_brand_list - return a zoneBrandList_t object describing the list
45  *	of all zone brands passed in.
46  *  z_get_zonename - return the name of the current zone
47  *  z_global_only - Determine if the global zone is only zone on the spec list
48  *  z_lock_this_zone - lock this zone
49  *  z_lock_zones - lock specified zones
50  *  z_mount_in_lz - Mount global zone directory in specified zone's root file
51  *	system
52  *  z_non_global_zones_exist - Determine if any non-global native zones exist
53  *  z_on_zone_spec - Determine if named zone is on the zone_spec list
54  *  z_running_in_global_zone - Determine if running in the "global" zone
55  *  z_set_output_functions - Link program specific output functions
56  *  z_set_zone_root - Set root for zones library operations
57  *  z_set_zone_spec - Set list of zones on which actions will be performed
58  *  z_umount_lz_mount - Unmount directory mounted with z_mount_in_lz
59  *  z_unlock_this_zone - unlock this zone
60  *  z_unlock_zones - unlock specified zones
61  *  z_verify_zone_spec - Verify list of zones on which actions will be performed
62  *  z_zlist_change_zone_state - Change the current state of the specified zone
63  *  z_zlist_get_current_state - Determine the current kernel state of the
64  *	specified zone
65  *  z_zlist_get_inherited_pkg_dirs - Determine directories inherited by
66  *	specified zone
67  *  z_zlist_get_original_state - Return the original kernal state of the
68  *	specified zone
69  *  z_zlist_get_scratch - Determine name of scratch zone
70  *  z_zlist_get_zonename - Determine name of specified zone
71  *  z_zlist_get_zonepath - Determine zonepath of specified zone
72  *  z_zlist_restore_zone_state - Return the zone to the state it was originally
73  *	in
74  *  z_zone_exec - Execute a Unix command in a specified zone and return results
75  *  z_zones_are_implemented - Determine if any zone operations can be performed
76  *  z_is_zone_branded - determine if zone has a non-native brand
77  *  z_is_zone_brand_in_list - determine if the zone's brand matches the
78  *      brand list passed in.
79  *  z_brands_are_implemented - determine if branded zones are implemented on
80  *			this system
81  */
82 
83 /*
84  * System includes
85  */
86 
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <unistd.h>
90 #include <fcntl.h>
91 #include <ctype.h>
92 #include <sys/types.h>
93 #include <sys/param.h>
94 #include <sys/sysmacros.h>
95 #include <string.h>
96 #include <strings.h>
97 #include <sys/stat.h>
98 #include <stdarg.h>
99 #include <limits.h>
100 #include <errno.h>
101 #include <time.h>
102 #include <signal.h>
103 #include <stropts.h>
104 #include <wait.h>
105 #include <zone.h>
106 #include <sys/brand.h>
107 #include <libintl.h>
108 #include <locale.h>
109 #include <libzonecfg.h>
110 #include <libcontract.h>
111 #include <sys/contract/process.h>
112 #include <sys/ctfs.h>
113 #include <assert.h>
114 #include <dlfcn.h>
115 #include <link.h>
116 #include <time.h>
117 
118 /*
119  * local includes
120  */
121 
122 /*
123  * When _INSTZONES_LIB_Z_DEFINE_GLOBAL_DATA is defined,
124  * instzones_lib.h will define the z_global_data structure.
125  * Otherwise an extern to the structure is inserted.
126  */
127 
128 #define	_INSTZONES_LIB_Z_DEFINE_GLOBAL_DATA
129 #include "instzones_lib.h"
130 #include "zones_strings.h"
131 
132 /*
133  * Private structures
134  */
135 
136 #define	CLUSTER_BRAND_NAME	"cluster"
137 
138 /* maximum number of arguments to exec() call */
139 
140 #define	UUID_FORMAT	"%02d%02d%02d%03d-%02d%02d%02d%d-%016llx"
141 
142 /*
143  * Library Function Prototypes
144  */
145 
146 #define	streq(a, b) (strcmp((a), (b)) == 0)
147 
148 /*
149  * Local Function Prototypes
150  */
151 
152 /*
153  * global internal (private) declarations
154  */
155 
156 /*
157  * *****************************************************************************
158  * global external (public) functions
159  * *****************************************************************************
160  */
161 
162 /*
163  * Name:	z_create_zone_admin_file
164  * Description:	Given a location to create the file, and optionally an existing
165  *		administration file, generate an administration file that
166  *		can be used to perform "non-interactive" operations in a
167  *		non-global zone.
168  * Arguments:	a_zoneAdminFilename - pointer to string representing the
169  *			full path of zone admin file to create
170  *		a_userAdminFilename - pointer to string representing the path
171  *			to an existing "user" administration file - the
172  *			administration file created will contain the
173  *			settings contained in this file, modified as
174  *			appropriate to supress any interaction;
175  *			If this is == NULL then the administration file
176  *			created will not contain any extra settings
177  * Returns:	boolean_t
178  *			== B_TRUE - admin file created
179  *			== B_FALSE - failed to create admin file
180  */
181 
182 boolean_t
183 z_create_zone_admin_file(char *a_zoneAdminFilename, char *a_userAdminFilename)
184 {
185 	FILE	*zFp;
186 	FILE	*uFp = (FILE *)NULL;
187 
188 	/* entry assertions */
189 
190 	assert(a_zoneAdminFilename != NULL);
191 	assert(*a_zoneAdminFilename != '\0');
192 
193 	/* create temporary zone admin file */
194 
195 	zFp = fopen(a_zoneAdminFilename, "w");
196 	if (zFp == (FILE *)NULL) {
197 		return (B_FALSE);
198 	}
199 
200 	/* open user admin file if specified */
201 
202 	if (a_userAdminFilename != (char *)NULL) {
203 		uFp = fopen(a_userAdminFilename, "r");
204 	}
205 
206 	/* create default admin file for zone pkg ops if no user admin file */
207 
208 	if (uFp == (FILE *)NULL) {
209 		/* create default admin file */
210 		(void) fprintf(zFp, "action=nocheck\nauthentication=nocheck\n"
211 		    "basedir=default\nconflict=nocheck\nidepend=nocheck\n"
212 		    "instance=unique\npartial=nocheck\nrdepend=nocheck\n"
213 		    "runlevel=nocheck\nsetuid=nocheck\nspace=nocheck\n"
214 		    "mail=\n");
215 	} else for (;;) {
216 		/* copy user admin file substitute/change appropriate entries */
217 		char	buf[LINE_MAX+1];
218 		char	*p;
219 
220 		/* read next line of user admin file */
221 
222 		p = fgets(buf, sizeof (buf), uFp);
223 		if (p == (char *)NULL) {
224 			(void) fclose(uFp);
225 			break;
226 		}
227 
228 		/* modify / replace / accept as appropriate */
229 
230 		if (strncmp(buf, "instance=quit", 13) == 0) {
231 			(void) fprintf(zFp, "%s", "instance=unique\n");
232 			/*LINTED*/
233 		} else if (strncmp(buf, "keystore=", 9) == 0) {
234 		} else if (strncmp(buf, "action=", 7) == 0) {
235 			(void) fprintf(zFp, "action=nocheck\n");
236 		} else if (strncmp(buf, "authentication=", 15) == 0) {
237 			(void) fprintf(zFp, "authentication=nocheck\n");
238 		} else if (strncmp(buf, "conflict=", 9) == 0) {
239 			(void) fprintf(zFp, "conflict=nocheck\n");
240 		} else if (strncmp(buf, "idepend=", 8) == 0) {
241 			(void) fprintf(zFp, "idepend=nocheck\n");
242 		} else if (strncmp(buf, "mail=", 5) == 0) {
243 			(void) fprintf(zFp, "mail=\n");
244 		} else if (strncmp(buf, "partial=", 8) == 0) {
245 			(void) fprintf(zFp, "partial=nocheck\n");
246 		} else if (strncmp(buf, "rdepend=", 8) == 0) {
247 			(void) fprintf(zFp, "rdepend=nocheck\n");
248 		} else if (strncmp(buf, "runlevel=", 9) == 0) {
249 			(void) fprintf(zFp, "runlevel=nocheck\n");
250 		} else if (strncmp(buf, "setuid=", 7) == 0) {
251 			(void) fprintf(zFp, "setuid=nocheck\n");
252 		} else if (strncmp(buf, "space=", 6) == 0) {
253 			(void) fprintf(zFp, "space=nocheck\n");
254 		} else {
255 			(void) fprintf(zFp, "%s", buf);
256 		}
257 	}
258 
259 	/* close admin file and return success */
260 
261 	(void) fclose(zFp);
262 	return (B_TRUE);
263 }
264 
265 /*
266  * Name:	z_brands_are_implemented
267  * Description:	Determine if any branded zones may be present
268  * Arguments:	void
269  * Returns:	boolean_t
270  *			== B_TRUE - branded zones are supported
271  *			== B_FALSE - branded zones are not supported
272  */
273 
274 boolean_t
275 z_brands_are_implemented(void)
276 {
277 static	boolean_t	_brandsImplementedDetermined = B_FALSE;
278 static	boolean_t	_brandsAreImplemented = B_FALSE;
279 
280 	/* if availability has not been determined, cache it now */
281 
282 	if (!_brandsImplementedDetermined) {
283 		_brandsImplementedDetermined = B_TRUE;
284 		_brandsAreImplemented = _z_brands_are_implemented();
285 		if (_brandsAreImplemented) {
286 			_z_echoDebug(DBG_BRANDS_ARE_IMPLEMENTED);
287 		} else {
288 			_z_echoDebug(DBG_BRANDS_NOT_IMPLEMENTED);
289 		}
290 	}
291 
292 	/* return cached answer */
293 
294 	return (_brandsAreImplemented);
295 }
296 
297 /*
298  * Name:	z_free_zone_list
299  * Description:	free contents of zoneList_t object
300  * Arguments:	a_zlst - handle to zoneList_t object to free
301  * Returns:	void
302  */
303 
304 void
305 z_free_zone_list(zoneList_t a_zlst)
306 {
307 	int	numzones;
308 
309 	/* ignore empty list */
310 
311 	if (a_zlst == (zoneList_t)NULL) {
312 		return;
313 	}
314 
315 	/* free each entry in the zone list */
316 
317 	for (numzones = 0; a_zlst[numzones]._zlName != (char *)NULL;
318 	    numzones++) {
319 		zoneListElement_t *zelm = &a_zlst[numzones];
320 
321 		/* free zone name string */
322 
323 		free(zelm->_zlName);
324 
325 		/* free zonepath string */
326 
327 		if (zelm->_zlPath != (char *)NULL) {
328 			free(zelm->_zlPath);
329 		}
330 
331 		/* free list of inherited package directories */
332 
333 		if (zelm->_zlInheritedDirs != (char **)NULL) {
334 			int	n;
335 
336 			for (n = 0;
337 			    (zelm->_zlInheritedDirs)[n] != (char *)NULL;
338 			    n++) {
339 				(void) free((zelm->_zlInheritedDirs)[n]);
340 			}
341 			(void) free(zelm->_zlInheritedDirs);
342 		}
343 	}
344 
345 	/* free handle to the list */
346 
347 	free(a_zlst);
348 }
349 
350 /*
351  * Name:	z_get_nonglobal_zone_list
352  * Description: return zoneList_t object describing all non-global
353  *              native zones - branded zones are not included in list
354  * Arguments:	None.
355  * Returns:	zoneList_t
356  *			== NULL - error, list could not be generated
357  *			!= NULL - success, list returned
358  * NOTE:    	Any zoneList_t returned is placed in new storage for the
359  *		calling function. The caller must use 'z_free_zone_list' to
360  *		dispose of the storage once the list is no longer needed.
361  */
362 
363 zoneList_t
364 z_get_nonglobal_zone_list(void)
365 {
366 	zoneList_t zones;
367 	zoneBrandList_t *brands = NULL;
368 
369 	if ((brands = z_make_brand_list("native cluster", " ")) == NULL)
370 		return (NULL);
371 
372 	zones = z_get_nonglobal_zone_list_by_brand(brands);
373 
374 	z_free_brand_list(brands);
375 
376 	return (zones);
377 }
378 
379 /*
380  * Name:	z_free_brand_list
381  * Description: Free contents of zoneBrandList_t object
382  * Arguments:	brands - pointer to zoneBrandList_t object to free
383  * Returns: 	void
384  */
385 void
386 z_free_brand_list(zoneBrandList_t *brands)
387 {
388 	while (brands != NULL) {
389 		zoneBrandList_t *temp = brands;
390 		free(brands->string_ptr);
391 		brands = brands->next;
392 		free(temp);
393 	}
394 }
395 
396 /*
397  * Name:	z_make_brand_list
398  * Description:	Given a string with a list of brand name delimited by
399  *		the delimeter passed in, build a zoneBrandList_t structure
400  *		with the list of brand names and return it to the caller.
401  * Arguments:
402  *		brands - const char pointer to string list of brand names
403  *		delim - const char pointer to string representing the
404  *			delimeter for brands string.
405  * Returns:	zoneBrandList_t *
406  *			== NULL - error, list could not be generated
407  *			!= NULL - success, list returned
408  * NOTE:	Any zoneBrandList_t returned is placed in new storage for the
409  *		calling function.  The caller must use 'z_free_brand_list' to
410  *		dispose of the storage once the list is no longer needed.
411  */
412 zoneBrandList_t *
413 z_make_brand_list(const char *brands, const char *delim)
414 {
415 	zoneBrandList_t *brand = NULL, *head = NULL;
416 	char		*blist = NULL;
417 	char		*str = NULL;
418 
419 	if ((blist = strdup(brands)) == NULL)
420 		return (NULL);
421 
422 	if ((str = strtok(blist, delim)) != NULL) {
423 		if ((brand = (zoneBrandList_t *)
424 		    malloc(sizeof (struct _zoneBrandList))) == NULL) {
425 			return (NULL);
426 		}
427 
428 		head = brand;
429 		brand->string_ptr = strdup(str);
430 		brand->next = NULL;
431 
432 		while ((str = strtok(NULL, delim)) != NULL) {
433 			if ((brand->next = (zoneBrandList_t *)
434 			    malloc(sizeof (struct _zoneBrandList))) == NULL) {
435 				return (NULL);
436 			}
437 
438 			brand = brand->next;
439 			brand->string_ptr = strdup(str);
440 			brand->next = NULL;
441 		}
442 	}
443 
444 	free(blist);
445 	return (head);
446 }
447 
448 /*
449  * Name:	z_get_nonglobal_zone_list_by_brand
450  * Description: return zoneList_t object describing all non-global
451  *              zones matching the list of brands passed in.
452  * Arguments:	brands - The list of zone brands to look for.
453  * Returns:	zoneList_t
454  *			== NULL - error, list could not be generated
455  *			!= NULL - success, list returned
456  * NOTE:    	Any zoneList_t returned is placed in new storage for the
457  *		calling function. The caller must use 'z_free_zone_list' to
458  *		dispose of the storage once the list is no longer needed.
459  */
460 zoneList_t
461 z_get_nonglobal_zone_list_by_brand(zoneBrandList_t *brands)
462 {
463 	FILE		*zoneIndexFP;
464 	int		numzones = 0;
465 	struct zoneent	*ze;
466 	zoneList_t	zlst = NULL;
467 	FILE		*mapFP;
468 	char		zonename[ZONENAME_MAX];
469 	zone_spec_t	*zent;
470 
471 	/* if zones are not implemented, return empty list */
472 
473 	if (!z_zones_are_implemented()) {
474 		return ((zoneList_t)NULL);
475 	}
476 
477 	/*
478 	 * Open the zone index file.  Note that getzoneent_private() handles
479 	 * NULL.
480 	 */
481 	zoneIndexFP = setzoneent();
482 
483 	mapFP = zonecfg_open_scratch("", B_FALSE);
484 
485 	/* index file open; scan all zones; see if any are at least installed */
486 
487 	while ((ze = getzoneent_private(zoneIndexFP)) != NULL) {
488 		zone_state_t	st;
489 
490 		/* skip the global zone */
491 
492 		if (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0) {
493 			free(ze);
494 			continue;
495 		}
496 
497 		/*
498 		 * skip any zones with brands not on the brand list
499 		 */
500 		if (!z_is_zone_brand_in_list(ze->zone_name, brands)) {
501 			free(ze);
502 			continue;
503 		}
504 
505 		/*
506 		 * If the user specified an explicit zone list, then ignore any
507 		 * zones that aren't on that list.
508 		 */
509 		if ((zent = _z_global_data._zone_spec) != NULL) {
510 			while (zent != NULL) {
511 				if (strcmp(zent->zl_name, ze->zone_name) == 0)
512 					break;
513 				zent = zent->zl_next;
514 			}
515 			if (zent == NULL) {
516 				free(ze);
517 				continue;
518 			}
519 		}
520 
521 		/* non-global zone: create entry for this zone */
522 
523 		if (numzones == 0) {
524 			zlst = (zoneList_t)_z_calloc(
525 			    sizeof (zoneListElement_t)*2);
526 		} else {
527 			zlst = (zoneList_t)_z_realloc(zlst,
528 			    sizeof (zoneListElement_t)*(numzones+2));
529 			(void) memset(&zlst[numzones], 0L,
530 			    sizeof (zoneListElement_t)*2);
531 		}
532 
533 		/*
534 		 * remember the zone name, zonepath and the current
535 		 * zone state of the zone.
536 		 */
537 		zlst[numzones]._zlName = _z_strdup(ze->zone_name);
538 		zlst[numzones]._zlPath = _z_strdup(ze->zone_path);
539 		zlst[numzones]._zlOrigInstallState = ze->zone_state;
540 		zlst[numzones]._zlCurrInstallState = ze->zone_state;
541 
542 		/* get the zone kernel status */
543 
544 		if (zone_get_state(ze->zone_name, &st) != Z_OK) {
545 			st = ZONE_STATE_INCOMPLETE;
546 		}
547 
548 		_z_echoDebug(DBG_ZONES_NGZ_LIST_STATES,
549 		    ze->zone_name, ze->zone_state, st);
550 
551 		/*
552 		 * For a scratch zone, we need to know the kernel zone name.
553 		 */
554 		if (zonecfg_in_alt_root() && mapFP != NULL &&
555 		    zonecfg_find_scratch(mapFP, ze->zone_name,
556 		    zonecfg_get_root(), zonename, sizeof (zonename)) != -1) {
557 			free(zlst[numzones]._zlScratchName);
558 			zlst[numzones]._zlScratchName = _z_strdup(zonename);
559 		}
560 
561 		/*
562 		 * remember the current kernel status of the zone.
563 		 */
564 
565 		zlst[numzones]._zlOrigKernelStatus = st;
566 		zlst[numzones]._zlCurrKernelStatus = st;
567 
568 		zlst[numzones]._zlInheritedDirs =
569 		    _z_get_inherited_dirs(ze->zone_name);
570 
571 		numzones++;
572 		free(ze);
573 	}
574 
575 	/* close the index file */
576 	endzoneent(zoneIndexFP);
577 
578 	if (mapFP != NULL)
579 		zonecfg_close_scratch(mapFP);
580 
581 	/* return generated list */
582 
583 	return (zlst);
584 }
585 
586 /*
587  * Name:	z_get_zonename
588  * Description:	return the name of the current zone
589  * Arguments:	void
590  * Returns:	char *
591  *			- pointer to string representing the name of the current
592  *			zone
593  * NOTE:    	Any string returned is placed in new storage for the
594  *		calling function. The caller must use 'Free' to dispose
595  *		of the storage once the string is no longer needed.
596  */
597 
598 char *
599 z_get_zonename(void)
600 {
601 	ssize_t		zonenameLen;
602 	char		zonename[ZONENAME_MAX];
603 	zoneid_t	zoneid = (zoneid_t)-1;
604 
605 	/* if zones are not implemented, return "" */
606 
607 	if (!z_zones_are_implemented()) {
608 		return (_z_strdup(""));
609 	}
610 
611 	/* get the zone i.d. of the current zone */
612 
613 	zoneid = getzoneid();
614 
615 	/* get the name of the current zone */
616 
617 	zonenameLen = getzonenamebyid(zoneid, zonename, sizeof (zonename));
618 
619 	/* return "" if could not get zonename */
620 
621 	if (zonenameLen < 1) {
622 		return (_z_strdup(""));
623 	}
624 
625 	return (_z_strdup(zonename));
626 }
627 
628 /*
629  * Name:	z_global_only
630  * Description:	Determine if the global zone is only zone on the spec list.
631  * Arguments:	None
632  * Returns:	B_TRUE if global zone is the only zone on the list,
633  *		B_FALSE otherwise.
634  */
635 
636 boolean_t
637 z_global_only(void)
638 {
639 	/* return true if zones are not implemented - treate as global zone */
640 
641 	if (!z_zones_are_implemented()) {
642 		return (B_TRUE);
643 	}
644 
645 	/* return true if this is the global zone */
646 
647 	if (_z_global_data._zone_spec != NULL &&
648 	    _z_global_data._zone_spec->zl_next == NULL &&
649 	    strcmp(_z_global_data._zone_spec->zl_name, GLOBAL_ZONENAME) == 0) {
650 		return (B_TRUE);
651 	}
652 
653 	/* return false - not the global zone */
654 
655 	return (B_FALSE);
656 }
657 
658 /*
659  * Name:	z_lock_this_zone
660  * Description:	lock this zone
661  * Arguments:	a_lflags - [RO, *RO] - (ZLOCKS_T)
662  *			Flags indicating which locks to acquire
663  * Returns:	boolean_t
664  *			== B_TRUE - success specified locks acquired
665  *			== B_FALSE - failure specified locks not acquired
666  * NOTE: the lock objects for "this zone" are maintained internally.
667  */
668 
669 boolean_t
670 z_lock_this_zone(ZLOCKS_T a_lflags)
671 {
672 	boolean_t	b;
673 	char		*zoneName;
674 	pid_t		pid = (pid_t)0;
675 
676 	/* entry assertions */
677 
678 	assert(a_lflags != ZLOCKS_NONE);
679 
680 	/* entry debugging info */
681 
682 	_z_echoDebug(DBG_ZONES_LCK_THIS, a_lflags);
683 
684 	zoneName = z_get_zonename();
685 	pid = getpid();
686 
687 	/* lock zone administration */
688 
689 	if (a_lflags & ZLOCKS_ZONE_ADMIN) {
690 		b = _z_lock_zone_object(&_z_global_data._z_ObjectLocks,
691 		    zoneName, LOBJ_ZONEADMIN, pid,
692 		    MSG_ZONES_LCK_THIS_ZONEADM,
693 		    ERR_ZONES_LCK_THIS_ZONEADM);
694 		if (!b) {
695 			(void) free(zoneName);
696 			return (B_FALSE);
697 		}
698 	}
699 
700 	/* lock package administration always */
701 
702 	if (a_lflags & ZLOCKS_PKG_ADMIN) {
703 		b = _z_lock_zone_object(&_z_global_data._z_ObjectLocks,
704 		    zoneName, LOBJ_PKGADMIN, pid,
705 		    MSG_ZONES_LCK_THIS_PKGADM,
706 		    ERR_ZONES_LCK_THIS_PKGADM);
707 		if (!b) {
708 			(void) z_unlock_this_zone(a_lflags);
709 			(void) free(zoneName);
710 			return (B_FALSE);
711 		}
712 	}
713 
714 	/* lock patch administration always */
715 
716 	if (a_lflags & ZLOCKS_PATCH_ADMIN) {
717 		b = _z_lock_zone_object(&_z_global_data._z_ObjectLocks,
718 		    zoneName, LOBJ_PATCHADMIN, pid,
719 		    MSG_ZONES_LCK_THIS_PATCHADM,
720 		    ERR_ZONES_LCK_THIS_PATCHADM);
721 		if (!b) {
722 			(void) z_unlock_this_zone(a_lflags);
723 			(void) free(zoneName);
724 			return (B_FALSE);
725 		}
726 	}
727 
728 	(void) free(zoneName);
729 
730 	return (B_TRUE);
731 }
732 
733 /*
734  * Name:	z_lock_zones
735  * Description:	lock specified zones
736  * Arguments:	a_zlst - zoneList_t object describing zones to lock
737  *		a_lflags - [RO, *RO] - (ZLOCKS_T)
738  *			Flags indicating which locks to acquire
739  * Returns:	boolean_t
740  *			== B_TRUE - success, zones locked
741  *			== B_FALSE - failure, zones not locked
742  */
743 
744 boolean_t
745 z_lock_zones(zoneList_t a_zlst, ZLOCKS_T a_lflags)
746 {
747 	boolean_t	b;
748 	int		i;
749 
750 	/* entry assertions */
751 
752 	assert(a_lflags != ZLOCKS_NONE);
753 
754 	/* entry debugging info */
755 
756 	_z_echoDebug(DBG_ZONES_LCK_ZONES, a_lflags);
757 
758 	/* if zones are not implemented, return TRUE */
759 
760 	if (z_zones_are_implemented() == B_FALSE) {
761 		_z_echoDebug(DBG_ZONES_LCK_ZONES_UNIMP);
762 		return (B_TRUE);
763 	}
764 
765 	/* lock this zone first before locking other zones */
766 
767 	b = z_lock_this_zone(a_lflags);
768 	if (b == B_FALSE) {
769 		return (b);
770 	}
771 
772 	/* ignore empty list */
773 
774 	if (a_zlst == (zoneList_t)NULL) {
775 		_z_echoDebug(DBG_ZONES_LCK_ZONES_NOZONES);
776 		return (B_FALSE);
777 	}
778 
779 	/* zones exist */
780 
781 	_z_echoDebug(DBG_ZONES_LCK_ZONES_EXIST);
782 
783 	/*
784 	 * lock each listed zone that is currently running
785 	 */
786 
787 	for (i = 0; (a_zlst[i]._zlName != (char *)NULL); i++) {
788 		/* ignore zone if already locked */
789 		if (a_zlst[i]._zlStatus & ZST_LOCKED) {
790 			continue;
791 		}
792 
793 		/* ignore zone if not running */
794 		if (a_zlst[i]._zlCurrKernelStatus != ZONE_STATE_RUNNING &&
795 		    a_zlst[i]._zlCurrKernelStatus != ZONE_STATE_MOUNTED) {
796 			continue;
797 		}
798 
799 		/*
800 		 * mark zone locked - if interrupted out during lock, an attempt
801 		 * will be made to release the lock
802 		 */
803 		a_zlst[i]._zlStatus |= ZST_LOCKED;
804 
805 		/* lock this zone */
806 		b = _z_lock_zone(&a_zlst[i], a_lflags);
807 
808 		/* on failure unlock all zones and return error */
809 		if (b != B_TRUE) {
810 			_z_program_error(ERR_ZONES_LCK_ZONES_FAILED,
811 			    a_zlst[i]._zlName);
812 			(void) z_unlock_zones(a_zlst, a_lflags);
813 			return (B_FALSE);
814 		}
815 	}
816 
817 	/* success */
818 
819 	return (B_TRUE);
820 }
821 
822 /*
823  * Name:	z_mount_in_lz
824  * Description:	Mount global zone directory in specified zone's root file system
825  * Arguments:	r_lzMountPoint - pointer to handle to string - on success, the
826  *			full path to the mount point relative to the global zone
827  *			root file system is returned here - this is needed to
828  *			unmount the directory when it is no longer needed
829  *		r_lzRootPath - pointer to handle to string - on success, the
830  *			full path to the mount point relative to the specified
831  *			zone's root file system is returned here - this is
832  *			passed to any command executing in the specified zone to
833  *			access the directory mounted
834  *		a_zoneName - pointer to string representing the name of the zone
835  *			to mount the specified global zone directory in
836  *		a_gzPath - pointer to string representing the full absolute path
837  *			of the global zone directory to LOFS mount inside of the
838  *			specified non-global zone
839  *		a_mountPointPrefix - pointer to string representing the prefix
840  *			to be used when creating the mount point name in the
841  *			specified zone's root directory
842  * Returns:	boolean_t
843  *			== B_TRUE - global zone directory mounted successfully
844  *			== B_FALSE - failed to mount directory in specified zone
845  * NOTE:    	Any strings returned is placed in new storage for the
846  *		calling function. The caller must use 'Free' to dispose
847  *		of the storage once the strings are no longer needed.
848  */
849 
850 boolean_t
851 z_mount_in_lz(char **r_lzMountPoint, char **r_lzRootPath, char *a_zoneName,
852 	char *a_gzPath, char *a_mountPointPrefix)
853 {
854 	char		lzRootPath[MAXPATHLEN] = {'\0'};
855 	char		uuid[MAXPATHLEN] = {'\0'};
856 	char		gzMountPoint[MAXPATHLEN] = {'\0'};
857 	char		lzMountPoint[MAXPATHLEN] = {'\0'};
858 	hrtime_t	hretime;
859 	int		err;
860 	int		slen;
861 	struct tm	tstruct;
862 	time_t		thetime;
863 	zoneid_t	zid;
864 
865 	/* entry assertions */
866 
867 	assert(a_zoneName != (char *)NULL);
868 	assert(*a_zoneName != '\0');
869 	assert(a_gzPath != (char *)NULL);
870 	assert(*a_gzPath != '\0');
871 	assert(r_lzMountPoint != (char **)NULL);
872 	assert(r_lzRootPath != (char **)NULL);
873 
874 	/* entry debugging info */
875 
876 	_z_echoDebug(DBG_ZONES_MOUNT_IN_LZ_ENTRY, a_zoneName, a_gzPath);
877 
878 	/* reset returned non-global zone mount point path handle */
879 
880 	*r_lzMountPoint = (char *)NULL;
881 	*r_lzRootPath = (char *)NULL;
882 
883 	/* if zones are not implemented, return FALSE */
884 
885 	if (z_zones_are_implemented() == B_FALSE) {
886 		return (B_FALSE);
887 	}
888 
889 	/* error if global zone path is not absolute */
890 
891 	if (*a_gzPath != '/') {
892 		_z_program_error(ERR_GZPATH_NOT_ABSOLUTE, a_gzPath);
893 		return (B_FALSE);
894 	}
895 
896 	/* error if global zone path does not exist */
897 
898 	if (_z_is_directory(a_gzPath) != 0) {
899 		_z_program_error(ERR_GZPATH_NOT_DIR, a_gzPath, strerror(errno));
900 		return (B_FALSE);
901 	}
902 
903 	/* verify that specified non-global zone exists */
904 
905 	err = zone_get_id(a_zoneName, &zid);
906 	if (err != Z_OK) {
907 		_z_program_error(ERR_GET_ZONEID, a_zoneName,
908 		    zonecfg_strerror(err));
909 		return (B_FALSE);
910 	}
911 
912 	/* obtain global zone path to non-global zones root file system */
913 
914 	err = zone_get_rootpath(a_zoneName, lzRootPath, sizeof (lzRootPath));
915 	if (err != Z_OK) {
916 		_z_program_error(ERR_NO_ZONE_ROOTPATH, a_zoneName,
917 		    zonecfg_strerror(err));
918 		return (B_FALSE);
919 	}
920 
921 	if (lzRootPath[0] == '\0') {
922 		_z_program_error(ERR_ROOTPATH_EMPTY, a_zoneName);
923 		return (B_FALSE);
924 	}
925 
926 	/*
927 	 * lofs resolve the non-global zone's root path first in case
928 	 * its in a path that's been lofs mounted read-only.
929 	 * (e.g. This happens when we're tyring to patch a zone in an ABE
930 	 * that lives on a filesystem that the ABE shares with the currently
931 	 * running BE.)
932 	 */
933 	z_resolve_lofs(lzRootPath, sizeof (lzRootPath));
934 
935 	/* verify that the root path exists */
936 
937 	if (_z_is_directory(lzRootPath) != 0) {
938 		_z_program_error(ERR_LZROOT_NOTDIR, lzRootPath,
939 		    strerror(errno));
940 		return (B_FALSE);
941 	}
942 
943 	/*
944 	 * generate a unique key - the key is the same length as unique uid
945 	 * but contains different information that is as unique as can be made;
946 	 * include current hires time (nanosecond real timer). Such a unique
947 	 * i.d. will look like:
948 	 *		0203104092-1145345-0004e94d6af481a0
949 	 */
950 
951 	hretime = gethrtime();
952 
953 	thetime = time((time_t *)NULL);
954 	(void) localtime_r(&thetime, &tstruct);
955 
956 	slen = snprintf(uuid, sizeof (uuid),
957 	    UUID_FORMAT,
958 	    tstruct.tm_mday, tstruct.tm_mon, tstruct.tm_year,
959 	    tstruct.tm_yday, tstruct.tm_hour, tstruct.tm_min,
960 	    tstruct.tm_sec,	tstruct.tm_wday, hretime);
961 	if (slen > sizeof (uuid)) {
962 		_z_program_error(ERR_GZMOUNT_SNPRINTFUUID_FAILED,
963 		    UUID_FORMAT, sizeof (uuid));
964 		return (B_FALSE);
965 	}
966 
967 	/* create the global zone mount point */
968 
969 	slen = snprintf(gzMountPoint, sizeof (gzMountPoint), "%s/.SUNW_%s_%s",
970 	    lzRootPath,
971 	    a_mountPointPrefix ? a_mountPointPrefix : "zones", uuid);
972 	if (slen > sizeof (gzMountPoint)) {
973 		_z_program_error(ERR_GZMOUNT_SNPRINTFGMP_FAILED,
974 		    "%s/.SUNW_%s_%s", lzRootPath,
975 		    a_mountPointPrefix ? a_mountPointPrefix : "zones",
976 		    uuid, sizeof (gzMountPoint));
977 		return (B_FALSE);
978 	}
979 
980 	slen = snprintf(lzMountPoint, sizeof (lzMountPoint), "%s",
981 	    gzMountPoint+strlen(lzRootPath));
982 	if (slen > sizeof (lzMountPoint)) {
983 		_z_program_error(ERR_GZMOUNT_SNPRINTFLMP_FAILED,
984 		    "%s", gzMountPoint+strlen(lzRootPath),
985 		    sizeof (lzMountPoint));
986 		return (B_FALSE);
987 	}
988 
989 	_z_echoDebug(DBG_MNTPT_NAMES, a_gzPath, a_zoneName, gzMountPoint,
990 	    lzMountPoint);
991 
992 	/* error if the mount point already exists */
993 
994 	if (_z_is_directory(gzMountPoint) == 0) {
995 		_z_program_error(ERR_ZONEROOT_NOTDIR, gzMountPoint,
996 		    a_zoneName, strerror(errno));
997 		return (B_FALSE);
998 	}
999 
1000 	/* create the temporary mount point */
1001 
1002 	if (mkdir(gzMountPoint, 0600) != 0) {
1003 		_z_program_error(ERR_MNTPT_MKDIR, gzMountPoint, a_zoneName,
1004 		    strerror(errno));
1005 		return (B_FALSE);
1006 	}
1007 
1008 	/* mount the global zone path on the non-global zone root file system */
1009 
1010 	err = mount(a_gzPath, gzMountPoint, MS_RDONLY|MS_DATA, "lofs",
1011 	    (char *)NULL, 0, (char *)NULL, 0);
1012 	if (err != 0) {
1013 		_z_program_error(ERR_GZMOUNT_FAILED, a_gzPath,
1014 		    gzMountPoint, a_zoneName, strerror(errno));
1015 		return (B_FALSE);
1016 	}
1017 
1018 	/* success - return both mountpoints to caller */
1019 
1020 	*r_lzMountPoint = _z_strdup(gzMountPoint);
1021 
1022 	*r_lzRootPath = _z_strdup(lzMountPoint);
1023 
1024 	/* return success */
1025 
1026 	return (B_TRUE);
1027 }
1028 
1029 /*
1030  * Name:	z_non_global_zones_exist
1031  * Description:	Determine if any non-global native zones exist
1032  * Arguments:	None.
1033  * Returns:	boolean_t
1034  *	== B_TRUE - at least one non-global native zone exists
1035  *	== B_FALSE - no non-global native zone exists
1036  */
1037 
1038 boolean_t
1039 z_non_global_zones_exist(void)
1040 {
1041 	FILE		*zoneIndexFP;
1042 	boolean_t	anyExist = B_FALSE;
1043 	struct zoneent	*ze;
1044 	zone_spec_t	*zent;
1045 
1046 	/* if zones are not implemented, return FALSE */
1047 
1048 	if (z_zones_are_implemented() == B_FALSE) {
1049 		return (B_FALSE);
1050 	}
1051 
1052 	/* determine if any zones are configured */
1053 	zoneIndexFP = setzoneent();
1054 	if (zoneIndexFP == NULL) {
1055 		return (B_FALSE);
1056 	}
1057 
1058 	/* index file open; scan all zones; see if any are at least installed */
1059 
1060 	while ((ze = getzoneent_private(zoneIndexFP)) != NULL) {
1061 		/*
1062 		 * If the user specified an explicit zone list, then ignore any
1063 		 * zones that aren't on that list.
1064 		 */
1065 		if ((zent = _z_global_data._zone_spec) != NULL) {
1066 			while (zent != NULL) {
1067 				if (strcmp(zent->zl_name, ze->zone_name) == 0)
1068 					break;
1069 				zent = zent->zl_next;
1070 			}
1071 			if (zent == NULL) {
1072 				free(ze);
1073 				continue;
1074 			}
1075 		}
1076 
1077 		/* skip the global zone */
1078 		if (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0) {
1079 			free(ze);
1080 			continue;
1081 		}
1082 
1083 		/* skip any branded zones */
1084 		if (z_is_zone_branded(ze->zone_name)) {
1085 			free(ze);
1086 			continue;
1087 		}
1088 
1089 		/* is this zone installed? */
1090 		if (ze->zone_state >= ZONE_STATE_INSTALLED) {
1091 			free(ze);
1092 			anyExist = B_TRUE;
1093 			break;
1094 		}
1095 		free(ze);
1096 	}
1097 
1098 	/* close the index file */
1099 
1100 	endzoneent(zoneIndexFP);
1101 
1102 	/* return results */
1103 
1104 	return (anyExist);
1105 }
1106 
1107 /*
1108  * Name:	z_on_zone_spec
1109  * Description:	Determine if named zone is on the zone_spec list.
1110  * Arguments:	Pointer to name to test.
1111  * Returns:	B_TRUE if named zone is on the list or if the user specified
1112  *		no list at all (all zones is the default), B_FALSE otherwise.
1113  */
1114 
1115 boolean_t
1116 z_on_zone_spec(const char *zonename)
1117 {
1118 	zone_spec_t	*zent;
1119 
1120 	/* entry assertions */
1121 
1122 	assert(zonename != NULL);
1123 	assert(*zonename != '\0');
1124 
1125 	/* return true if zones not implemented or no zone spec list defined */
1126 
1127 	if (!z_zones_are_implemented() || _z_global_data._zone_spec == NULL) {
1128 		return (B_TRUE);
1129 	}
1130 
1131 	/* return true if named zone is on the zone spec list */
1132 
1133 	for (zent = _z_global_data._zone_spec;
1134 	    zent != NULL; zent = zent->zl_next) {
1135 		if (strcmp(zent->zl_name, zonename) == 0)
1136 			return (B_TRUE);
1137 	}
1138 
1139 	/* named zone is not on the zone spec list */
1140 
1141 	return (B_FALSE);
1142 }
1143 
1144 /*
1145  * Name:	z_running_in_global_zone
1146  * Description:	Determine if running in the "global" zone
1147  * Arguments:	void
1148  * Returns:	boolean_t
1149  *			== B_TRUE - running in global zone
1150  *			== B_FALSE - not running in global zone
1151  */
1152 
1153 boolean_t
1154 z_running_in_global_zone(void)
1155 {
1156 	static	boolean_t	_zoneIdDetermined = B_FALSE;
1157 	static	boolean_t	_zoneIsGlobal = B_FALSE;
1158 
1159 	/* if ID has not been determined, cache it now */
1160 
1161 	if (!_zoneIdDetermined) {
1162 		_zoneIdDetermined = B_TRUE;
1163 		_zoneIsGlobal = _z_running_in_global_zone();
1164 	}
1165 
1166 	return (_zoneIsGlobal);
1167 }
1168 
1169 /*
1170  * Name:	z_set_output_functions
1171  * Description:	Link program specific output functions to this library.
1172  * Arguments:	a_echo_fcn - (_z_printf_fcn_t)
1173  *			Function to call to cause "normal operation" messages
1174  *			to be output/displayed
1175  *		a_echo_debug_fcn - (_z_printf_fcn_t)
1176  *			Function to call to cause "debugging" messages
1177  *			to be output/displayed
1178  *		a_progerr_fcn - (_z_printf_fcn_t)
1179  *			Function to call to cause "program error" messages
1180  *			to be output/displayed
1181  * Returns:	void
1182  * NOTE:	If NULL is specified for any function, then the functionality
1183  *		associated with that function is disabled.
1184  * NOTE:	The function pointers provided must call a function that
1185  *		takes two arguments:
1186  *			function(char *format, char *message)
1187  *		Any registered function will be called like:
1188  *			function("%s", "message")
1189  */
1190 
1191 void
1192 z_set_output_functions(_z_printf_fcn_t a_echo_fcn,
1193     _z_printf_fcn_t a_echo_debug_fcn,
1194     _z_printf_fcn_t a_progerr_fcn)
1195 {
1196 	_z_global_data._z_echo = a_echo_fcn;
1197 	_z_global_data._z_echo_debug = a_echo_debug_fcn;
1198 	_z_global_data._z_progerr = a_progerr_fcn;
1199 }
1200 
1201 /*
1202  * Name:	z_set_zone_root
1203  * Description:	Set root for zones library operations
1204  * Arguments:	Path to root of boot environment containing zone; must be
1205  *		absolute.
1206  * Returns:	None.
1207  * NOTE:	Must be called before performing any zone-related operations.
1208  *		(Currently called directly by set_inst_root() during -R
1209  *		argument handling.)
1210  */
1211 
1212 void
1213 z_set_zone_root(const char *zroot)
1214 {
1215 	char *rootdir;
1216 
1217 	/* if zones are not implemented, just return */
1218 
1219 	if (!z_zones_are_implemented())
1220 		return;
1221 
1222 	/* entry assertions */
1223 
1224 	assert(zroot != NULL);
1225 
1226 	rootdir = _z_strdup((char *)zroot);
1227 	z_canoninplace(rootdir);
1228 
1229 	if (strcmp(rootdir, "/") == 0) {
1230 		rootdir[0] = '\0';
1231 	}
1232 
1233 	/* free any existing cached root path */
1234 	if (*_z_global_data._z_root_dir != '\0') {
1235 		free(_z_global_data._z_root_dir);
1236 		_z_global_data._z_root_dir = NULL;
1237 	}
1238 
1239 	/* store duplicate of new zone root path */
1240 
1241 	if (*rootdir != '\0') {
1242 		_z_global_data._z_root_dir = _z_strdup(rootdir);
1243 	} else {
1244 		_z_global_data._z_root_dir = "";
1245 	}
1246 
1247 	/* set zone root path */
1248 
1249 	zonecfg_set_root(rootdir);
1250 
1251 	free(rootdir);
1252 }
1253 
1254 /*
1255  * Name:	z_set_zone_spec
1256  * Description:	Set list of zones on which actions will be performed.
1257  * Arguments:	Whitespace-separated list of zone names.
1258  * Returns:	0 on success, -1 on error.
1259  * NOTES:	Will call _z_program_error if argument can't be parsed or
1260  *		memory not available.
1261  */
1262 
1263 int
1264 z_set_zone_spec(const char *zlist)
1265 {
1266 	const char	*zend;
1267 	ptrdiff_t	zlen;
1268 	zone_spec_t	*zent;
1269 	zone_spec_t	*zhead;
1270 	zone_spec_t	**znextp = &zhead;
1271 
1272 	/* entry assertions */
1273 
1274 	assert(zlist != NULL);
1275 
1276 	/* parse list to zone_spec_t list, store in global data */
1277 
1278 	for (;;) {
1279 		while (isspace(*zlist)) {
1280 			zlist++;
1281 		}
1282 		if (*zlist == '\0') {
1283 			break;
1284 		}
1285 		for (zend = zlist; *zend != '\0'; zend++) {
1286 			if (isspace(*zend)) {
1287 				break;
1288 			}
1289 		}
1290 		zlen = ((ptrdiff_t)zend) - ((ptrdiff_t)zlist);
1291 		if (zlen >= ZONENAME_MAX) {
1292 			_z_program_error(ERR_ZONE_NAME_ILLEGAL, zlen, zlist);
1293 			return (-1);
1294 		}
1295 		zent = _z_malloc(sizeof (*zent));
1296 		(void) memcpy(zent->zl_name, zlist, zlen);
1297 		zent->zl_name[zlen] = '\0';
1298 		zent->zl_used = B_FALSE;
1299 		*znextp = zent;
1300 		znextp = &zent->zl_next;
1301 		zlist = zend;
1302 	}
1303 	*znextp = NULL;
1304 
1305 	if (zhead == NULL) {
1306 		_z_program_error(ERR_ZONE_LIST_EMPTY);
1307 		return (-1);
1308 	}
1309 
1310 	_z_global_data._zone_spec = zhead;
1311 	return (0);
1312 }
1313 
1314 /*
1315  * Name:	z_umount_lz_mount
1316  * Description:	Unmount directory mounted with z_mount_in_lz
1317  * Arguments:	a_lzMountPointer - pointer to string returned by z_mount_in_lz
1318  * Returns:	boolean_t
1319  *			== B_TRUE - successfully unmounted directory
1320  *			== B_FALSE - failed to unmount directory
1321  */
1322 
1323 boolean_t
1324 z_umount_lz_mount(char *a_lzMountPoint)
1325 {
1326 	int	err;
1327 
1328 	/* entry assertions */
1329 
1330 	assert(a_lzMountPoint != (char *)NULL);
1331 	assert(*a_lzMountPoint != '\0');
1332 
1333 	/* entry debugging info */
1334 
1335 	_z_echoDebug(DBG_ZONES_UNMOUNT_FROM_LZ_ENTRY, a_lzMountPoint);
1336 
1337 	/* if zones are not implemented, return TRUE */
1338 
1339 	if (z_zones_are_implemented() == B_FALSE) {
1340 		return (B_FALSE);
1341 	}
1342 
1343 	/* error if global zone path is not absolute */
1344 
1345 	if (*a_lzMountPoint != '/') {
1346 		_z_program_error(ERR_LZMNTPT_NOT_ABSOLUTE, a_lzMountPoint);
1347 		return (B_FALSE);
1348 	}
1349 
1350 	/* verify mount point exists */
1351 
1352 	if (_z_is_directory(a_lzMountPoint) != 0) {
1353 		_z_program_error(ERR_LZMNTPT_NOTDIR, a_lzMountPoint,
1354 		    strerror(errno));
1355 		return (B_FALSE);
1356 	}
1357 
1358 	/* unmount */
1359 
1360 	err = umount2(a_lzMountPoint, 0);
1361 	if (err != 0) {
1362 		_z_program_error(ERR_GZUMOUNT_FAILED, a_lzMountPoint,
1363 		    strerror(errno));
1364 		return (B_FALSE);
1365 	}
1366 
1367 	/* remove the mount point */
1368 
1369 	(void) remove(a_lzMountPoint);
1370 
1371 	/* return success */
1372 
1373 	return (B_TRUE);
1374 }
1375 
1376 /*
1377  * Name:	z_unlock_this_zone
1378  * Description:	unlock this zone
1379  * Arguments:	a_lflags - [RO, *RO] - (ZLOCKS_T)
1380  *			Flags indicating which locks to release
1381  * Returns:	boolean_t
1382  *			== B_TRUE - success specified locks released
1383  *			== B_FALSE - failure specified locks may not be released
1384  * NOTE: the lock objects for "this zone" are maintained internally.
1385  */
1386 
1387 boolean_t
1388 z_unlock_this_zone(ZLOCKS_T a_lflags)
1389 {
1390 	boolean_t	b;
1391 	boolean_t	errors = B_FALSE;
1392 	char		*zoneName;
1393 
1394 	/* entry assertions */
1395 
1396 	assert(a_lflags != ZLOCKS_NONE);
1397 
1398 	/* entry debugging info */
1399 
1400 	_z_echoDebug(DBG_ZONES_ULK_THIS, a_lflags);
1401 
1402 	/* return if no objects locked */
1403 
1404 	if ((_z_global_data._z_ObjectLocks == (char *)NULL) ||
1405 	    (*_z_global_data._z_ObjectLocks == '\0')) {
1406 		return (B_TRUE);
1407 	}
1408 
1409 	zoneName = z_get_zonename();
1410 
1411 	/* unlock patch administration */
1412 
1413 	if (a_lflags & ZLOCKS_PATCH_ADMIN) {
1414 		b = _z_unlock_zone_object(&_z_global_data._z_ObjectLocks,
1415 		    zoneName, LOBJ_PATCHADMIN, ERR_ZONES_ULK_THIS_PATCH);
1416 		if (!b) {
1417 			errors = B_TRUE;
1418 		}
1419 	}
1420 
1421 	/* unlock package administration */
1422 
1423 	if (a_lflags & ZLOCKS_PKG_ADMIN) {
1424 		b = _z_unlock_zone_object(&_z_global_data._z_ObjectLocks,
1425 		    zoneName, LOBJ_PKGADMIN, ERR_ZONES_ULK_THIS_PACKAGE);
1426 		if (!b) {
1427 			errors = B_TRUE;
1428 		}
1429 	}
1430 
1431 	/* unlock zone administration */
1432 
1433 	if (a_lflags & ZLOCKS_ZONE_ADMIN) {
1434 		b = _z_unlock_zone_object(&_z_global_data._z_ObjectLocks,
1435 		    zoneName, LOBJ_ZONEADMIN, ERR_ZONES_ULK_THIS_ZONES);
1436 		if (!b) {
1437 			errors = B_TRUE;
1438 		}
1439 	}
1440 
1441 	(void) free(zoneName);
1442 	return (!errors);
1443 }
1444 
1445 /*
1446  * Name:	z_unlock_zones
1447  * Description:	unlock specified zones
1448  * Arguments:	a_zlst - zoneList_t object describing zones to unlock
1449  *		a_lflags - [RO, *RO] - (ZLOCKS_T)
1450  *			Flags indicating which locks to release
1451  * Returns:	boolean_t
1452  *			== B_TRUE - success, zones unlocked
1453  *			== B_FALSE - failure, zones not unlocked
1454  */
1455 
1456 boolean_t
1457 z_unlock_zones(zoneList_t a_zlst, ZLOCKS_T a_lflags)
1458 {
1459 	boolean_t	b;
1460 	boolean_t	errors = B_FALSE;
1461 	int		i;
1462 
1463 	/* entry assertions */
1464 
1465 	assert(a_lflags != ZLOCKS_NONE);
1466 
1467 	/* entry debugging info */
1468 
1469 	_z_echoDebug(DBG_ZONES_ULK_ZONES, a_lflags);
1470 
1471 	/* if zones are not implemented, return TRUE */
1472 
1473 	if (z_zones_are_implemented() == B_FALSE) {
1474 		_z_echoDebug(DBG_ZONES_ULK_ZONES_UNIMP);
1475 		return (B_TRUE);
1476 	}
1477 
1478 	/* ignore empty list */
1479 
1480 	if (a_zlst == (zoneList_t)NULL) {
1481 		_z_echoDebug(DBG_ZONES_ULK_ZONES_NOZONES);
1482 		/* unlock this zone before returning */
1483 		return (z_unlock_this_zone(a_lflags));
1484 	}
1485 
1486 	/* zones exist */
1487 
1488 	_z_echoDebug(DBG_ZONES_ULK_ZONES_EXIST);
1489 
1490 	/*
1491 	 * unlock each listed zone that is currently running
1492 	 */
1493 
1494 	for (i = 0; (a_zlst[i]._zlName != (char *)NULL); i++) {
1495 		/* ignore zone if not locked */
1496 		if (!(a_zlst[i]._zlStatus & ZST_LOCKED)) {
1497 			continue;
1498 		}
1499 
1500 		/* ignore zone if not running */
1501 		if (a_zlst[i]._zlCurrKernelStatus != ZONE_STATE_RUNNING &&
1502 		    a_zlst[i]._zlCurrKernelStatus != ZONE_STATE_MOUNTED) {
1503 			continue;
1504 		}
1505 
1506 		/* unlock this zone */
1507 		b = _z_unlock_zone(&a_zlst[i], a_lflags);
1508 
1509 		if (b != B_TRUE) {
1510 			errors = B_TRUE;
1511 		} else {
1512 			/* mark zone as unlocked */
1513 			a_zlst[i]._zlStatus &= ~ZST_LOCKED;
1514 		}
1515 	}
1516 
1517 	/* unlock this zone */
1518 
1519 	if (z_unlock_this_zone(a_lflags) != B_TRUE) {
1520 		errors = B_TRUE;
1521 	}
1522 
1523 	return (errors);
1524 }
1525 
1526 /*
1527  * Name:	z_verify_zone_spec
1528  * Description:	Verify list of zones on which actions will be performed.
1529  * Arguments:	None.
1530  * Returns:	0 on success, -1 on error.
1531  * NOTES:	Will call _z_program_error if there are zones on the specified
1532  *		list that don't exist on the system. Requires that
1533  *		z_set_zone_root is called first (if it is called at all).
1534  */
1535 
1536 int
1537 z_verify_zone_spec(void)
1538 {
1539 	FILE		*zoneIndexFP;
1540 	boolean_t	errors;
1541 	char		zoneIndexPath[MAXPATHLEN];
1542 	struct zoneent	*ze;
1543 	zone_spec_t	*zent;
1544 
1545 	if (!z_zones_are_implemented()) {
1546 		_z_program_error(ERR_ZONES_NOT_IMPLEMENTED);
1547 		return (-1);
1548 	}
1549 
1550 	zoneIndexFP = setzoneent();
1551 	if (zoneIndexFP == NULL) {
1552 		_z_program_error(ERR_ZONEINDEX_OPEN, zoneIndexPath,
1553 		    strerror(errno));
1554 		return (-1);
1555 	}
1556 
1557 	while ((ze = getzoneent_private(zoneIndexFP)) != NULL) {
1558 		for (zent = _z_global_data._zone_spec;
1559 		    zent != NULL; zent = zent->zl_next) {
1560 			if (strcmp(zent->zl_name, ze->zone_name) == 0) {
1561 				zent->zl_used = B_TRUE;
1562 				break;
1563 			}
1564 		}
1565 		free(ze);
1566 	}
1567 	endzoneent(zoneIndexFP);
1568 
1569 	errors = B_FALSE;
1570 	for (zent = _z_global_data._zone_spec;
1571 	    zent != NULL; zent = zent->zl_next) {
1572 		if (!zent->zl_used) {
1573 			_z_program_error(ERR_ZONE_NONEXISTENT, zent->zl_name);
1574 			errors = B_TRUE;
1575 		}
1576 	}
1577 	return (errors ? -1 : 0);
1578 }
1579 
1580 /*
1581  * Name:	z_zlist_change_zone_state
1582  * Description:	Change the current state of the specified zone
1583  * Arguments:	a_zlst - handle to zoneList_t object describing all zones
1584  *		a_zoneIndex - index into a_zlst of the zone to return the
1585  *		a_newState - the state to put the specified zone in
1586  * Returns:	boolean_t
1587  *			== B_TRUE - the zone is in the new state
1588  *			== B_FALSE - unable to transition the zone to the
1589  *				specified state
1590  * NOTE:	This changes the "current kernel" state of the specified
1591  *		zone. For example, to boot the zone, change the state
1592  *		to "ZONE_STATE_RUNNING". To halt the zone, change the
1593  *		state to "ZONE_STATE_INSTALLED".
1594  */
1595 
1596 boolean_t
1597 z_zlist_change_zone_state(zoneList_t a_zlst, int a_zoneIndex,
1598 	zone_state_t a_newState)
1599 {
1600 	int	i;
1601 
1602 	/* entry debugging info */
1603 
1604 	_z_echoDebug(DBG_ZONES_CHG_Z_STATE_ENTRY, a_zoneIndex, a_newState);
1605 
1606 	/* ignore empty list */
1607 
1608 	if (a_zlst == (zoneList_t)NULL) {
1609 		return (B_FALSE);
1610 	}
1611 
1612 	/* find the specified zone in the list */
1613 
1614 	for (i = 0; (i != a_zoneIndex) &&
1615 	    (a_zlst[i]._zlName != (char *)NULL); i++)
1616 		;
1617 
1618 	/* return error if the specified zone does not exist */
1619 
1620 	if (a_zlst[i]._zlName == (char *)NULL) {
1621 		return (B_FALSE);
1622 	}
1623 
1624 	/* return success if the zone is already in this state */
1625 
1626 	if (a_zlst[i]._zlCurrKernelStatus == a_newState) {
1627 		return (B_TRUE);
1628 	}
1629 
1630 	/* take action on new state to set zone to */
1631 
1632 	_z_echoDebug(DBG_ZONES_CHG_Z_STATE, a_zlst[i]._zlName,
1633 	    a_zlst[i]._zlCurrKernelStatus, a_newState);
1634 
1635 	switch (a_newState) {
1636 	case ZONE_STATE_RUNNING:
1637 	case ZONE_STATE_MOUNTED:
1638 		/* these states mean "boot the zone" */
1639 		return (_z_make_zone_running(&a_zlst[i]));
1640 
1641 	case ZONE_STATE_DOWN:
1642 	case ZONE_STATE_INSTALLED:
1643 		/* these states mean "halt the zone" */
1644 		return (_z_make_zone_down(&a_zlst[i]));
1645 
1646 	case ZONE_STATE_READY:
1647 		return (_z_make_zone_ready(&a_zlst[i]));
1648 
1649 	case ZONE_STATE_CONFIGURED:
1650 	case ZONE_STATE_INCOMPLETE:
1651 	case ZONE_STATE_SHUTTING_DOWN:
1652 	default:
1653 		/* do not know how to change zone to this state */
1654 		return (B_FALSE);
1655 	}
1656 }
1657 
1658 /*
1659  * Name:	z_is_zone_branded
1660  * Description:	Determine whether zone has a non-native brand
1661  * Arguments:	a_zoneName - name of the zone to check for branding
1662  * Returns:	boolean_t
1663  *			== B_TRUE - zone has a non-native brand
1664  *			== B_FALSE - zone is native
1665  */
1666 boolean_t
1667 z_is_zone_branded(char *zoneName)
1668 {
1669 	char			brandname[MAXNAMELEN];
1670 	int			err;
1671 
1672 	/* if zones are not implemented, return FALSE */
1673 	if (!z_zones_are_implemented()) {
1674 		return (B_FALSE);
1675 	}
1676 
1677 	/* if brands are not implemented, return FALSE */
1678 	if (!z_brands_are_implemented()) {
1679 		return (B_FALSE);
1680 	}
1681 
1682 	err = zone_get_brand(zoneName, brandname, sizeof (brandname));
1683 	if (err != Z_OK) {
1684 		_z_program_error(ERR_BRAND_GETBRAND, zonecfg_strerror(err));
1685 		return (B_FALSE);
1686 	}
1687 
1688 	/*
1689 	 * Both "native" and "cluster" are native brands
1690 	 * that use the standard facilities in the areas
1691 	 * of packaging/installation/patching/update.
1692 	 */
1693 	if (streq(brandname, NATIVE_BRAND_NAME) ||
1694 	    streq(brandname, CLUSTER_BRAND_NAME)) {
1695 		return (B_FALSE);
1696 	} else {
1697 		return (B_TRUE);
1698 	}
1699 }
1700 
1701 /*
1702  * Name:	z_is_zone_brand_in_list
1703  * Description:	Determine whether zone's brand has a match in the list
1704  *              brands passed in.
1705  * Arguments:	zoneName - name of the zone to check for branding
1706  *              list - list of brands to check the zone against
1707  * Returns:	boolean_t
1708  *			== B_TRUE - zone has a matching brand
1709  *			== B_FALSE - zone brand is not in list
1710  */
1711 boolean_t
1712 z_is_zone_brand_in_list(char *zoneName, zoneBrandList_t *list)
1713 {
1714 	char			brandname[MAXNAMELEN];
1715 	int			err;
1716 	zoneBrandList_t		*sp;
1717 
1718 	if (zoneName == NULL || list == NULL)
1719 		return (B_FALSE);
1720 
1721 	/* if zones are not implemented, return FALSE */
1722 	if (!z_zones_are_implemented()) {
1723 		return (B_FALSE);
1724 	}
1725 
1726 	/* if brands are not implemented, return FALSE */
1727 	if (!z_brands_are_implemented()) {
1728 		return (B_FALSE);
1729 	}
1730 
1731 	err = zone_get_brand(zoneName, brandname, sizeof (brandname));
1732 	if (err != Z_OK) {
1733 		_z_program_error(ERR_BRAND_GETBRAND, zonecfg_strerror(err));
1734 		return (B_FALSE);
1735 	}
1736 
1737 	for (sp = list; sp != NULL; sp = sp->next) {
1738 		if (sp->string_ptr != NULL &&
1739 		    strcmp(sp->string_ptr, brandname) == 0) {
1740 			return (B_TRUE);
1741 		}
1742 	}
1743 
1744 	return (B_FALSE);
1745 }
1746 
1747 /*
1748  * Name:	z_zlist_get_current_state
1749  * Description:	Determine the current kernel state of the specified zone
1750  * Arguments:	a_zlst - handle to zoneList_t object describing all zones
1751  *		a_zoneIndex - index into a_zlst of the zone to return
1752  * Returns:	zone_state_t
1753  *			The current state of the specified zone is returned
1754  */
1755 
1756 zone_state_t
1757 z_zlist_get_current_state(zoneList_t a_zlst, int a_zoneIndex)
1758 {
1759 	int	i;
1760 
1761 	/* ignore empty list */
1762 
1763 	if (a_zlst == (zoneList_t)NULL) {
1764 		return (ZONE_STATE_INCOMPLETE);
1765 	}
1766 
1767 	/* find the specified zone in the list */
1768 
1769 	for (i = 0; (i != a_zoneIndex) &&
1770 	    (a_zlst[i]._zlName != (char *)NULL); i++)
1771 		;
1772 
1773 	/* return error if the specified zone does not exist */
1774 
1775 	if (a_zlst[i]._zlName == (char *)NULL) {
1776 		return (ZONE_STATE_INCOMPLETE);
1777 	}
1778 
1779 	/* return selected zone's current kernel state */
1780 
1781 	_z_echoDebug(DBG_ZONES_GET_ZONE_STATE,
1782 	    a_zlst[i]._zlName ? a_zlst[i]._zlName : "",
1783 	    a_zlst[i]._zlCurrKernelStatus);
1784 
1785 	return (a_zlst[i]._zlCurrKernelStatus);
1786 }
1787 
1788 /*
1789  * Name:	z_zlist_get_inherited_pkg_dirs
1790  * Description:	Determine directories inherited by specified zone
1791  * Arguments:	a_zlst - handle to zoneList_t object describing all zones
1792  *		a_zoneIndex - index into a_zlst of the zone to return the
1793  *			inherited directories list
1794  * Returns:	char **
1795  *			== NULL - zone does not inherit any directories
1796  *				- zone index is invalid
1797  *			!= NULL - array of inherited directories
1798  * NOTE:    	Any directory list returned is located in static storage that
1799  *		must NEVER be free()ed by the caller.
1800  */
1801 
1802 extern char **
1803 z_zlist_get_inherited_pkg_dirs(zoneList_t a_zlst, int a_zoneIndex)
1804 {
1805 	int	i;
1806 
1807 	/* if zones are not implemented, return empty list */
1808 
1809 	if (z_zones_are_implemented() == B_FALSE) {
1810 		return (NULL);
1811 	}
1812 
1813 	/* ignore empty list */
1814 
1815 	if (a_zlst == (zoneList_t)NULL) {
1816 		return (NULL);
1817 	}
1818 
1819 	/* find the specified zone in the list */
1820 
1821 	for (i = 0; (i != a_zoneIndex) &&
1822 	    (a_zlst[i]._zlName != (char *)NULL); i++)
1823 		;
1824 
1825 	/* return error if the specified zone does not exist */
1826 
1827 	if (a_zlst[i]._zlName == (char *)NULL) {
1828 		return (NULL);
1829 	}
1830 
1831 	/* return selected zone's inherited directories */
1832 
1833 	return (a_zlst[i]._zlInheritedDirs);
1834 }
1835 
1836 /*
1837  * Name:	z_zlist_get_original_state
1838  * Description:	Return the original kernal state of the specified zone
1839  * Arguments:	a_zlst - handle to zoneList_t object describing all zones
1840  *		a_zoneIndex - index into a_zlst of the zone to return the
1841  * Returns:	zone_state_t
1842  *			The original state of the specified zone is returned.
1843  *			This is the state of the zone when the zoneList_t
1844  *			object was first generated.
1845  */
1846 
1847 zone_state_t
1848 z_zlist_get_original_state(zoneList_t a_zlst, int a_zoneIndex)
1849 {
1850 	int	i;
1851 
1852 	/* ignore empty list */
1853 
1854 	if (a_zlst == (zoneList_t)NULL) {
1855 		return (ZONE_STATE_INCOMPLETE);
1856 	}
1857 
1858 	/* find the specified zone in the list */
1859 
1860 	for (i = 0; (i != a_zoneIndex) &&
1861 	    (a_zlst[i]._zlName != (char *)NULL); i++)
1862 		;
1863 
1864 	/* return error if the specified zone does not exist */
1865 
1866 	if (a_zlst[i]._zlName == (char *)NULL) {
1867 		return (ZONE_STATE_INCOMPLETE);
1868 	}
1869 
1870 	/* return selected zone's original kernel state */
1871 
1872 	return (a_zlst[i]._zlOrigKernelStatus);
1873 }
1874 
1875 /*
1876  * Name:	z_zlist_get_scratch
1877  * Description:	Determine name of scratch zone
1878  * Arguments:	a_zlst - handle to zoneList_t object describing all zones
1879  *		a_zoneIndex - index into a_zlst of the zone to use
1880  * Return:	char *
1881  *			== NULL - zone name could not be determined
1882  *			!= NULL - pointer to string representing scratch zone
1883  * NOTE:    	Any name returned is placed in static storage that must
1884  *		NEVER be free()ed by the caller.
1885  */
1886 
1887 char *
1888 z_zlist_get_scratch(zoneList_t a_zlst, int a_zoneIndex)
1889 {
1890 	int	i;
1891 
1892 	/* ignore empty list */
1893 
1894 	if (a_zlst == NULL)
1895 		return (NULL);
1896 
1897 	/* find the specified zone in the list */
1898 
1899 	for (i = 0; i != a_zoneIndex; i++) {
1900 		if (a_zlst[i]._zlName == NULL)
1901 			return (NULL);
1902 	}
1903 
1904 	/* return selected zone's scratch name */
1905 
1906 	return (a_zlst[i]._zlScratchName == NULL ? a_zlst[i]._zlName :
1907 	    a_zlst[i]._zlScratchName);
1908 }
1909 
1910 /*
1911  * Name:	z_zlist_get_zonename
1912  * Description:	Determine name of specified zone
1913  * Arguments:	a_zlst - handle to zoneList_t object describing all zones
1914  *		a_zoneIndex - index into a_zlst of the zone to return the
1915  * Return:	char *
1916  *			== NULL - zone name could not be determined
1917  *			!= NULL - pointer to string representing zone name
1918  * NOTE:    	Any zoneList_t returned is placed in static storage that must
1919  *		NEVER be free()ed by the caller.
1920  */
1921 
1922 char *
1923 z_zlist_get_zonename(zoneList_t a_zlst, int a_zoneIndex)
1924 {
1925 	int	i;
1926 
1927 	/* ignore empty list */
1928 
1929 	if (a_zlst == (zoneList_t)NULL) {
1930 		return ((char *)NULL);
1931 	}
1932 
1933 	/* find the specified zone in the list */
1934 
1935 	for (i = 0; (i != a_zoneIndex) &&
1936 	    (a_zlst[i]._zlName != (char *)NULL); i++)
1937 		;
1938 
1939 	/* return error if the specified zone does not exist */
1940 
1941 	if (a_zlst[i]._zlName == (char *)NULL) {
1942 		return (NULL);
1943 	}
1944 
1945 	/* return selected zone's name */
1946 
1947 	return (a_zlst[i]._zlName);
1948 }
1949 
1950 /*
1951  * Name:	z_zlist_get_zonepath
1952  * Description:	Determine zonepath of specified zone
1953  * Arguments:	a_zlst - handle to zoneList_t object describing all zones
1954  *		a_zoneIndex - index into a_zlst of the zone to return
1955  * Return:	char *
1956  *			== NULL - zonepath could not be determined
1957  *			!= NULL - pointer to string representing zonepath
1958  * NOTE:    	Any zoneList_t returned is placed in static storage that must
1959  *		NEVER be free()ed by the caller.
1960  */
1961 
1962 char *
1963 z_zlist_get_zonepath(zoneList_t a_zlst, int a_zoneIndex)
1964 {
1965 	int	i;
1966 
1967 	/* ignore empty list */
1968 
1969 	if (a_zlst == (zoneList_t)NULL) {
1970 		return ((char *)NULL);
1971 	}
1972 
1973 	/* find the specified zone in the list */
1974 
1975 	for (i = 0; (i != a_zoneIndex) &&
1976 	    (a_zlst[i]._zlName != (char *)NULL); i++)
1977 		;
1978 
1979 	/* return error if the specified zone does not exist */
1980 
1981 	if (a_zlst[i]._zlName == (char *)NULL) {
1982 		return (NULL);
1983 	}
1984 
1985 	/* return selected zone's zonepath */
1986 
1987 	return (a_zlst[i]._zlPath);
1988 }
1989 
1990 boolean_t
1991 z_zlist_is_zone_runnable(zoneList_t a_zlst, int a_zoneIndex)
1992 {
1993 	int	i;
1994 
1995 	/* if zones are not implemented, return error */
1996 
1997 	if (z_zones_are_implemented() == B_FALSE) {
1998 		return (B_FALSE);
1999 	}
2000 
2001 	/* ignore empty list */
2002 
2003 	if (a_zlst == (zoneList_t)NULL) {
2004 		return (B_FALSE);
2005 	}
2006 
2007 	/* find the specified zone in the list */
2008 
2009 	for (i = 0; (i != a_zoneIndex) &&
2010 	    (a_zlst[i]._zlName != (char *)NULL); i++)
2011 		;
2012 
2013 	/* return error if the specified zone does not exist */
2014 
2015 	if (a_zlst[i]._zlName == (char *)NULL) {
2016 		return (B_FALSE);
2017 	}
2018 
2019 	/* choose based on current state */
2020 
2021 	switch (a_zlst[i]._zlCurrKernelStatus) {
2022 	case ZONE_STATE_RUNNING:
2023 	case ZONE_STATE_MOUNTED:
2024 		/* already running */
2025 		return (B_TRUE);
2026 
2027 	case ZONE_STATE_INSTALLED:
2028 	case ZONE_STATE_DOWN:
2029 	case ZONE_STATE_READY:
2030 	case ZONE_STATE_SHUTTING_DOWN:
2031 		/* return false if the zone cannot be booted */
2032 
2033 		if (a_zlst[i]._zlStatus & ZST_NOT_BOOTABLE) {
2034 			return (B_FALSE);
2035 		}
2036 
2037 		return (B_TRUE);
2038 
2039 	case ZONE_STATE_CONFIGURED:
2040 	case ZONE_STATE_INCOMPLETE:
2041 	default:
2042 		/* cannot transition (boot) these states */
2043 		return (B_FALSE);
2044 	}
2045 }
2046 
2047 /*
2048  * Name:	z_zlist_restore_zone_state
2049  * Description:	Return the zone to the state it was originally in
2050  * Arguments:	a_zlst - handle to zoneList_t object describing all zones
2051  *		a_zoneIndex - index into a_zlst of the zone to return the
2052  * Returns:	boolean_t
2053  *			== B_TRUE - the zone's state has been restored
2054  *			== B_FALSE - unable to transition the zone to its
2055  *				original state
2056  */
2057 
2058 boolean_t
2059 z_zlist_restore_zone_state(zoneList_t a_zlst, int a_zoneIndex)
2060 {
2061 	int		i;
2062 
2063 	/* ignore empty list */
2064 
2065 	if (a_zlst == (zoneList_t)NULL) {
2066 		return (B_FALSE);
2067 	}
2068 
2069 	/* find the specified zone in the list */
2070 
2071 	for (i = 0; (i != a_zoneIndex) &&
2072 	    (a_zlst[i]._zlName != (char *)NULL); i++)
2073 		;
2074 
2075 	/* return error if the specified zone does not exist */
2076 
2077 	if (a_zlst[i]._zlName == (char *)NULL) {
2078 		return (B_FALSE);
2079 	}
2080 
2081 	/* transition the zone back to its original state */
2082 
2083 	return (z_zlist_change_zone_state(a_zlst,
2084 	    a_zoneIndex, a_zlst[i]._zlOrigKernelStatus));
2085 }
2086 
2087 /*
2088  * Name:	z_zone_exec
2089  * Description:	Execute a Unix command in a specified zone and return results
2090  * Arguments:	a_zoneName - pointer to string representing the name of the zone
2091  *			to execute the specified command in
2092  *		a_path - pointer to string representing the full path *in the
2093  *			non-global zone named by a_zoneName* of the Unix command
2094  *			to be executed
2095  *		a_argv[] - Pointer to array of character strings representing
2096  *			the arguments to be passed to the Unix command. The list
2097  *			must be termianted with an element that is (char *)NULL
2098  *		NOTE: a_argv[0] is the "command name" passed to the command
2099  *		a_stdoutPath - Pointer to string representing the path to a file
2100  *			into which all output to "stdout" from the Unix command
2101  *			is placed.
2102  *			== (char *)NULL - leave stdout open and pass through
2103  *			== "/dev/null" - discard stdout output
2104  *		a_strerrPath - Pointer to string representing the path to a file
2105  *			into which all output to "stderr" from the Unix command
2106  *			is placed.
2107  *			== (char *)NULL - leave stderr open and pass through
2108  *			== "/dev/null" - discard stderr output
2109  *		a_fds - Pointer to array of integers representing file
2110  *			descriptors to remain open during the call - all
2111  *			file descriptors above STDERR_FILENO not in this
2112  *			list will be closed.
2113  * Returns:	int
2114  *			The return (exit) code from the specified Unix command
2115  *			Special return codes:
2116  *			-1 : failure to exec process
2117  *			-2 : could not create contract for greenline
2118  *			-3 : fork() failed
2119  *			-4 : could not open stdout capture file
2120  *			-5 : error from 'waitpid' other than EINTR
2121  *			-6 : zones are not supported
2122  * NOTE:	All file descriptores other than 0, 1 and 2 are closed except
2123  *		for those file descriptors listed in the a_fds array.
2124  */
2125 
2126 int
2127 z_zone_exec(const char *a_zoneName, const char *a_path, char *a_argv[],
2128 	char *a_stdoutPath, char *a_stderrPath, int *a_fds)
2129 {
2130 	int			final_status;
2131 	int			lerrno;
2132 	int			status;
2133 	int			tmpl_fd;
2134 	pid_t			child_pid;
2135 	pid_t			result_pid;
2136 	struct sigaction	nact;
2137 	struct sigaction	oact;
2138 	void			(*funcSighup)();
2139 	void			(*funcSigint)();
2140 
2141 	/* if zones are not implemented, return TRUE */
2142 
2143 	if (z_zones_are_implemented() == B_FALSE) {
2144 		return (-6);	/* -6 : zones are not supported */
2145 	}
2146 
2147 	if ((tmpl_fd = _zexec_init_template()) == -1) {
2148 		_z_program_error(ERR_CANNOT_CREATE_CONTRACT, strerror(errno));
2149 		return (-2);	/* -2 : could not create greenline contract */
2150 	}
2151 
2152 	/*
2153 	 * hold SIGINT/SIGHUP signals and reset signal received counter;
2154 	 * after the fork1() the parent and child need to setup their respective
2155 	 * interrupt handling and release the hold on the signals
2156 	 */
2157 
2158 	(void) sighold(SIGINT);
2159 	(void) sighold(SIGHUP);
2160 
2161 	_z_global_data._z_SigReceived = 0;	/* no signals received */
2162 
2163 	/*
2164 	 * fork off a new process to execute command in;
2165 	 * fork1() is used instead of vfork() so the child process can
2166 	 * perform operations that would modify the parent process if
2167 	 * vfork() were used
2168 	 */
2169 
2170 	child_pid = fork1();
2171 
2172 	if (child_pid < 0) {
2173 		/*
2174 		 * *************************************************************
2175 		 * fork failed!
2176 		 * *************************************************************
2177 		 */
2178 
2179 		(void) ct_tmpl_clear(tmpl_fd);
2180 		(void) close(tmpl_fd);
2181 		_z_program_error(ERR_FORK, strerror(errno));
2182 
2183 		/* release hold on signals */
2184 
2185 		(void) sigrelse(SIGHUP);
2186 		(void) sigrelse(SIGINT);
2187 
2188 		return (-3);	/* -3 : fork() failed */
2189 	}
2190 
2191 	if (child_pid == 0) {
2192 		int	i;
2193 
2194 		/*
2195 		 * *************************************************************
2196 		 * This is the forked (child) process
2197 		 * *************************************************************
2198 		 */
2199 
2200 		(void) ct_tmpl_clear(tmpl_fd);
2201 		(void) close(tmpl_fd);
2202 
2203 		/* reset any signals to default */
2204 
2205 		for (i = 0; i < NSIG; i++) {
2206 			(void) sigset(i, SIG_DFL);
2207 		}
2208 
2209 		/*
2210 		 * close all file descriptors not in the a_fds list
2211 		 */
2212 
2213 		(void) fdwalk(&_z_close_file_descriptors, (void *)a_fds);
2214 
2215 		/*
2216 		 * if a file for stdout is present, open the file and use the
2217 		 * file to capture stdout from the _zexec process
2218 		 */
2219 
2220 		if (a_stdoutPath != (char *)NULL) {
2221 			int	stdoutfd;
2222 
2223 			stdoutfd = open(a_stdoutPath,
2224 			    O_WRONLY|O_CREAT|O_TRUNC, 0600);
2225 			if (stdoutfd < 0) {
2226 				_z_program_error(ERR_CAPTURE_FILE, a_stdoutPath,
2227 				    strerror(errno));
2228 				return (-4);
2229 			}
2230 
2231 			(void) dup2(stdoutfd, STDOUT_FILENO);
2232 			(void) close(stdoutfd);
2233 		}
2234 
2235 		/*
2236 		 * if a file for stderr is present, open the file and use the
2237 		 * file to capture stderr from the _zexec process
2238 		 */
2239 
2240 		if (a_stderrPath != (char *)NULL) {
2241 			int	stderrfd;
2242 
2243 			stderrfd = open(a_stderrPath,
2244 			    O_WRONLY|O_CREAT|O_TRUNC, 0600);
2245 			if (stderrfd < 0) {
2246 				_z_program_error(ERR_CAPTURE_FILE, a_stderrPath,
2247 				    strerror(errno));
2248 				return (-4);
2249 			}
2250 
2251 			(void) dup2(stderrfd, STDERR_FILENO);
2252 			(void) close(stderrfd);
2253 		}
2254 
2255 		/* release all held signals */
2256 
2257 		(void) sigrelse(SIGHUP);
2258 		(void) sigrelse(SIGINT);
2259 
2260 		/* execute command in the specified non-global zone */
2261 
2262 		_exit(_zexec(a_zoneName, a_path, a_argv));
2263 	}
2264 
2265 	/*
2266 	 * *********************************************************************
2267 	 * This is the forking (parent) process
2268 	 * *********************************************************************
2269 	 */
2270 
2271 	/* register child process i.d. so signal handlers can pass signal on */
2272 
2273 	_z_global_data._z_ChildProcessId = child_pid;
2274 
2275 	/*
2276 	 * setup signal handlers for SIGINT and SIGHUP and release hold
2277 	 */
2278 
2279 	/* hook SIGINT to _z_sig_trap() */
2280 
2281 	nact.sa_handler = _z_sig_trap;
2282 	nact.sa_flags = SA_RESTART;
2283 	(void) sigemptyset(&nact.sa_mask);
2284 
2285 	if (sigaction(SIGINT, &nact, &oact) < 0) {
2286 		funcSigint = SIG_DFL;
2287 	} else {
2288 		funcSigint = oact.sa_handler;
2289 	}
2290 
2291 	/* hook SIGHUP to _z_sig_trap() */
2292 
2293 	nact.sa_handler = _z_sig_trap;
2294 	nact.sa_flags = SA_RESTART;
2295 	(void) sigemptyset(&nact.sa_mask);
2296 
2297 	if (sigaction(SIGHUP, &nact, &oact) < 0) {
2298 		funcSighup = SIG_DFL;
2299 	} else {
2300 		funcSighup = oact.sa_handler;
2301 	}
2302 
2303 	/* release hold on signals */
2304 
2305 	(void) sigrelse(SIGHUP);
2306 	(void) sigrelse(SIGINT);
2307 
2308 	(void) ct_tmpl_clear(tmpl_fd);
2309 	(void) close(tmpl_fd);
2310 
2311 	/*
2312 	 * wait for the process to exit, reap child exit status
2313 	 */
2314 
2315 	for (;;) {
2316 		result_pid = waitpid(child_pid, &status, 0L);
2317 		lerrno = (result_pid == -1 ? errno : 0);
2318 
2319 		/* break loop if child process status reaped */
2320 
2321 		if (result_pid != -1) {
2322 			break;
2323 		}
2324 
2325 		/* break loop if not interrupted out of waitpid */
2326 
2327 		if (errno != EINTR) {
2328 			break;
2329 		}
2330 	}
2331 
2332 	/* reset child process i.d. so signal handlers do not pass signals on */
2333 
2334 	_z_global_data._z_ChildProcessId = -1;
2335 
2336 	/*
2337 	 * If the child process terminated due to a call to exit(), then
2338 	 * set results equal to the 8-bit exit status of the child process;
2339 	 * otherwise, set the exit status to "-1" indicating that the child
2340 	 * exited via a signal.
2341 	 */
2342 
2343 	if (WIFEXITED(status)) {
2344 		final_status = WEXITSTATUS(status);
2345 		if ((_z_global_data._z_SigReceived != 0) &&
2346 		    (final_status == 0)) {
2347 			final_status = 1;
2348 		}
2349 	} else {
2350 		final_status = -1;	/* -1 : failure to exec process */
2351 	}
2352 
2353 	/* determine proper exit code */
2354 
2355 	if (result_pid == -1) {
2356 		final_status = -5;	/* -5 : error from waitpid not EINTR */
2357 	} else if (_z_global_data._z_SigReceived != 0) {
2358 		final_status = -7;	/* -7 : interrupt received */
2359 	}
2360 
2361 	/*
2362 	 * reset signal handlers
2363 	 */
2364 
2365 	/* reset SIGINT */
2366 
2367 	nact.sa_handler = funcSigint;
2368 	nact.sa_flags = SA_RESTART;
2369 	(void) sigemptyset(&nact.sa_mask);
2370 
2371 	(void) sigaction(SIGINT, &nact, (struct sigaction *)NULL);
2372 
2373 	/* reset SIGHUP */
2374 
2375 	nact.sa_handler = funcSighup;
2376 	nact.sa_flags = SA_RESTART;
2377 	(void) sigemptyset(&nact.sa_mask);
2378 
2379 	(void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL);
2380 
2381 	/*
2382 	 * if signal received during command execution, interrupt
2383 	 * this process now.
2384 	 */
2385 
2386 	if (_z_global_data._z_SigReceived != 0) {
2387 		(void) kill(getpid(), SIGINT);
2388 	}
2389 
2390 	/* set errno and return */
2391 
2392 	errno = lerrno;
2393 
2394 	return (final_status);
2395 }
2396 
2397 /*
2398  * Name:	z_zones_are_implemented
2399  * Description:	Determine if any zone operations can be performed
2400  * Arguments:	void
2401  * Returns:	boolean_t
2402  *			== B_TRUE - zone operations are available
2403  *			== B_FALSE - no zone operations can be done
2404  */
2405 
2406 boolean_t
2407 z_zones_are_implemented(void)
2408 {
2409 	static	boolean_t	_zonesImplementedDetermined = B_FALSE;
2410 	static	boolean_t	_zonesAreImplemented = B_FALSE;
2411 
2412 	/* if availability has not been determined, cache it now */
2413 
2414 	if (!_zonesImplementedDetermined) {
2415 		_zonesImplementedDetermined = B_TRUE;
2416 		_zonesAreImplemented = _z_zones_are_implemented();
2417 		if (!_zonesAreImplemented) {
2418 			_z_echoDebug(DBG_ZONES_NOT_IMPLEMENTED);
2419 		} else {
2420 			_z_echoDebug(DBG_ZONES_ARE_IMPLEMENTED);
2421 		}
2422 	}
2423 
2424 	return (_zonesAreImplemented);
2425 }
2426