xref: /illumos-gate/usr/src/lib/libzonecfg/common/libzonecfg.c (revision 7bd461e53b7d677564e6cf81f964fb599de9e8eb)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <libsysevent.h>
30 #include <pthread.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <fnmatch.h>
34 #include <strings.h>
35 #include <unistd.h>
36 #include <assert.h>
37 #include <libgen.h>
38 #include <libintl.h>
39 #include <alloca.h>
40 #include <ctype.h>
41 #include <sys/acl.h>
42 #include <sys/stat.h>
43 #include <sys/brand.h>
44 #include <sys/mntio.h>
45 #include <sys/mnttab.h>
46 #include <sys/nvpair.h>
47 #include <sys/types.h>
48 #include <sys/sockio.h>
49 #include <ftw.h>
50 #include <pool.h>
51 #include <libscf.h>
52 #include <libproc.h>
53 #include <sys/priocntl.h>
54 #include <libuutil.h>
55 
56 #include <arpa/inet.h>
57 #include <netdb.h>
58 
59 #include <libxml/xmlmemory.h>
60 #include <libxml/parser.h>
61 
62 #include <libdevinfo.h>
63 #include <uuid/uuid.h>
64 #include <dirent.h>
65 #include <libbrand.h>
66 
67 #include <libzonecfg.h>
68 #include "zonecfg_impl.h"
69 
70 #define	_PATH_TMPFILE	"/zonecfg.XXXXXX"
71 #define	ZONE_CB_RETRY_COUNT		10
72 #define	ZONE_EVENT_PING_SUBCLASS	"ping"
73 #define	ZONE_EVENT_PING_PUBLISHER	"solaris"
74 
75 /* Hard-code the DTD element/attribute/entity names just once, here. */
76 #define	DTD_ELEM_ATTR		(const xmlChar *) "attr"
77 #define	DTD_ELEM_COMMENT	(const xmlChar *) "comment"
78 #define	DTD_ELEM_DEVICE		(const xmlChar *) "device"
79 #define	DTD_ELEM_FS		(const xmlChar *) "filesystem"
80 #define	DTD_ELEM_FSOPTION	(const xmlChar *) "fsoption"
81 #define	DTD_ELEM_IPD		(const xmlChar *) "inherited-pkg-dir"
82 #define	DTD_ELEM_NET		(const xmlChar *) "network"
83 #define	DTD_ELEM_RCTL		(const xmlChar *) "rctl"
84 #define	DTD_ELEM_RCTLVALUE	(const xmlChar *) "rctl-value"
85 #define	DTD_ELEM_ZONE		(const xmlChar *) "zone"
86 #define	DTD_ELEM_DATASET	(const xmlChar *) "dataset"
87 #define	DTD_ELEM_TMPPOOL	(const xmlChar *) "tmp_pool"
88 #define	DTD_ELEM_PSET		(const xmlChar *) "pset"
89 #define	DTD_ELEM_MCAP		(const xmlChar *) "mcap"
90 #define	DTD_ELEM_PACKAGE	(const xmlChar *) "package"
91 #define	DTD_ELEM_PATCH		(const xmlChar *) "patch"
92 #define	DTD_ELEM_OBSOLETES	(const xmlChar *) "obsoletes"
93 #define	DTD_ELEM_DEV_PERM	(const xmlChar *) "dev-perm"
94 
95 #define	DTD_ATTR_ACTION		(const xmlChar *) "action"
96 #define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
97 #define	DTD_ATTR_AUTOBOOT	(const xmlChar *) "autoboot"
98 #define	DTD_ATTR_IPTYPE		(const xmlChar *) "ip-type"
99 #define	DTD_ATTR_DIR		(const xmlChar *) "directory"
100 #define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
101 #define	DTD_ATTR_LIMITPRIV	(const xmlChar *) "limitpriv"
102 #define	DTD_ATTR_BOOTARGS	(const xmlChar *) "bootargs"
103 #define	DTD_ATTR_SCHED		(const xmlChar *) "scheduling-class"
104 #define	DTD_ATTR_MATCH		(const xmlChar *) "match"
105 #define	DTD_ATTR_NAME		(const xmlChar *) "name"
106 #define	DTD_ATTR_PHYSICAL	(const xmlChar *) "physical"
107 #define	DTD_ATTR_POOL		(const xmlChar *) "pool"
108 #define	DTD_ATTR_PRIV		(const xmlChar *) "priv"
109 #define	DTD_ATTR_RAW		(const xmlChar *) "raw"
110 #define	DTD_ATTR_SPECIAL	(const xmlChar *) "special"
111 #define	DTD_ATTR_TYPE		(const xmlChar *) "type"
112 #define	DTD_ATTR_VALUE		(const xmlChar *) "value"
113 #define	DTD_ATTR_ZONEPATH	(const xmlChar *) "zonepath"
114 #define	DTD_ATTR_NCPU_MIN	(const xmlChar *) "ncpu_min"
115 #define	DTD_ATTR_NCPU_MAX	(const xmlChar *) "ncpu_max"
116 #define	DTD_ATTR_IMPORTANCE	(const xmlChar *) "importance"
117 #define	DTD_ATTR_PHYSCAP	(const xmlChar *) "physcap"
118 #define	DTD_ATTR_VERSION	(const xmlChar *) "version"
119 #define	DTD_ATTR_ID		(const xmlChar *) "id"
120 #define	DTD_ATTR_UID		(const xmlChar *) "uid"
121 #define	DTD_ATTR_GID		(const xmlChar *) "gid"
122 #define	DTD_ATTR_MODE		(const xmlChar *) "mode"
123 #define	DTD_ATTR_ACL		(const xmlChar *) "acl"
124 #define	DTD_ATTR_BRAND		(const xmlChar *) "brand"
125 
126 #define	DTD_ENTITY_BOOLEAN	"boolean"
127 #define	DTD_ENTITY_DEVPATH	"devpath"
128 #define	DTD_ENTITY_DRIVER	"driver"
129 #define	DTD_ENTITY_DRVMIN	"drv_min"
130 #define	DTD_ENTITY_FALSE	"false"
131 #define	DTD_ENTITY_INT		"int"
132 #define	DTD_ENTITY_STRING	"string"
133 #define	DTD_ENTITY_TRUE		"true"
134 #define	DTD_ENTITY_UINT		"uint"
135 
136 #define	DTD_ENTITY_BOOL_LEN	6	/* "false" */
137 
138 #define	DETACHED	"SUNWdetached.xml"
139 #define	ATTACH_FORCED	"SUNWattached.xml"
140 #define	PKG_PATH	"/var/sadm/pkg"
141 #define	CONTENTS_FILE	"/var/sadm/install/contents"
142 #define	SUNW_PKG_ALL_ZONES	"SUNW_PKG_ALLZONES=true\n"
143 #define	SUNW_PKG_THIS_ZONE	"SUNW_PKG_THISZONE=true\n"
144 #define	VERSION		"VERSION="
145 #define	PATCHLIST	"PATCHLIST="
146 #define	PATCHINFO	"PATCH_INFO_"
147 #define	PKGINFO_RD_LEN	128
148 
149 #define	TMP_POOL_NAME	"SUNWtmp_%s"
150 #define	MAX_TMP_POOL_NAME	(ZONENAME_MAX + 9)
151 #define	RCAP_SERVICE	"system/rcap:default"
152 #define	POOLD_SERVICE	"system/pools/dynamic:default"
153 
154 enum zn_ipd_fs {ZONE_IPD, ZONE_FS};
155 
156 /*
157  * rctl alias definitions
158  *
159  * This holds the alias, the full rctl name, the default priv value, action
160  * and lower limit.  The functions that handle rctl aliases step through
161  * this table, matching on the alias, and using the full values for setting
162  * the rctl entry as well the limit for validation.
163  */
164 static struct alias {
165 	char *shortname;
166 	char *realname;
167 	char *priv;
168 	char *action;
169 	uint64_t low_limit;
170 } aliases[] = {
171 	{ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
172 	{ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
173 	{ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
174 	{ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
175 	{ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
176 	{ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
177 	{ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
178 	{ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
179 	{ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
180 	{NULL, NULL, NULL, NULL, 0}
181 };
182 
183 /*
184  * Structure for applying rctls to a running zone.  It allows important
185  * process values to be passed together easily.
186  */
187 typedef struct pr_info_handle {
188 	struct ps_prochandle *pr;
189 	pid_t pid;
190 } pr_info_handle_t;
191 
192 struct zone_dochandle {
193 	char		*zone_dh_rootdir;
194 	xmlDocPtr	zone_dh_doc;
195 	xmlNodePtr	zone_dh_cur;
196 	xmlNodePtr	zone_dh_top;
197 	boolean_t	zone_dh_newzone;
198 	boolean_t	zone_dh_snapshot;
199 	boolean_t	zone_dh_sw_inv;
200 	char		zone_dh_delete_name[ZONENAME_MAX];
201 };
202 
203 struct znotify {
204 	void * zn_private;
205 	evchan_t *zn_eventchan;
206 	int (*zn_callback)(const  char *zonename, zoneid_t zid,
207 	    const char *newstate, const char *oldstate, hrtime_t when, void *p);
208 	pthread_mutex_t zn_mutex;
209 	pthread_cond_t zn_cond;
210 	pthread_mutex_t zn_bigmutex;
211 	volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
212 	    ZN_PING_RECEIVED} zn_state;
213 	char zn_subscriber_id[MAX_SUBID_LEN];
214 	volatile boolean_t zn_failed;
215 	int zn_failure_count;
216 };
217 
218 struct zone_pkginfo {
219 	boolean_t	zpi_all_zones;
220 	boolean_t	zpi_this_zone;
221 	int		zpi_patch_cnt;
222 	char		*zpi_version;
223 	char		**zpi_patchinfo;
224 };
225 
226 typedef struct {
227 	uu_avl_node_t	patch_node;
228 	char		*patch_num;
229 	char		*patch_vers;
230 	uu_list_t	*obs_patches;
231 } patch_node_t;
232 
233 typedef struct {
234 	uu_list_node_t	link;
235 	char		*patch_num;
236 } obs_patch_node_t;
237 
238 typedef struct {
239 	uu_avl_t	*obs_patches_avl;
240 	zone_dochandle_t handle;
241 	int		res;
242 } patch_parms_t;
243 
244 char *zonecfg_root = "";
245 
246 /*
247  * For functions which return int, which is most of the functions herein,
248  * the return values should be from the Z_foo set defined in <libzonecfg.h>.
249  * In some instances, we take pains mapping some libc errno values to Z_foo
250  * values from this set.
251  */
252 
253 /*
254  * Set the root (/) path for all zonecfg configuration files.  This is a
255  * private interface used by Live Upgrade extensions to access zone
256  * configuration inside mounted alternate boot environments.
257  */
258 void
259 zonecfg_set_root(const char *rootpath)
260 {
261 	if (*zonecfg_root != '\0')
262 		free(zonecfg_root);
263 	if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
264 	    (zonecfg_root = strdup(rootpath)) == NULL)
265 		zonecfg_root = "";
266 }
267 
268 const char *
269 zonecfg_get_root(void)
270 {
271 	return (zonecfg_root);
272 }
273 
274 boolean_t
275 zonecfg_in_alt_root(void)
276 {
277 	return (*zonecfg_root != '\0');
278 }
279 
280 /*
281  * Callers of the _file_path() functions are expected to have the second
282  * parameter be a (char foo[MAXPATHLEN]).
283  */
284 
285 static boolean_t
286 config_file_path(const char *zonename, char *answer)
287 {
288 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
289 	    ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
290 }
291 
292 static boolean_t
293 snap_file_path(const char *zonename, char *answer)
294 {
295 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
296 	    zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
297 }
298 
299 /*ARGSUSED*/
300 static void
301 zonecfg_error_func(void *ctx, const char *msg, ...)
302 {
303 	/*
304 	 * This function does nothing by design.  Its purpose is to prevent
305 	 * libxml from dumping unwanted messages to stdout/stderr.
306 	 */
307 }
308 
309 zone_dochandle_t
310 zonecfg_init_handle(void)
311 {
312 	zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
313 	if (handle == NULL) {
314 		errno = Z_NOMEM;
315 		return (NULL);
316 	}
317 
318 	/* generic libxml initialization */
319 	xmlLineNumbersDefault(1);
320 	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
321 	xmlDoValidityCheckingDefaultValue = 1;
322 	(void) xmlKeepBlanksDefault(0);
323 	xmlGetWarningsDefaultValue = 0;
324 	xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
325 
326 	return (handle);
327 }
328 
329 int
330 zonecfg_check_handle(zone_dochandle_t handle)
331 {
332 	if (handle == NULL || handle->zone_dh_doc == NULL)
333 		return (Z_BAD_HANDLE);
334 	return (Z_OK);
335 }
336 
337 void
338 zonecfg_fini_handle(zone_dochandle_t handle)
339 {
340 	if (zonecfg_check_handle(handle) == Z_OK)
341 		xmlFreeDoc(handle->zone_dh_doc);
342 	if (handle != NULL)
343 		free(handle);
344 }
345 
346 static int
347 zonecfg_destroy_impl(char *filename)
348 {
349 	if (unlink(filename) == -1) {
350 		if (errno == EACCES)
351 			return (Z_ACCES);
352 		if (errno == ENOENT)
353 			return (Z_NO_ZONE);
354 		return (Z_MISC_FS);
355 	}
356 	return (Z_OK);
357 }
358 
359 int
360 zonecfg_destroy(const char *zonename, boolean_t force)
361 {
362 	char path[MAXPATHLEN];
363 	struct zoneent ze;
364 	int err, state_err;
365 	zone_state_t state;
366 
367 	if (!config_file_path(zonename, path))
368 		return (Z_MISC_FS);
369 
370 	state_err = zone_get_state((char *)zonename, &state);
371 	err = access(path, W_OK);
372 
373 	/*
374 	 * If there is no file, and no index entry, reliably indicate that no
375 	 * such zone exists.
376 	 */
377 	if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
378 		return (Z_NO_ZONE);
379 
380 	/*
381 	 * Handle any other filesystem related errors (except if the XML
382 	 * file is missing, which we treat silently), unless we're forcing,
383 	 * in which case we plow on.
384 	 */
385 	if (err == -1 && errno != ENOENT) {
386 		if (errno == EACCES)
387 			return (Z_ACCES);
388 		else if (!force)
389 			return (Z_MISC_FS);
390 	}
391 
392 	if (state > ZONE_STATE_INSTALLED)
393 		return (Z_BAD_ZONE_STATE);
394 
395 	if (!force && state > ZONE_STATE_CONFIGURED)
396 		return (Z_BAD_ZONE_STATE);
397 
398 	/*
399 	 * Index deletion succeeds even if the entry doesn't exist.  So this
400 	 * will fail only if we've had some more severe problem.
401 	 */
402 	bzero(&ze, sizeof (ze));
403 	(void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
404 	if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
405 		if (!force)
406 			return (err);
407 
408 	err = zonecfg_destroy_impl(path);
409 
410 	/*
411 	 * Treat failure to find the XML file silently, since, well, it's
412 	 * gone, and with the index file cleaned up, we're done.
413 	 */
414 	if (err == Z_OK || err == Z_NO_ZONE)
415 		return (Z_OK);
416 	return (err);
417 }
418 
419 int
420 zonecfg_destroy_snapshot(const char *zonename)
421 {
422 	char path[MAXPATHLEN];
423 
424 	if (!snap_file_path(zonename, path))
425 		return (Z_MISC_FS);
426 	return (zonecfg_destroy_impl(path));
427 }
428 
429 static int
430 getroot(zone_dochandle_t handle, xmlNodePtr *root)
431 {
432 	if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
433 		return (Z_BAD_HANDLE);
434 
435 	*root = xmlDocGetRootElement(handle->zone_dh_doc);
436 
437 	if (*root == NULL)
438 		return (Z_EMPTY_DOCUMENT);
439 
440 	if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
441 		return (Z_WRONG_DOC_TYPE);
442 
443 	return (Z_OK);
444 }
445 
446 static int
447 operation_prep(zone_dochandle_t handle)
448 {
449 	xmlNodePtr root;
450 	int err;
451 
452 	if ((err = getroot(handle, &root)) != 0)
453 		return (err);
454 
455 	handle->zone_dh_cur = root;
456 	handle->zone_dh_top = root;
457 	return (Z_OK);
458 }
459 
460 static int
461 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
462 {
463 	xmlChar *property;
464 	size_t srcsize;
465 
466 	if ((property = xmlGetProp(cur, propname)) == NULL)
467 		return (Z_BAD_PROPERTY);
468 	srcsize = strlcpy(dst, (char *)property, dstsize);
469 	xmlFree(property);
470 	if (srcsize >= dstsize)
471 		return (Z_TOO_BIG);
472 	return (Z_OK);
473 }
474 
475 static int
476 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst)
477 {
478 	xmlChar *property;
479 
480 	if ((property = xmlGetProp(cur, propname)) == NULL)
481 		return (Z_BAD_PROPERTY);
482 	if ((*dst = strdup((char *)property)) == NULL) {
483 		xmlFree(property);
484 		return (Z_NOMEM);
485 	}
486 	xmlFree(property);
487 	return (Z_OK);
488 }
489 
490 static int
491 getrootattr(zone_dochandle_t handle, const xmlChar *propname,
492     char *propval, size_t propsize)
493 {
494 	xmlNodePtr root;
495 	int err;
496 
497 	if ((err = getroot(handle, &root)) != 0)
498 		return (err);
499 
500 	return (fetchprop(root, propname, propval, propsize));
501 }
502 
503 static int
504 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname,
505     char **propval)
506 {
507 	xmlNodePtr root;
508 	int err;
509 
510 	if ((err = getroot(handle, &root)) != 0)
511 		return (err);
512 
513 	return (fetch_alloc_prop(root, propname, propval));
514 }
515 
516 static int
517 setrootattr(zone_dochandle_t handle, const xmlChar *propname,
518     const char *propval)
519 {
520 	int err;
521 	xmlNodePtr root;
522 
523 	if ((err = getroot(handle, &root)) != Z_OK)
524 		return (err);
525 
526 	/*
527 	 * If we get a null propval remove the property (ignore return since it
528 	 * may not be set to begin with).
529 	 */
530 	if (propval == NULL) {
531 		(void) xmlUnsetProp(root, propname);
532 	} else {
533 		if (xmlSetProp(root, propname, (const xmlChar *) propval)
534 		    == NULL)
535 			return (Z_INVAL);
536 	}
537 	return (Z_OK);
538 }
539 
540 static void
541 addcomment(zone_dochandle_t handle, const char *comment)
542 {
543 	xmlNodePtr node;
544 	node = xmlNewComment((xmlChar *) comment);
545 
546 	if (node != NULL)
547 		(void) xmlAddPrevSibling(handle->zone_dh_top, node);
548 }
549 
550 static void
551 stripcomments(zone_dochandle_t handle)
552 {
553 	xmlDocPtr top;
554 	xmlNodePtr child, next;
555 
556 	top = handle->zone_dh_doc;
557 	for (child = top->xmlChildrenNode; child != NULL; child = next) {
558 		next = child->next;
559 		if (child->name == NULL)
560 			continue;
561 		if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
562 			next = child->next;
563 			xmlUnlinkNode(child);
564 			xmlFreeNode(child);
565 		}
566 	}
567 }
568 
569 static void
570 strip_sw_inv(zone_dochandle_t handle)
571 {
572 	xmlNodePtr root, child, next;
573 
574 	root = xmlDocGetRootElement(handle->zone_dh_doc);
575 	for (child = root->xmlChildrenNode; child != NULL; child = next) {
576 		next = child->next;
577 		if (child->name == NULL)
578 			continue;
579 		if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0 ||
580 		    xmlStrcmp(child->name, DTD_ELEM_PATCH) == 0) {
581 			next = child->next;
582 			xmlUnlinkNode(child);
583 			xmlFreeNode(child);
584 		}
585 	}
586 }
587 
588 static int
589 zonecfg_get_handle_impl(const char *zonename, const char *filename,
590     zone_dochandle_t handle)
591 {
592 	xmlValidCtxtPtr cvp;
593 	struct stat statbuf;
594 	int valid;
595 
596 	if (zonename == NULL)
597 		return (Z_NO_ZONE);
598 
599 	if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
600 		/* distinguish file not found vs. found but not parsed */
601 		if (stat(filename, &statbuf) == 0)
602 			return (Z_INVALID_DOCUMENT);
603 		return (Z_NO_ZONE);
604 	}
605 	if ((cvp = xmlNewValidCtxt()) == NULL)
606 		return (Z_NOMEM);
607 	cvp->error = zonecfg_error_func;
608 	cvp->warning = zonecfg_error_func;
609 	valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
610 	xmlFreeValidCtxt(cvp);
611 	if (valid == 0)
612 		return (Z_INVALID_DOCUMENT);
613 
614 	/* delete any comments such as inherited Sun copyright / ident str */
615 	stripcomments(handle);
616 	return (Z_OK);
617 }
618 
619 int
620 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
621 {
622 	char path[MAXPATHLEN];
623 
624 	if (!config_file_path(zonename, path))
625 		return (Z_MISC_FS);
626 	handle->zone_dh_newzone = B_FALSE;
627 
628 	return (zonecfg_get_handle_impl(zonename, path, handle));
629 }
630 
631 int
632 zonecfg_get_attach_handle(const char *path, const char *zonename,
633     boolean_t preserve_sw, zone_dochandle_t handle)
634 {
635 	char		migpath[MAXPATHLEN];
636 	int		err;
637 	struct stat	buf;
638 
639 	if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
640 	    sizeof (migpath))
641 		return (Z_NOMEM);
642 
643 	if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
644 		return (Z_NO_ZONE);
645 
646 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >=
647 	    sizeof (migpath))
648 		return (Z_NOMEM);
649 
650 	if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
651 		return (err);
652 
653 	if (!preserve_sw)
654 		strip_sw_inv(handle);
655 
656 	handle->zone_dh_newzone = B_TRUE;
657 	if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
658 		return (err);
659 
660 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
661 }
662 
663 int
664 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
665 {
666 	char path[MAXPATHLEN];
667 
668 	if (!snap_file_path(zonename, path))
669 		return (Z_MISC_FS);
670 	handle->zone_dh_newzone = B_FALSE;
671 	return (zonecfg_get_handle_impl(zonename, path, handle));
672 }
673 
674 int
675 zonecfg_get_template_handle(const char *template, const char *zonename,
676     zone_dochandle_t handle)
677 {
678 	char path[MAXPATHLEN];
679 	int err;
680 
681 	if (!config_file_path(template, path))
682 		return (Z_MISC_FS);
683 
684 	if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
685 		return (err);
686 	handle->zone_dh_newzone = B_TRUE;
687 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
688 }
689 
690 int
691 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
692 {
693 	struct stat buf;
694 	int err;
695 
696 	if (stat(path, &buf) == -1)
697 		return (Z_MISC_FS);
698 
699 	if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
700 		return (err);
701 	handle->zone_dh_newzone = B_TRUE;
702 	return (Z_OK);
703 }
704 
705 /*
706  * Initialize two handles from the manifest read on fd.  The rem_handle
707  * is initialized from the input file, including the sw inventory.  The
708  * local_handle is initialized with the same zone configuration but with
709  * no sw inventory.
710  */
711 int
712 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
713     zone_dochandle_t rem_handle)
714 {
715 	xmlValidCtxtPtr cvp;
716 	int valid;
717 
718 	/* load the manifest into the handle for the remote system */
719 	if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
720 		return (Z_INVALID_DOCUMENT);
721 	}
722 	if ((cvp = xmlNewValidCtxt()) == NULL)
723 		return (Z_NOMEM);
724 	cvp->error = zonecfg_error_func;
725 	cvp->warning = zonecfg_error_func;
726 	valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
727 	xmlFreeValidCtxt(cvp);
728 	if (valid == 0)
729 		return (Z_INVALID_DOCUMENT);
730 
731 	/* delete any comments such as inherited Sun copyright / ident str */
732 	stripcomments(rem_handle);
733 
734 	rem_handle->zone_dh_newzone = B_TRUE;
735 	rem_handle->zone_dh_sw_inv = B_TRUE;
736 
737 	/*
738 	 * Now use the remote system handle to generate a local system handle
739 	 * with an identical zones configuration but no sw inventory.
740 	 */
741 	if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
742 	    1)) == NULL) {
743 		return (Z_INVALID_DOCUMENT);
744 	}
745 
746 	/*
747 	 * We need to re-run xmlValidateDocument on local_handle to properly
748 	 * update the in-core representation of the configuration.
749 	 */
750 	if ((cvp = xmlNewValidCtxt()) == NULL)
751 		return (Z_NOMEM);
752 	cvp->error = zonecfg_error_func;
753 	cvp->warning = zonecfg_error_func;
754 	valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
755 	xmlFreeValidCtxt(cvp);
756 	if (valid == 0)
757 		return (Z_INVALID_DOCUMENT);
758 
759 	strip_sw_inv(local_handle);
760 
761 	local_handle->zone_dh_newzone = B_TRUE;
762 	local_handle->zone_dh_sw_inv = B_FALSE;
763 
764 	return (Z_OK);
765 }
766 
767 static boolean_t
768 is_renaming(zone_dochandle_t handle)
769 {
770 	if (handle->zone_dh_newzone)
771 		return (B_FALSE);
772 	if (strlen(handle->zone_dh_delete_name) > 0)
773 		return (B_TRUE);
774 	return (B_FALSE);
775 }
776 
777 static boolean_t
778 is_new(zone_dochandle_t handle)
779 {
780 	return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
781 }
782 
783 static boolean_t
784 is_snapshot(zone_dochandle_t handle)
785 {
786 	return (handle->zone_dh_snapshot);
787 }
788 
789 /*
790  * It would be great to be able to use libc's ctype(3c) macros, but we
791  * can't, as they are locale sensitive, and it would break our limited thread
792  * safety if this routine had to change the app locale on the fly.
793  */
794 int
795 zonecfg_validate_zonename(const char *zone)
796 {
797 	int i;
798 
799 	if (strcmp(zone, GLOBAL_ZONENAME) == 0)
800 		return (Z_BOGUS_ZONE_NAME);
801 
802 	if (strlen(zone) >= ZONENAME_MAX)
803 		return (Z_BOGUS_ZONE_NAME);
804 
805 	if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
806 	    (zone[0] >= 'A' && zone[0] <= 'Z') ||
807 	    (zone[0] >= '0' && zone[0] <= '9')))
808 		return (Z_BOGUS_ZONE_NAME);
809 
810 	for (i = 1; zone[i] != '\0'; i++) {
811 		if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
812 		    (zone[i] >= 'A' && zone[i] <= 'Z') ||
813 		    (zone[i] >= '0' && zone[i] <= '9') ||
814 		    (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
815 			return (Z_BOGUS_ZONE_NAME);
816 	}
817 
818 	return (Z_OK);
819 }
820 
821 /*
822  * Changing the zone name requires us to track both the old and new
823  * name of the zone until commit time.
824  */
825 int
826 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
827 {
828 	return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
829 }
830 
831 int
832 zonecfg_set_name(zone_dochandle_t handle, char *name)
833 {
834 	zone_state_t state;
835 	char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
836 	int err;
837 
838 	if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
839 	    sizeof (curname))) != Z_OK)
840 		return (err);
841 
842 	if (strcmp(name, curname) == 0)
843 		return (Z_OK);
844 
845 	/*
846 	 * Switching zone names to one beginning with SUNW is not permitted.
847 	 */
848 	if (strncmp(name, "SUNW", 4) == 0)
849 		return (Z_BOGUS_ZONE_NAME);
850 
851 	if ((err = zonecfg_validate_zonename(name)) != Z_OK)
852 		return (err);
853 
854 	/*
855 	 * Setting the name back to the original name (effectively a revert of
856 	 * the name) is fine.  But if we carry on, we'll falsely identify the
857 	 * name as "in use," so special case here.
858 	 */
859 	if (strcmp(name, handle->zone_dh_delete_name) == 0) {
860 		err = setrootattr(handle, DTD_ATTR_NAME, name);
861 		handle->zone_dh_delete_name[0] = '\0';
862 		return (err);
863 	}
864 
865 	/* Check to see if new name chosen is already in use */
866 	if (zone_get_state(name, &state) != Z_NO_ZONE)
867 		return (Z_NAME_IN_USE);
868 
869 	/*
870 	 * If this isn't already "new" or in a renaming transition, then
871 	 * we're initiating a rename here; so stash the "delete name"
872 	 * (i.e. the name of the zone we'll be removing) for the rename.
873 	 */
874 	(void) strlcpy(old_delname, handle->zone_dh_delete_name,
875 	    sizeof (old_delname));
876 	if (!is_new(handle) && !is_renaming(handle)) {
877 		/*
878 		 * Name change is allowed only when the zone we're altering
879 		 * is not ready or running.
880 		 */
881 		err = zone_get_state(curname, &state);
882 		if (err == Z_OK) {
883 			if (state > ZONE_STATE_INSTALLED)
884 				return (Z_BAD_ZONE_STATE);
885 		} else if (err != Z_NO_ZONE) {
886 			return (err);
887 		}
888 
889 		(void) strlcpy(handle->zone_dh_delete_name, curname,
890 		    sizeof (handle->zone_dh_delete_name));
891 		assert(is_renaming(handle));
892 	} else if (is_renaming(handle)) {
893 		err = zone_get_state(handle->zone_dh_delete_name, &state);
894 		if (err == Z_OK) {
895 			if (state > ZONE_STATE_INSTALLED)
896 				return (Z_BAD_ZONE_STATE);
897 		} else if (err != Z_NO_ZONE) {
898 			return (err);
899 		}
900 	}
901 
902 	if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
903 		/*
904 		 * Restore the deletename to whatever it was at the
905 		 * top of the routine, since we've had a failure.
906 		 */
907 		(void) strlcpy(handle->zone_dh_delete_name, old_delname,
908 		    sizeof (handle->zone_dh_delete_name));
909 		return (err);
910 	}
911 
912 	return (Z_OK);
913 }
914 
915 int
916 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
917 {
918 	size_t len;
919 
920 	if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize)
921 		return (Z_TOO_BIG);
922 	return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len,
923 	    pathsize - len));
924 }
925 
926 int
927 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
928 {
929 	size_t len;
930 
931 	/*
932 	 * The user deals in absolute paths in the running global zone, but the
933 	 * internal configuration files deal with boot environment relative
934 	 * paths.  Strip out the alternate root when specified.
935 	 */
936 	len = strlen(zonecfg_root);
937 	if (strncmp(zonepath, zonecfg_root, len) != 0 || zonepath[len] != '/')
938 		return (Z_BAD_PROPERTY);
939 	zonepath += len;
940 	return (setrootattr(handle, DTD_ATTR_ZONEPATH, zonepath));
941 }
942 
943 int
944 zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize)
945 {
946 	int ret, sz;
947 
948 	ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize);
949 
950 	/* If the zone has no brand, it is native. */
951 	if (ret == Z_OK && brand[0] == '\0') {
952 		sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize);
953 		if (sz >= brandsize)
954 			ret = Z_TOO_BIG;
955 		else
956 			ret = Z_OK;
957 	}
958 
959 	return (ret);
960 }
961 
962 int
963 zonecfg_set_brand(zone_dochandle_t handle, char *brand)
964 {
965 	return (setrootattr(handle, DTD_ATTR_BRAND, brand));
966 }
967 
968 int
969 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
970 {
971 	char autobootstr[DTD_ENTITY_BOOL_LEN];
972 	int ret;
973 
974 	if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
975 	    sizeof (autobootstr))) != Z_OK)
976 		return (ret);
977 
978 	if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
979 		*autoboot = B_TRUE;
980 	else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
981 		*autoboot = B_FALSE;
982 	else
983 		ret = Z_BAD_PROPERTY;
984 	return (ret);
985 }
986 
987 int
988 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
989 {
990 	return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
991 	    autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
992 }
993 
994 int
995 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
996 {
997 	return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
998 }
999 
1000 int
1001 zonecfg_set_pool(zone_dochandle_t handle, char *pool)
1002 {
1003 	return (setrootattr(handle, DTD_ATTR_POOL, pool));
1004 }
1005 
1006 int
1007 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv)
1008 {
1009 	return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1010 }
1011 
1012 int
1013 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv)
1014 {
1015 	return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1016 }
1017 
1018 int
1019 zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize)
1020 {
1021 	return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize));
1022 }
1023 
1024 int
1025 zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs)
1026 {
1027 	return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs));
1028 }
1029 
1030 int
1031 zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize)
1032 {
1033 	return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize));
1034 }
1035 
1036 int
1037 zonecfg_set_sched(zone_dochandle_t handle, char *sched)
1038 {
1039 	return (setrootattr(handle, DTD_ATTR_SCHED, sched));
1040 }
1041 
1042 /*
1043  * /etc/zones/index caches a vital piece of information which is also
1044  * in the <zonename>.xml file: the path to the zone.  This is for performance,
1045  * since we need to walk all zonepath's in order to be able to detect conflicts
1046  * (see crosscheck_zonepaths() in the zoneadm command).
1047  *
1048  * An additional complexity is that when doing a rename, we'd like the entire
1049  * index update operation (rename, and potential state changes) to be atomic.
1050  * In general, the operation of this function should succeed or fail as
1051  * a unit.
1052  */
1053 int
1054 zonecfg_refresh_index_file(zone_dochandle_t handle)
1055 {
1056 	char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
1057 	struct zoneent ze;
1058 	int err;
1059 	int opcode;
1060 	char *zn;
1061 
1062 	bzero(&ze, sizeof (ze));
1063 	ze.zone_state = -1;	/* Preserve existing state in index */
1064 
1065 	if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
1066 		return (err);
1067 	(void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
1068 
1069 	if ((err = zonecfg_get_zonepath(handle, zonepath,
1070 	    sizeof (zonepath))) != Z_OK)
1071 		return (err);
1072 	(void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root),
1073 	    sizeof (ze.zone_path));
1074 
1075 	if (is_renaming(handle)) {
1076 		opcode = PZE_MODIFY;
1077 		(void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
1078 		    sizeof (ze.zone_name));
1079 		(void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
1080 	} else if (is_new(handle)) {
1081 		FILE *cookie;
1082 		/*
1083 		 * Be tolerant of the zone already existing in the index file,
1084 		 * since we might be forcibly overwriting an existing
1085 		 * configuration with a new one (for example 'create -F'
1086 		 * in zonecfg).
1087 		 */
1088 		opcode = PZE_ADD;
1089 		cookie = setzoneent();
1090 		while ((zn = getzoneent(cookie)) != NULL) {
1091 			if (strcmp(zn, name) == 0) {
1092 				opcode = PZE_MODIFY;
1093 				free(zn);
1094 				break;
1095 			}
1096 			free(zn);
1097 		}
1098 		endzoneent(cookie);
1099 		ze.zone_state = ZONE_STATE_CONFIGURED;
1100 	} else {
1101 		opcode = PZE_MODIFY;
1102 	}
1103 
1104 	if ((err = putzoneent(&ze, opcode)) != Z_OK)
1105 		return (err);
1106 
1107 	return (Z_OK);
1108 }
1109 
1110 /*
1111  * The goal of this routine is to cause the index file update and the
1112  * document save to happen as an atomic operation.  We do the document
1113  * first, saving a backup copy using a hard link; if that succeeds, we go
1114  * on to the index.  If that fails, we roll the document back into place.
1115  *
1116  * Strategy:
1117  *
1118  * New zone 'foo' configuration:
1119  * 	Create tmpfile (zonecfg.xxxxxx)
1120  * 	Write XML to tmpfile
1121  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1122  * 	Add entry to index file
1123  * 	If it fails, delete foo.xml, leaving nothing behind.
1124  *
1125  * Save existing zone 'foo':
1126  * 	Make backup of foo.xml -> .backup
1127  * 	Create tmpfile (zonecfg.xxxxxx)
1128  * 	Write XML to tmpfile
1129  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1130  * 	Modify index file as needed
1131  * 	If it fails, recover from .backup -> foo.xml
1132  *
1133  * Rename 'foo' to 'bar':
1134  * 	Create tmpfile (zonecfg.xxxxxx)
1135  * 	Write XML to tmpfile
1136  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1137  * 	Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1138  * 	If it fails, delete bar.xml; foo.xml is left behind.
1139  */
1140 static int
1141 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
1142 {
1143 	char tmpfile[MAXPATHLEN];
1144 	char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
1145 	int tmpfd, err, valid;
1146 	xmlValidCtxt cvp = { NULL };
1147 	boolean_t backup;
1148 
1149 	(void) strlcpy(tmpfile, filename, sizeof (tmpfile));
1150 	(void) dirname(tmpfile);
1151 	(void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
1152 
1153 	tmpfd = mkstemp(tmpfile);
1154 	if (tmpfd == -1) {
1155 		(void) unlink(tmpfile);
1156 		return (Z_TEMP_FILE);
1157 	}
1158 	(void) close(tmpfd);
1159 
1160 	cvp.error = zonecfg_error_func;
1161 	cvp.warning = zonecfg_error_func;
1162 
1163 	/*
1164 	 * We do a final validation of the document.  Since the library has
1165 	 * malfunctioned if it fails to validate, we follow-up with an
1166 	 * assert() that the doc is valid.
1167 	 */
1168 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1169 	assert(valid != 0);
1170 
1171 	if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
1172 		goto err;
1173 
1174 	(void) chmod(tmpfile, 0644);
1175 
1176 	/*
1177 	 * In the event we are doing a standard save, hard link a copy of the
1178 	 * original file in .backup.<pid>.filename so we can restore it if
1179 	 * something goes wrong.
1180 	 */
1181 	if (!is_new(handle) && !is_renaming(handle)) {
1182 		backup = B_TRUE;
1183 
1184 		(void) strlcpy(bakdir, filename, sizeof (bakdir));
1185 		(void) strlcpy(bakbase, filename, sizeof (bakbase));
1186 		(void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1187 		    dirname(bakdir), getpid(), basename(bakbase));
1188 
1189 		if (link(filename, bakfile) == -1) {
1190 			err = errno;
1191 			(void) unlink(tmpfile);
1192 			if (errno == EACCES)
1193 				return (Z_ACCES);
1194 			return (Z_MISC_FS);
1195 		}
1196 	}
1197 
1198 	/*
1199 	 * Move the new document over top of the old.
1200 	 * i.e.:   zonecfg.XXXXXX  ->  myzone.xml
1201 	 */
1202 	if (rename(tmpfile, filename) == -1) {
1203 		err = errno;
1204 		(void) unlink(tmpfile);
1205 		if (backup)
1206 			(void) unlink(bakfile);
1207 		if (err == EACCES)
1208 			return (Z_ACCES);
1209 		return (Z_MISC_FS);
1210 	}
1211 
1212 	/*
1213 	 * If this is a snapshot, we're done-- don't add an index entry.
1214 	 */
1215 	if (is_snapshot(handle))
1216 		return (Z_OK);
1217 
1218 	/* now update the index file to reflect whatever we just did */
1219 	if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1220 		if (backup) {
1221 			/*
1222 			 * Try to restore from our backup.
1223 			 */
1224 			(void) unlink(filename);
1225 			(void) rename(bakfile, filename);
1226 		} else {
1227 			/*
1228 			 * Either the zone is new, in which case we can delete
1229 			 * new.xml, or we're doing a rename, so ditto.
1230 			 */
1231 			assert(is_new(handle) || is_renaming(handle));
1232 			(void) unlink(filename);
1233 		}
1234 		return (Z_UPDATING_INDEX);
1235 	}
1236 
1237 	if (backup)
1238 		(void) unlink(bakfile);
1239 
1240 	return (Z_OK);
1241 
1242 err:
1243 	(void) unlink(tmpfile);
1244 	return (Z_SAVING_FILE);
1245 }
1246 
1247 int
1248 zonecfg_save(zone_dochandle_t handle)
1249 {
1250 	char zname[ZONENAME_MAX], path[MAXPATHLEN];
1251 	char delpath[MAXPATHLEN];
1252 	int err = Z_SAVING_FILE;
1253 
1254 	if (zonecfg_check_handle(handle) != Z_OK)
1255 		return (Z_BAD_HANDLE);
1256 
1257 	/*
1258 	 * We don't support saving snapshots or a tree containing a sw
1259 	 * inventory at this time.
1260 	 */
1261 	if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1262 		return (Z_INVAL);
1263 
1264 	if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1265 		return (err);
1266 
1267 	if (!config_file_path(zname, path))
1268 		return (Z_MISC_FS);
1269 
1270 	addcomment(handle, "\n    DO NOT EDIT THIS "
1271 	    "FILE.  Use zonecfg(1M) instead.\n");
1272 
1273 	err = zonecfg_save_impl(handle, path);
1274 
1275 	stripcomments(handle);
1276 
1277 	if (err != Z_OK)
1278 		return (err);
1279 
1280 	handle->zone_dh_newzone = B_FALSE;
1281 
1282 	if (is_renaming(handle)) {
1283 		if (config_file_path(handle->zone_dh_delete_name, delpath))
1284 			(void) unlink(delpath);
1285 		handle->zone_dh_delete_name[0] = '\0';
1286 	}
1287 
1288 	return (Z_OK);
1289 }
1290 
1291 int
1292 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
1293 {
1294 	int valid;
1295 
1296 	xmlValidCtxt cvp = { NULL };
1297 
1298 	if (zonecfg_check_handle(handle) != Z_OK)
1299 		return (Z_BAD_HANDLE);
1300 
1301 	cvp.error = zonecfg_error_func;
1302 	cvp.warning = zonecfg_error_func;
1303 
1304 	/*
1305 	 * We do a final validation of the document.  Since the library has
1306 	 * malfunctioned if it fails to validate, we follow-up with an
1307 	 * assert() that the doc is valid.
1308 	 */
1309 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1310 	assert(valid != 0);
1311 
1312 	if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
1313 		return (Z_SAVING_FILE);
1314 
1315 	return (Z_OK);
1316 }
1317 
1318 int
1319 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
1320 {
1321 	char zname[ZONENAME_MAX];
1322 	char path[MAXPATHLEN];
1323 	char migpath[MAXPATHLEN];
1324 	xmlValidCtxt cvp = { NULL };
1325 	int err = Z_SAVING_FILE;
1326 	int valid;
1327 
1328 	if (zonecfg_check_handle(handle) != Z_OK)
1329 		return (Z_BAD_HANDLE);
1330 
1331 	/*
1332 	 * We can only detach if we have taken a sw inventory.
1333 	 */
1334 	if (!handle->zone_dh_sw_inv)
1335 		return (Z_INVAL);
1336 
1337 	if (flags & ZONE_DRY_RUN) {
1338 		(void) strlcpy(migpath, "-", sizeof (migpath));
1339 	} else {
1340 		if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
1341 		    != Z_OK)
1342 			return (err);
1343 
1344 		if ((err = zone_get_zonepath(zname, path, sizeof (path)))
1345 		    != Z_OK)
1346 			return (err);
1347 
1348 		if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED)
1349 		    >= sizeof (migpath))
1350 			return (Z_NOMEM);
1351 	}
1352 
1353 	if ((err = operation_prep(handle)) != Z_OK)
1354 		return (err);
1355 
1356 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1357 	    "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1358 
1359 	cvp.error = zonecfg_error_func;
1360 	cvp.warning = zonecfg_error_func;
1361 
1362 	/*
1363 	 * We do a final validation of the document.  Since the library has
1364 	 * malfunctioned if it fails to validate, we follow-up with an
1365 	 * assert() that the doc is valid.
1366 	 */
1367 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1368 	assert(valid != 0);
1369 
1370 	if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1371 		return (Z_SAVING_FILE);
1372 
1373 	if (!(flags & ZONE_DRY_RUN))
1374 		(void) chmod(migpath, 0644);
1375 
1376 	stripcomments(handle);
1377 
1378 	handle->zone_dh_newzone = B_FALSE;
1379 
1380 	return (Z_OK);
1381 }
1382 
1383 boolean_t
1384 zonecfg_detached(const char *path)
1385 {
1386 	char		migpath[MAXPATHLEN];
1387 	struct stat	buf;
1388 
1389 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >=
1390 	    sizeof (migpath))
1391 		return (B_FALSE);
1392 
1393 	if (stat(migpath, &buf) != -1)
1394 		return (B_TRUE);
1395 
1396 	return (B_FALSE);
1397 }
1398 
1399 void
1400 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced)
1401 {
1402 	char zname[ZONENAME_MAX];
1403 	char path[MAXPATHLEN];
1404 	char detached[MAXPATHLEN];
1405 	char attached[MAXPATHLEN];
1406 
1407 	if (zonecfg_check_handle(handle) != Z_OK)
1408 		return;
1409 
1410 	if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK)
1411 		return;
1412 
1413 	if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK)
1414 		return;
1415 
1416 	(void) snprintf(detached, sizeof (detached), "%s/%s", path, DETACHED);
1417 	(void) snprintf(attached, sizeof (attached), "%s/%s", path,
1418 	    ATTACH_FORCED);
1419 
1420 	if (forced) {
1421 		(void) rename(detached, attached);
1422 	} else {
1423 		(void) unlink(attached);
1424 		(void) unlink(detached);
1425 	}
1426 }
1427 
1428 /*
1429  * Special case: if access(2) fails with ENOENT, then try again using
1430  * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
1431  * work around the case of a config file which has not been created yet:
1432  * the user will need access to the directory so use that as a heuristic.
1433  */
1434 
1435 int
1436 zonecfg_access(const char *zonename, int amode)
1437 {
1438 	char path[MAXPATHLEN];
1439 
1440 	if (!config_file_path(zonename, path))
1441 		return (Z_INVAL);
1442 	if (access(path, amode) == 0)
1443 		return (Z_OK);
1444 	if (errno == ENOENT) {
1445 		if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1446 		    ZONE_CONFIG_ROOT) >= sizeof (path))
1447 			return (Z_INVAL);
1448 		if (access(path, amode) == 0)
1449 			return (Z_OK);
1450 	}
1451 	if (errno == EACCES)
1452 		return (Z_ACCES);
1453 	if (errno == EINVAL)
1454 		return (Z_INVAL);
1455 	return (Z_MISC_FS);
1456 }
1457 
1458 int
1459 zonecfg_create_snapshot(const char *zonename)
1460 {
1461 	zone_dochandle_t handle;
1462 	char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
1463 	int error = Z_OK, res;
1464 
1465 	if ((handle = zonecfg_init_handle()) == NULL) {
1466 		return (Z_NOMEM);
1467 	}
1468 
1469 	handle->zone_dh_newzone = B_TRUE;
1470 	handle->zone_dh_snapshot = B_TRUE;
1471 
1472 	if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
1473 		goto out;
1474 	if ((error = operation_prep(handle)) != Z_OK)
1475 		goto out;
1476 	error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
1477 	if (error != Z_OK)
1478 		goto out;
1479 	if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
1480 		error = Z_RESOLVED_PATH;
1481 		goto out;
1482 	}
1483 	/*
1484 	 * If the resolved path is not the same as the original path, then
1485 	 * save the resolved path in the snapshot, thus preventing any
1486 	 * potential problems down the line when zoneadmd goes to unmount
1487 	 * file systems and depends on initial string matches with resolved
1488 	 * paths.
1489 	 */
1490 	rpath[res] = '\0';
1491 	if (strcmp(zonepath, rpath) != 0) {
1492 		if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1493 			goto out;
1494 	}
1495 	if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1496 	    ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1497 		error = Z_MISC_FS;
1498 		goto out;
1499 	}
1500 	if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1501 		error = Z_MISC_FS;
1502 		goto out;
1503 	}
1504 
1505 	if (!snap_file_path(zonename, path)) {
1506 		error = Z_MISC_FS;
1507 		goto out;
1508 	}
1509 
1510 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1511 	    "It is a snapshot of running zone state.\n");
1512 
1513 	error = zonecfg_save_impl(handle, path);
1514 
1515 	stripcomments(handle);
1516 
1517 out:
1518 	zonecfg_fini_handle(handle);
1519 	return (error);
1520 }
1521 
1522 int
1523 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
1524 {
1525 	char property[10]; /* 10 is big enough for "shared"/"exclusive" */
1526 	int err;
1527 
1528 	err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property));
1529 	if (err == Z_BAD_PROPERTY) {
1530 		/* Return default value */
1531 		*iptypep = ZS_SHARED;
1532 		return (Z_OK);
1533 	} else if (err != Z_OK) {
1534 		return (err);
1535 	}
1536 
1537 	if (strlen(property) == 0 ||
1538 	    strcmp(property, "shared") == 0)
1539 		*iptypep = ZS_SHARED;
1540 	else if (strcmp(property, "exclusive") == 0)
1541 		*iptypep = ZS_EXCLUSIVE;
1542 	else
1543 		return (Z_INVAL);
1544 
1545 	return (Z_OK);
1546 }
1547 
1548 int
1549 zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype)
1550 {
1551 	xmlNodePtr cur;
1552 
1553 	if (handle == NULL)
1554 		return (Z_INVAL);
1555 
1556 	cur = xmlDocGetRootElement(handle->zone_dh_doc);
1557 	if (cur == NULL) {
1558 		return (Z_EMPTY_DOCUMENT);
1559 	}
1560 
1561 	if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) {
1562 		return (Z_WRONG_DOC_TYPE);
1563 	}
1564 	switch (iptype) {
1565 	case ZS_SHARED:
1566 		/*
1567 		 * Since "shared" is the default, we don't write it to the
1568 		 * configuration file, so that it's easier to migrate those
1569 		 * zones elsewhere, eg., to systems which are not IP-Instances
1570 		 * aware.
1571 		 * xmlUnsetProp only fails when the attribute doesn't exist,
1572 		 * which we don't care.
1573 		 */
1574 		(void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE);
1575 		break;
1576 	case ZS_EXCLUSIVE:
1577 		if (xmlSetProp(cur, DTD_ATTR_IPTYPE,
1578 		    (const xmlChar *) "exclusive") == NULL)
1579 			return (Z_INVAL);
1580 		break;
1581 	}
1582 	return (Z_OK);
1583 }
1584 
1585 static int
1586 newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
1587 {
1588 	xmlAttrPtr newattr;
1589 
1590 	newattr = xmlNewProp(node, attrname, (xmlChar *)src);
1591 	if (newattr == NULL) {
1592 		xmlUnlinkNode(node);
1593 		xmlFreeNode(node);
1594 		return (Z_BAD_PROPERTY);
1595 	}
1596 	return (Z_OK);
1597 }
1598 
1599 static int
1600 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1601 {
1602 	xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
1603 	zone_fsopt_t *ptr;
1604 	int err;
1605 
1606 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
1607 	if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
1608 	    tabptr->zone_fs_special)) != Z_OK)
1609 		return (err);
1610 	if (tabptr->zone_fs_raw[0] != '\0' &&
1611 	    (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
1612 		return (err);
1613 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1614 		return (err);
1615 	if ((err = newprop(newnode, DTD_ATTR_TYPE,
1616 	    tabptr->zone_fs_type)) != Z_OK)
1617 		return (err);
1618 	if (tabptr->zone_fs_options != NULL) {
1619 		for (ptr = tabptr->zone_fs_options; ptr != NULL;
1620 		    ptr = ptr->zone_fsopt_next) {
1621 			options_node = xmlNewTextChild(newnode, NULL,
1622 			    DTD_ELEM_FSOPTION, NULL);
1623 			if ((err = newprop(options_node, DTD_ATTR_NAME,
1624 			    ptr->zone_fsopt_opt)) != Z_OK)
1625 				return (err);
1626 		}
1627 	}
1628 	return (Z_OK);
1629 }
1630 
1631 int
1632 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1633 {
1634 	int err;
1635 
1636 	if (tabptr == NULL)
1637 		return (Z_INVAL);
1638 
1639 	if ((err = operation_prep(handle)) != Z_OK)
1640 		return (err);
1641 
1642 	if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
1643 		return (err);
1644 
1645 	return (Z_OK);
1646 }
1647 
1648 static int
1649 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1650 {
1651 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
1652 	int err;
1653 
1654 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL);
1655 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1656 		return (err);
1657 	return (Z_OK);
1658 }
1659 
1660 int
1661 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
1662 {
1663 	int err;
1664 
1665 	if (tabptr == NULL)
1666 		return (Z_INVAL);
1667 
1668 	if ((err = operation_prep(handle)) != Z_OK)
1669 		return (err);
1670 
1671 	if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK)
1672 		return (err);
1673 
1674 	return (Z_OK);
1675 }
1676 
1677 int
1678 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
1679 {
1680 	zone_fsopt_t *last, *old, *new;
1681 
1682 	last = tabptr->zone_fs_options;
1683 	for (old = last; old != NULL; old = old->zone_fsopt_next)
1684 		last = old;	/* walk to the end of the list */
1685 	new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
1686 	if (new == NULL)
1687 		return (Z_NOMEM);
1688 	(void) strlcpy(new->zone_fsopt_opt, option,
1689 	    sizeof (new->zone_fsopt_opt));
1690 	new->zone_fsopt_next = NULL;
1691 	if (last == NULL)
1692 		tabptr->zone_fs_options = new;
1693 	else
1694 		last->zone_fsopt_next = new;
1695 	return (Z_OK);
1696 }
1697 
1698 int
1699 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
1700 {
1701 	zone_fsopt_t *last, *this, *next;
1702 
1703 	last = tabptr->zone_fs_options;
1704 	for (this = last; this != NULL; this = this->zone_fsopt_next) {
1705 		if (strcmp(this->zone_fsopt_opt, option) == 0) {
1706 			next = this->zone_fsopt_next;
1707 			if (this == tabptr->zone_fs_options)
1708 				tabptr->zone_fs_options = next;
1709 			else
1710 				last->zone_fsopt_next = next;
1711 			free(this);
1712 			return (Z_OK);
1713 		} else
1714 			last = this;
1715 	}
1716 	return (Z_NO_PROPERTY_ID);
1717 }
1718 
1719 void
1720 zonecfg_free_fs_option_list(zone_fsopt_t *list)
1721 {
1722 	zone_fsopt_t *this, *next;
1723 
1724 	for (this = list; this != NULL; this = next) {
1725 		next = this->zone_fsopt_next;
1726 		free(this);
1727 	}
1728 }
1729 
1730 void
1731 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
1732 {
1733 	if (valtab == NULL)
1734 		return;
1735 	zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
1736 	free(valtab);
1737 }
1738 
1739 static boolean_t
1740 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
1741 {
1742 	xmlChar *gotten_prop;
1743 	int prop_result;
1744 
1745 	gotten_prop = xmlGetProp(cur, attr);
1746 	if (gotten_prop == NULL)	/* shouldn't happen */
1747 		return (B_FALSE);
1748 	prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
1749 	xmlFree(gotten_prop);
1750 	return ((prop_result == 0));
1751 }
1752 
1753 static int
1754 zonecfg_delete_filesystem_core(zone_dochandle_t handle,
1755     struct zone_fstab *tabptr)
1756 {
1757 	xmlNodePtr cur = handle->zone_dh_cur;
1758 	boolean_t dir_match, spec_match, raw_match, type_match;
1759 
1760 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1761 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1762 			continue;
1763 		dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
1764 		spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
1765 		    tabptr->zone_fs_special);
1766 		raw_match = match_prop(cur, DTD_ATTR_RAW,
1767 		    tabptr->zone_fs_raw);
1768 		type_match = match_prop(cur, DTD_ATTR_TYPE,
1769 		    tabptr->zone_fs_type);
1770 		if (dir_match && spec_match && raw_match && type_match) {
1771 			xmlUnlinkNode(cur);
1772 			xmlFreeNode(cur);
1773 			return (Z_OK);
1774 		}
1775 	}
1776 	return (Z_NO_RESOURCE_ID);
1777 }
1778 
1779 int
1780 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1781 {
1782 	int err;
1783 
1784 	if (tabptr == NULL)
1785 		return (Z_INVAL);
1786 
1787 	if ((err = operation_prep(handle)) != Z_OK)
1788 		return (err);
1789 
1790 	if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
1791 		return (err);
1792 
1793 	return (Z_OK);
1794 }
1795 
1796 int
1797 zonecfg_modify_filesystem(
1798 	zone_dochandle_t handle,
1799 	struct zone_fstab *oldtabptr,
1800 	struct zone_fstab *newtabptr)
1801 {
1802 	int err;
1803 
1804 	if (oldtabptr == NULL || newtabptr == NULL)
1805 		return (Z_INVAL);
1806 
1807 	if ((err = operation_prep(handle)) != Z_OK)
1808 		return (err);
1809 
1810 	if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
1811 		return (err);
1812 
1813 	if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
1814 		return (err);
1815 
1816 	return (Z_OK);
1817 }
1818 
1819 static int
1820 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1821 {
1822 	xmlNodePtr cur = handle->zone_dh_cur;
1823 
1824 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1825 		if (xmlStrcmp(cur->name, DTD_ELEM_IPD))
1826 			continue;
1827 		if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) {
1828 			xmlUnlinkNode(cur);
1829 			xmlFreeNode(cur);
1830 			return (Z_OK);
1831 		}
1832 	}
1833 	return (Z_NO_RESOURCE_ID);
1834 }
1835 
1836 int
1837 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
1838 {
1839 	int err;
1840 
1841 	if (tabptr == NULL)
1842 		return (Z_INVAL);
1843 
1844 	if ((err = operation_prep(handle)) != Z_OK)
1845 		return (err);
1846 
1847 	if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK)
1848 		return (err);
1849 
1850 	return (Z_OK);
1851 }
1852 
1853 int
1854 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr,
1855     struct zone_fstab *newtabptr)
1856 {
1857 	int err;
1858 
1859 	if (oldtabptr == NULL || newtabptr == NULL)
1860 		return (Z_INVAL);
1861 
1862 	if ((err = operation_prep(handle)) != Z_OK)
1863 		return (err);
1864 
1865 	if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK)
1866 		return (err);
1867 
1868 	if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK)
1869 		return (err);
1870 
1871 	return (Z_OK);
1872 }
1873 
1874 int
1875 zonecfg_lookup_filesystem(
1876 	zone_dochandle_t handle,
1877 	struct zone_fstab *tabptr)
1878 {
1879 	xmlNodePtr cur, options, firstmatch;
1880 	int err;
1881 	char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
1882 	char type[FSTYPSZ];
1883 	char options_str[MAX_MNTOPT_STR];
1884 
1885 	if (tabptr == NULL)
1886 		return (Z_INVAL);
1887 
1888 	if ((err = operation_prep(handle)) != Z_OK)
1889 		return (err);
1890 
1891 	/*
1892 	 * Walk the list of children looking for matches on any properties
1893 	 * specified in the fstab parameter.  If more than one resource
1894 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1895 	 * Z_NO_RESOURCE_ID.
1896 	 */
1897 	cur = handle->zone_dh_cur;
1898 	firstmatch = NULL;
1899 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1900 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1901 			continue;
1902 		if (strlen(tabptr->zone_fs_dir) > 0) {
1903 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1904 			    sizeof (dirname)) == Z_OK) &&
1905 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1906 				if (firstmatch == NULL)
1907 					firstmatch = cur;
1908 				else
1909 					return (Z_INSUFFICIENT_SPEC);
1910 			}
1911 		}
1912 		if (strlen(tabptr->zone_fs_special) > 0) {
1913 			if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
1914 			    sizeof (special)) == Z_OK)) {
1915 				if (strcmp(tabptr->zone_fs_special,
1916 				    special) == 0) {
1917 					if (firstmatch == NULL)
1918 						firstmatch = cur;
1919 					else if (firstmatch != cur)
1920 						return (Z_INSUFFICIENT_SPEC);
1921 				} else {
1922 					/*
1923 					 * If another property matched but this
1924 					 * one doesn't then reset firstmatch.
1925 					 */
1926 					if (firstmatch == cur)
1927 						firstmatch = NULL;
1928 				}
1929 			}
1930 		}
1931 		if (strlen(tabptr->zone_fs_raw) > 0) {
1932 			if ((fetchprop(cur, DTD_ATTR_RAW, raw,
1933 			    sizeof (raw)) == Z_OK)) {
1934 				if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
1935 					if (firstmatch == NULL)
1936 						firstmatch = cur;
1937 					else if (firstmatch != cur)
1938 						return (Z_INSUFFICIENT_SPEC);
1939 				} else {
1940 					/*
1941 					 * If another property matched but this
1942 					 * one doesn't then reset firstmatch.
1943 					 */
1944 					if (firstmatch == cur)
1945 						firstmatch = NULL;
1946 				}
1947 			}
1948 		}
1949 		if (strlen(tabptr->zone_fs_type) > 0) {
1950 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
1951 			    sizeof (type)) == Z_OK)) {
1952 				if (strcmp(tabptr->zone_fs_type, type) == 0) {
1953 					if (firstmatch == NULL)
1954 						firstmatch = cur;
1955 					else if (firstmatch != cur)
1956 						return (Z_INSUFFICIENT_SPEC);
1957 				} else {
1958 					/*
1959 					 * If another property matched but this
1960 					 * one doesn't then reset firstmatch.
1961 					 */
1962 					if (firstmatch == cur)
1963 						firstmatch = NULL;
1964 				}
1965 			}
1966 		}
1967 	}
1968 
1969 	if (firstmatch == NULL)
1970 		return (Z_NO_RESOURCE_ID);
1971 
1972 	cur = firstmatch;
1973 
1974 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1975 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
1976 		return (err);
1977 
1978 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
1979 	    sizeof (tabptr->zone_fs_special))) != Z_OK)
1980 		return (err);
1981 
1982 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
1983 	    sizeof (tabptr->zone_fs_raw))) != Z_OK)
1984 		return (err);
1985 
1986 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
1987 	    sizeof (tabptr->zone_fs_type))) != Z_OK)
1988 		return (err);
1989 
1990 	/* options are optional */
1991 	tabptr->zone_fs_options = NULL;
1992 	for (options = cur->xmlChildrenNode; options != NULL;
1993 	    options = options->next) {
1994 		if ((fetchprop(options, DTD_ATTR_NAME, options_str,
1995 		    sizeof (options_str)) != Z_OK))
1996 			break;
1997 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
1998 			break;
1999 	}
2000 	return (Z_OK);
2001 }
2002 
2003 int
2004 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
2005 {
2006 	xmlNodePtr cur, match;
2007 	int err;
2008 	char dirname[MAXPATHLEN];
2009 
2010 	if (tabptr == NULL)
2011 		return (Z_INVAL);
2012 
2013 	if ((err = operation_prep(handle)) != Z_OK)
2014 		return (err);
2015 
2016 	/*
2017 	 * General algorithm:
2018 	 * Walk the list of children looking for matches on any properties
2019 	 * specified in the fstab parameter.  If more than one resource
2020 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
2021 	 * Z_NO_RESOURCE_ID.
2022 	 */
2023 	cur = handle->zone_dh_cur;
2024 	match = NULL;
2025 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2026 		if (xmlStrcmp(cur->name, DTD_ELEM_IPD))
2027 			continue;
2028 		if (strlen(tabptr->zone_fs_dir) > 0) {
2029 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
2030 			    sizeof (dirname)) == Z_OK) &&
2031 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
2032 				if (match == NULL)
2033 					match = cur;
2034 				else
2035 					return (Z_INSUFFICIENT_SPEC);
2036 			}
2037 		}
2038 	}
2039 
2040 	if (match == NULL)
2041 		return (Z_NO_RESOURCE_ID);
2042 
2043 	cur = match;
2044 
2045 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
2046 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
2047 		return (err);
2048 
2049 	return (Z_OK);
2050 }
2051 
2052 /*
2053  * Compare two IP addresses in string form.  Allow for the possibility that
2054  * one might have "/<prefix-length>" at the end: allow a match on just the
2055  * IP address (or host name) part.
2056  */
2057 
2058 boolean_t
2059 zonecfg_same_net_address(char *a1, char *a2)
2060 {
2061 	char *slashp, *slashp1, *slashp2;
2062 	int result;
2063 
2064 	if (strcmp(a1, a2) == 0)
2065 		return (B_TRUE);
2066 
2067 	/*
2068 	 * If neither has a slash or both do, they need to match to be
2069 	 * considered the same, but they did not match above, so fail.
2070 	 */
2071 	slashp1 = strchr(a1, '/');
2072 	slashp2 = strchr(a2, '/');
2073 	if ((slashp1 == NULL && slashp2 == NULL) ||
2074 	    (slashp1 != NULL && slashp2 != NULL))
2075 		return (B_FALSE);
2076 
2077 	/*
2078 	 * Only one had a slash: pick that one, zero out the slash, compare
2079 	 * the "address only" strings, restore the slash, and return the
2080 	 * result of the comparison.
2081 	 */
2082 	slashp = (slashp1 == NULL) ? slashp2 : slashp1;
2083 	*slashp = '\0';
2084 	result = strcmp(a1, a2);
2085 	*slashp = '/';
2086 	return ((result == 0));
2087 }
2088 
2089 int
2090 zonecfg_valid_net_address(char *address, struct lifreq *lifr)
2091 {
2092 	struct sockaddr_in *sin4;
2093 	struct sockaddr_in6 *sin6;
2094 	struct addrinfo hints, *result;
2095 	char *slashp = strchr(address, '/');
2096 
2097 	bzero(lifr, sizeof (struct lifreq));
2098 	sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
2099 	sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
2100 	if (slashp != NULL)
2101 		*slashp = '\0';
2102 	if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
2103 		sin4->sin_family = AF_INET;
2104 	} else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
2105 		if (slashp == NULL)
2106 			return (Z_IPV6_ADDR_PREFIX_LEN);
2107 		sin6->sin6_family = AF_INET6;
2108 	} else {
2109 		/* "address" may be a host name */
2110 		(void) memset(&hints, 0, sizeof (hints));
2111 		hints.ai_family = PF_INET;
2112 		if (getaddrinfo(address, NULL, &hints, &result) != 0)
2113 			return (Z_BOGUS_ADDRESS);
2114 		sin4->sin_family = result->ai_family;
2115 
2116 		(void) memcpy(&sin4->sin_addr,
2117 		    /* LINTED E_BAD_PTR_CAST_ALIGN */
2118 		    &((struct sockaddr_in *)result->ai_addr)->sin_addr,
2119 		    sizeof (struct in_addr));
2120 
2121 		freeaddrinfo(result);
2122 	}
2123 	return (Z_OK);
2124 }
2125 
2126 boolean_t
2127 zonecfg_ifname_exists(sa_family_t af, char *ifname)
2128 {
2129 	struct lifreq lifr;
2130 	int so;
2131 	int save_errno;
2132 
2133 	(void) memset(&lifr, 0, sizeof (lifr));
2134 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2135 	lifr.lifr_addr.ss_family = af;
2136 	if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
2137 		/* Odd - can't tell if the ifname exists */
2138 		return (B_FALSE);
2139 	}
2140 	if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2141 		save_errno = errno;
2142 		(void) close(so);
2143 		errno = save_errno;
2144 		return (B_FALSE);
2145 	}
2146 	(void) close(so);
2147 	return (B_TRUE);
2148 }
2149 
2150 int
2151 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2152 {
2153 	xmlNodePtr cur, firstmatch;
2154 	int err;
2155 	char address[INET6_ADDRSTRLEN], physical[LIFNAMSIZ];
2156 
2157 	if (tabptr == NULL)
2158 		return (Z_INVAL);
2159 
2160 	if ((err = operation_prep(handle)) != Z_OK)
2161 		return (err);
2162 
2163 	cur = handle->zone_dh_cur;
2164 	firstmatch = NULL;
2165 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2166 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2167 			continue;
2168 		if (strlen(tabptr->zone_nwif_physical) > 0) {
2169 			if ((fetchprop(cur, DTD_ATTR_PHYSICAL, physical,
2170 			    sizeof (physical)) == Z_OK) &&
2171 			    (strcmp(tabptr->zone_nwif_physical,
2172 			    physical) == 0)) {
2173 				if (firstmatch == NULL)
2174 					firstmatch = cur;
2175 				else
2176 					return (Z_INSUFFICIENT_SPEC);
2177 			}
2178 		}
2179 		if (strlen(tabptr->zone_nwif_address) > 0) {
2180 			if ((fetchprop(cur, DTD_ATTR_ADDRESS, address,
2181 			    sizeof (address)) == Z_OK)) {
2182 				if (zonecfg_same_net_address(
2183 				    tabptr->zone_nwif_address, address)) {
2184 					if (firstmatch == NULL)
2185 						firstmatch = cur;
2186 					else if (firstmatch != cur)
2187 						return (Z_INSUFFICIENT_SPEC);
2188 				} else {
2189 					/*
2190 					 * If another property matched but this
2191 					 * one doesn't then reset firstmatch.
2192 					 */
2193 					if (firstmatch == cur)
2194 						firstmatch = NULL;
2195 				}
2196 			}
2197 		}
2198 	}
2199 	if (firstmatch == NULL)
2200 		return (Z_NO_RESOURCE_ID);
2201 
2202 	cur = firstmatch;
2203 
2204 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2205 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK)
2206 		return (err);
2207 
2208 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2209 	    sizeof (tabptr->zone_nwif_address))) != Z_OK)
2210 		return (err);
2211 
2212 	return (Z_OK);
2213 }
2214 
2215 static int
2216 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2217 {
2218 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2219 	int err;
2220 
2221 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
2222 	if ((err = newprop(newnode, DTD_ATTR_ADDRESS,
2223 	    tabptr->zone_nwif_address)) != Z_OK)
2224 		return (err);
2225 	if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
2226 	    tabptr->zone_nwif_physical)) != Z_OK)
2227 		return (err);
2228 	return (Z_OK);
2229 }
2230 
2231 int
2232 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2233 {
2234 	int err;
2235 
2236 	if (tabptr == NULL)
2237 		return (Z_INVAL);
2238 
2239 	if ((err = operation_prep(handle)) != Z_OK)
2240 		return (err);
2241 
2242 	if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2243 		return (err);
2244 
2245 	return (Z_OK);
2246 }
2247 
2248 static int
2249 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2250 {
2251 	xmlNodePtr cur = handle->zone_dh_cur;
2252 	boolean_t addr_match, phys_match;
2253 
2254 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2255 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2256 			continue;
2257 
2258 		addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2259 		    tabptr->zone_nwif_address);
2260 		phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2261 		    tabptr->zone_nwif_physical);
2262 
2263 		if (addr_match && phys_match) {
2264 			xmlUnlinkNode(cur);
2265 			xmlFreeNode(cur);
2266 			return (Z_OK);
2267 		}
2268 	}
2269 	return (Z_NO_RESOURCE_ID);
2270 }
2271 
2272 int
2273 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2274 {
2275 	int err;
2276 
2277 	if (tabptr == NULL)
2278 		return (Z_INVAL);
2279 
2280 	if ((err = operation_prep(handle)) != Z_OK)
2281 		return (err);
2282 
2283 	if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
2284 		return (err);
2285 
2286 	return (Z_OK);
2287 }
2288 
2289 int
2290 zonecfg_modify_nwif(
2291 	zone_dochandle_t handle,
2292 	struct zone_nwiftab *oldtabptr,
2293 	struct zone_nwiftab *newtabptr)
2294 {
2295 	int err;
2296 
2297 	if (oldtabptr == NULL || newtabptr == NULL)
2298 		return (Z_INVAL);
2299 
2300 	if ((err = operation_prep(handle)) != Z_OK)
2301 		return (err);
2302 
2303 	if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2304 		return (err);
2305 
2306 	if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2307 		return (err);
2308 
2309 	return (Z_OK);
2310 }
2311 
2312 int
2313 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2314 {
2315 	xmlNodePtr cur, firstmatch;
2316 	int err;
2317 	char match[MAXPATHLEN];
2318 
2319 	if (tabptr == NULL)
2320 		return (Z_INVAL);
2321 
2322 	if ((err = operation_prep(handle)) != Z_OK)
2323 		return (err);
2324 
2325 	cur = handle->zone_dh_cur;
2326 	firstmatch = NULL;
2327 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2328 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2329 			continue;
2330 		if (strlen(tabptr->zone_dev_match) == 0)
2331 			continue;
2332 
2333 		if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2334 		    sizeof (match)) == Z_OK)) {
2335 			if (strcmp(tabptr->zone_dev_match,
2336 			    match) == 0) {
2337 				if (firstmatch == NULL)
2338 					firstmatch = cur;
2339 				else if (firstmatch != cur)
2340 					return (Z_INSUFFICIENT_SPEC);
2341 			} else {
2342 				/*
2343 				 * If another property matched but this
2344 				 * one doesn't then reset firstmatch.
2345 				 */
2346 				if (firstmatch == cur)
2347 					firstmatch = NULL;
2348 			}
2349 		}
2350 	}
2351 	if (firstmatch == NULL)
2352 		return (Z_NO_RESOURCE_ID);
2353 
2354 	cur = firstmatch;
2355 
2356 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2357 	    sizeof (tabptr->zone_dev_match))) != Z_OK)
2358 		return (err);
2359 
2360 	return (Z_OK);
2361 }
2362 
2363 static int
2364 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2365 {
2366 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2367 	int err;
2368 
2369 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2370 
2371 	if ((err = newprop(newnode, DTD_ATTR_MATCH,
2372 	    tabptr->zone_dev_match)) != Z_OK)
2373 		return (err);
2374 
2375 	return (Z_OK);
2376 }
2377 
2378 int
2379 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2380 {
2381 	int err;
2382 
2383 	if (tabptr == NULL)
2384 		return (Z_INVAL);
2385 
2386 	if ((err = operation_prep(handle)) != Z_OK)
2387 		return (err);
2388 
2389 	if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2390 		return (err);
2391 
2392 	return (Z_OK);
2393 }
2394 
2395 static int
2396 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2397 {
2398 	xmlNodePtr cur = handle->zone_dh_cur;
2399 	int match_match;
2400 
2401 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2402 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2403 			continue;
2404 
2405 		match_match = match_prop(cur, DTD_ATTR_MATCH,
2406 		    tabptr->zone_dev_match);
2407 
2408 		if (match_match) {
2409 			xmlUnlinkNode(cur);
2410 			xmlFreeNode(cur);
2411 			return (Z_OK);
2412 		}
2413 	}
2414 	return (Z_NO_RESOURCE_ID);
2415 }
2416 
2417 int
2418 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2419 {
2420 	int err;
2421 
2422 	if (tabptr == NULL)
2423 		return (Z_INVAL);
2424 
2425 	if ((err = operation_prep(handle)) != Z_OK)
2426 		return (err);
2427 
2428 	if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
2429 		return (err);
2430 
2431 	return (Z_OK);
2432 }
2433 
2434 int
2435 zonecfg_modify_dev(
2436 	zone_dochandle_t handle,
2437 	struct zone_devtab *oldtabptr,
2438 	struct zone_devtab *newtabptr)
2439 {
2440 	int err;
2441 
2442 	if (oldtabptr == NULL || newtabptr == NULL)
2443 		return (Z_INVAL);
2444 
2445 	if ((err = operation_prep(handle)) != Z_OK)
2446 		return (err);
2447 
2448 	if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
2449 		return (err);
2450 
2451 	if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
2452 		return (err);
2453 
2454 	return (Z_OK);
2455 }
2456 
2457 /* Lock to serialize all zonecfg_devwalks */
2458 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
2459 /*
2460  * Global variables used to pass data from zonecfg_devwalk to the nftw
2461  * call-back (zonecfg_devwalk_cb).  g_devwalk_data is really the void*
2462  * parameter and g_devwalk_cb is really the *cb parameter from zonecfg_devwalk.
2463  */
2464 static void *g_devwalk_data;
2465 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *,
2466     void *);
2467 static size_t g_devwalk_skip_prefix;
2468 
2469 /*
2470  * This is the nftw call-back function used by zonecfg_devwalk.  It is
2471  * responsible for calling the actual call-back that is passed in to
2472  * zonecfg_devwalk as the *cb argument.
2473  */
2474 /* ARGSUSED2 */
2475 static int
2476 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f,
2477     struct FTW *ftw)
2478 {
2479 	acl_t *acl;
2480 	char *acl_txt = NULL;
2481 
2482 	/* skip all but character and block devices */
2483 	if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
2484 		return (0);
2485 
2486 	if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) &&
2487 	    acl != NULL) {
2488 		acl_txt = acl_totext(acl, ACL_NORESOLVE);
2489 		acl_free(acl);
2490 	}
2491 
2492 	if (strlen(path) <= g_devwalk_skip_prefix)
2493 		return (0);
2494 
2495 	g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid,
2496 	    st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "",
2497 	    g_devwalk_data);
2498 	free(acl_txt);
2499 	return (0);
2500 }
2501 
2502 /*
2503  * Walk the dev tree for the zone specified by hdl and call the call-back (cb)
2504  * function for each entry in the tree.  The call-back will be passed the
2505  * name, uid, gid, mode, acl string and the void *data input parameter
2506  * for each dev entry.
2507  *
2508  * Data is passed to the zonecfg_devwalk_cb through the global variables
2509  * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix.  The
2510  * zonecfg_devwalk_cb function will actually call *cb.
2511  */
2512 int
2513 zonecfg_devwalk(zone_dochandle_t hdl,
2514     int (*cb)(const char *, uid_t, gid_t, mode_t, const char *, void *),
2515     void *data)
2516 {
2517 	char path[MAXPATHLEN];
2518 	int ret;
2519 
2520 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
2521 		return (ret);
2522 
2523 	if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path))
2524 		return (Z_TOO_BIG);
2525 	g_devwalk_skip_prefix = strlen(path) + 1;
2526 
2527 	/*
2528 	 * We have to serialize all zonecfg_devwalks in the same process
2529 	 * (which should be fine), since nftw() is so badly designed.
2530 	 */
2531 	(void) pthread_mutex_lock(&zonecfg_devwalk_lock);
2532 
2533 	g_devwalk_data = data;
2534 	g_devwalk_cb = cb;
2535 	(void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS);
2536 
2537 	(void) pthread_mutex_unlock(&zonecfg_devwalk_lock);
2538 	return (Z_OK);
2539 }
2540 
2541 /*
2542  * Update the owner, group, mode and acl on the specified dev (inpath) for
2543  * the zone (hdl).  This function can be used to fix up the dev tree after
2544  * attaching a migrated zone.
2545  */
2546 int
2547 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner,
2548     gid_t group, mode_t mode, const char *acltxt)
2549 {
2550 	int ret;
2551 	char path[MAXPATHLEN];
2552 	struct stat st;
2553 	acl_t *aclp;
2554 
2555 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
2556 		return (ret);
2557 
2558 	if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path))
2559 		return (Z_TOO_BIG);
2560 	if (strlcat(path, inpath, sizeof (path)) >= sizeof (path))
2561 		return (Z_TOO_BIG);
2562 
2563 	if (stat(path, &st) == -1)
2564 		return (Z_INVAL);
2565 
2566 	/* make sure we're only touching device nodes */
2567 	if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
2568 		return (Z_INVAL);
2569 
2570 	if (chown(path, owner, group) == -1)
2571 		return (Z_SYSTEM);
2572 
2573 	if (chmod(path, mode) == -1)
2574 		return (Z_SYSTEM);
2575 
2576 	if ((acltxt == NULL) || (strcmp(acltxt, "") == 0))
2577 		return (Z_OK);
2578 
2579 	if (acl_fromtext(acltxt, &aclp) != 0)
2580 		return (Z_SYSTEM);
2581 
2582 	errno = 0;
2583 	if (acl_set(path, aclp) == -1) {
2584 		free(aclp);
2585 		return (Z_SYSTEM);
2586 	}
2587 
2588 	free(aclp);
2589 	return (Z_OK);
2590 }
2591 
2592 /*
2593  * This function finds everything mounted under a zone's rootpath.
2594  * This returns the number of mounts under rootpath, or -1 on error.
2595  * callback is called once per mount found with the first argument
2596  * pointing to the  mount point.
2597  *
2598  * If the callback function returns non-zero zonecfg_find_mounts
2599  * aborts with an error.
2600  */
2601 int
2602 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *),
2603     void *priv) {
2604 	FILE *mnttab;
2605 	struct mnttab m;
2606 	size_t l;
2607 	int zfsl;
2608 	int rv = 0;
2609 	char zfs_path[MAXPATHLEN];
2610 
2611 	assert(rootpath != NULL);
2612 
2613 	if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath))
2614 	    >= sizeof (zfs_path))
2615 		return (-1);
2616 
2617 	l = strlen(rootpath);
2618 
2619 	mnttab = fopen("/etc/mnttab", "r");
2620 
2621 	if (mnttab == NULL)
2622 		return (-1);
2623 
2624 	if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0)  {
2625 		rv = -1;
2626 		goto out;
2627 	}
2628 
2629 	while (!getmntent(mnttab, &m)) {
2630 		if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
2631 		    (m.mnt_mountp[l] == '/') &&
2632 		    (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) {
2633 			rv++;
2634 			if (callback == NULL)
2635 				continue;
2636 			if (callback(m.mnt_mountp, priv)) {
2637 				rv = -1;
2638 				goto out;
2639 
2640 			}
2641 		}
2642 	}
2643 
2644 out:
2645 	(void) fclose(mnttab);
2646 	return (rv);
2647 }
2648 
2649 int
2650 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2651 {
2652 	xmlNodePtr cur, firstmatch;
2653 	int err;
2654 	char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
2655 
2656 	if (tabptr == NULL)
2657 		return (Z_INVAL);
2658 
2659 	if ((err = operation_prep(handle)) != Z_OK)
2660 		return (err);
2661 
2662 	cur = handle->zone_dh_cur;
2663 	firstmatch = NULL;
2664 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2665 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
2666 			continue;
2667 		if (strlen(tabptr->zone_attr_name) > 0) {
2668 			if ((fetchprop(cur, DTD_ATTR_NAME, name,
2669 			    sizeof (name)) == Z_OK) &&
2670 			    (strcmp(tabptr->zone_attr_name, name) == 0)) {
2671 				if (firstmatch == NULL)
2672 					firstmatch = cur;
2673 				else
2674 					return (Z_INSUFFICIENT_SPEC);
2675 			}
2676 		}
2677 		if (strlen(tabptr->zone_attr_type) > 0) {
2678 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
2679 			    sizeof (type)) == Z_OK)) {
2680 				if (strcmp(tabptr->zone_attr_type, type) == 0) {
2681 					if (firstmatch == NULL)
2682 						firstmatch = cur;
2683 					else if (firstmatch != cur)
2684 						return (Z_INSUFFICIENT_SPEC);
2685 				} else {
2686 					/*
2687 					 * If another property matched but this
2688 					 * one doesn't then reset firstmatch.
2689 					 */
2690 					if (firstmatch == cur)
2691 						firstmatch = NULL;
2692 				}
2693 			}
2694 		}
2695 		if (strlen(tabptr->zone_attr_value) > 0) {
2696 			if ((fetchprop(cur, DTD_ATTR_VALUE, value,
2697 			    sizeof (value)) == Z_OK)) {
2698 				if (strcmp(tabptr->zone_attr_value, value) ==
2699 				    0) {
2700 					if (firstmatch == NULL)
2701 						firstmatch = cur;
2702 					else if (firstmatch != cur)
2703 						return (Z_INSUFFICIENT_SPEC);
2704 				} else {
2705 					/*
2706 					 * If another property matched but this
2707 					 * one doesn't then reset firstmatch.
2708 					 */
2709 					if (firstmatch == cur)
2710 						firstmatch = NULL;
2711 				}
2712 			}
2713 		}
2714 	}
2715 	if (firstmatch == NULL)
2716 		return (Z_NO_RESOURCE_ID);
2717 
2718 	cur = firstmatch;
2719 
2720 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
2721 	    sizeof (tabptr->zone_attr_name))) != Z_OK)
2722 		return (err);
2723 
2724 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
2725 	    sizeof (tabptr->zone_attr_type))) != Z_OK)
2726 		return (err);
2727 
2728 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
2729 	    sizeof (tabptr->zone_attr_value))) != Z_OK)
2730 		return (err);
2731 
2732 	return (Z_OK);
2733 }
2734 
2735 static int
2736 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2737 {
2738 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2739 	int err;
2740 
2741 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
2742 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
2743 	if (err != Z_OK)
2744 		return (err);
2745 	err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
2746 	if (err != Z_OK)
2747 		return (err);
2748 	err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
2749 	if (err != Z_OK)
2750 		return (err);
2751 	return (Z_OK);
2752 }
2753 
2754 int
2755 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2756 {
2757 	int err;
2758 
2759 	if (tabptr == NULL)
2760 		return (Z_INVAL);
2761 
2762 	if ((err = operation_prep(handle)) != Z_OK)
2763 		return (err);
2764 
2765 	if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
2766 		return (err);
2767 
2768 	return (Z_OK);
2769 }
2770 
2771 static int
2772 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2773 {
2774 	xmlNodePtr cur = handle->zone_dh_cur;
2775 	int name_match, type_match, value_match;
2776 
2777 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2778 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
2779 			continue;
2780 
2781 		name_match = match_prop(cur, DTD_ATTR_NAME,
2782 		    tabptr->zone_attr_name);
2783 		type_match = match_prop(cur, DTD_ATTR_TYPE,
2784 		    tabptr->zone_attr_type);
2785 		value_match = match_prop(cur, DTD_ATTR_VALUE,
2786 		    tabptr->zone_attr_value);
2787 
2788 		if (name_match && type_match && value_match) {
2789 			xmlUnlinkNode(cur);
2790 			xmlFreeNode(cur);
2791 			return (Z_OK);
2792 		}
2793 	}
2794 	return (Z_NO_RESOURCE_ID);
2795 }
2796 
2797 int
2798 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2799 {
2800 	int err;
2801 
2802 	if (tabptr == NULL)
2803 		return (Z_INVAL);
2804 
2805 	if ((err = operation_prep(handle)) != Z_OK)
2806 		return (err);
2807 
2808 	if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
2809 		return (err);
2810 
2811 	return (Z_OK);
2812 }
2813 
2814 int
2815 zonecfg_modify_attr(
2816 	zone_dochandle_t handle,
2817 	struct zone_attrtab *oldtabptr,
2818 	struct zone_attrtab *newtabptr)
2819 {
2820 	int err;
2821 
2822 	if (oldtabptr == NULL || newtabptr == NULL)
2823 		return (Z_INVAL);
2824 
2825 	if ((err = operation_prep(handle)) != Z_OK)
2826 		return (err);
2827 
2828 	if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK)
2829 		return (err);
2830 
2831 	if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK)
2832 		return (err);
2833 
2834 	return (Z_OK);
2835 }
2836 
2837 int
2838 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value)
2839 {
2840 	if (attr == NULL)
2841 		return (Z_INVAL);
2842 
2843 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0)
2844 		return (Z_INVAL);
2845 
2846 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) {
2847 		*value = B_TRUE;
2848 		return (Z_OK);
2849 	}
2850 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) {
2851 		*value = B_FALSE;
2852 		return (Z_OK);
2853 	}
2854 	return (Z_INVAL);
2855 }
2856 
2857 int
2858 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value)
2859 {
2860 	long long result;
2861 	char *endptr;
2862 
2863 	if (attr == NULL)
2864 		return (Z_INVAL);
2865 
2866 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0)
2867 		return (Z_INVAL);
2868 
2869 	errno = 0;
2870 	result = strtoll(attr->zone_attr_value, &endptr, 10);
2871 	if (errno != 0 || *endptr != '\0')
2872 		return (Z_INVAL);
2873 	*value = result;
2874 	return (Z_OK);
2875 }
2876 
2877 int
2878 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value,
2879     size_t val_sz)
2880 {
2881 	if (attr == NULL)
2882 		return (Z_INVAL);
2883 
2884 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0)
2885 		return (Z_INVAL);
2886 
2887 	if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz)
2888 		return (Z_TOO_BIG);
2889 	return (Z_OK);
2890 }
2891 
2892 int
2893 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value)
2894 {
2895 	unsigned long long result;
2896 	long long neg_result;
2897 	char *endptr;
2898 
2899 	if (attr == NULL)
2900 		return (Z_INVAL);
2901 
2902 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0)
2903 		return (Z_INVAL);
2904 
2905 	errno = 0;
2906 	result = strtoull(attr->zone_attr_value, &endptr, 10);
2907 	if (errno != 0 || *endptr != '\0')
2908 		return (Z_INVAL);
2909 	errno = 0;
2910 	neg_result = strtoll(attr->zone_attr_value, &endptr, 10);
2911 	/*
2912 	 * Incredibly, strtoull("<negative number>", ...) will not fail but
2913 	 * return whatever (negative) number cast as a u_longlong_t, so we
2914 	 * need to look for this here.
2915 	 */
2916 	if (errno == 0 && neg_result < 0)
2917 		return (Z_INVAL);
2918 	*value = result;
2919 	return (Z_OK);
2920 }
2921 
2922 int
2923 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2924 {
2925 	xmlNodePtr cur, val;
2926 	char savedname[MAXNAMELEN];
2927 	struct zone_rctlvaltab *valptr;
2928 	int err;
2929 
2930 	if (tabptr->zone_rctl_name == NULL ||
2931 	    strlen(tabptr->zone_rctl_name) == 0)
2932 		return (Z_INVAL);
2933 
2934 	if ((err = operation_prep(handle)) != Z_OK)
2935 		return (err);
2936 
2937 	cur = handle->zone_dh_cur;
2938 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2939 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
2940 			continue;
2941 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
2942 		    sizeof (savedname)) == Z_OK) &&
2943 		    (strcmp(savedname, tabptr->zone_rctl_name) == 0)) {
2944 			tabptr->zone_rctl_valptr = NULL;
2945 			for (val = cur->xmlChildrenNode; val != NULL;
2946 			    val = val->next) {
2947 				valptr = (struct zone_rctlvaltab *)malloc(
2948 				    sizeof (struct zone_rctlvaltab));
2949 				if (valptr == NULL)
2950 					return (Z_NOMEM);
2951 				if ((fetchprop(val, DTD_ATTR_PRIV,
2952 				    valptr->zone_rctlval_priv,
2953 				    sizeof (valptr->zone_rctlval_priv)) !=
2954 				    Z_OK))
2955 					break;
2956 				if ((fetchprop(val, DTD_ATTR_LIMIT,
2957 				    valptr->zone_rctlval_limit,
2958 				    sizeof (valptr->zone_rctlval_limit)) !=
2959 				    Z_OK))
2960 					break;
2961 				if ((fetchprop(val, DTD_ATTR_ACTION,
2962 				    valptr->zone_rctlval_action,
2963 				    sizeof (valptr->zone_rctlval_action)) !=
2964 				    Z_OK))
2965 					break;
2966 				if (zonecfg_add_rctl_value(tabptr, valptr) !=
2967 				    Z_OK)
2968 					break;
2969 			}
2970 			return (Z_OK);
2971 		}
2972 	}
2973 	return (Z_NO_RESOURCE_ID);
2974 }
2975 
2976 static int
2977 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2978 {
2979 	xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
2980 	struct zone_rctlvaltab *valptr;
2981 	int err;
2982 
2983 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL);
2984 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name);
2985 	if (err != Z_OK)
2986 		return (err);
2987 	for (valptr = tabptr->zone_rctl_valptr; valptr != NULL;
2988 	    valptr = valptr->zone_rctlval_next) {
2989 		valnode = xmlNewTextChild(newnode, NULL,
2990 		    DTD_ELEM_RCTLVALUE, NULL);
2991 		err = newprop(valnode, DTD_ATTR_PRIV,
2992 		    valptr->zone_rctlval_priv);
2993 		if (err != Z_OK)
2994 			return (err);
2995 		err = newprop(valnode, DTD_ATTR_LIMIT,
2996 		    valptr->zone_rctlval_limit);
2997 		if (err != Z_OK)
2998 			return (err);
2999 		err = newprop(valnode, DTD_ATTR_ACTION,
3000 		    valptr->zone_rctlval_action);
3001 		if (err != Z_OK)
3002 			return (err);
3003 	}
3004 	return (Z_OK);
3005 }
3006 
3007 int
3008 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3009 {
3010 	int err;
3011 
3012 	if (tabptr == NULL || tabptr->zone_rctl_name == NULL)
3013 		return (Z_INVAL);
3014 
3015 	if ((err = operation_prep(handle)) != Z_OK)
3016 		return (err);
3017 
3018 	if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK)
3019 		return (err);
3020 
3021 	return (Z_OK);
3022 }
3023 
3024 static int
3025 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3026 {
3027 	xmlNodePtr cur = handle->zone_dh_cur;
3028 	xmlChar *savedname;
3029 	int name_result;
3030 
3031 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3032 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
3033 			continue;
3034 
3035 		savedname = xmlGetProp(cur, DTD_ATTR_NAME);
3036 		if (savedname == NULL)	/* shouldn't happen */
3037 			continue;
3038 		name_result = xmlStrcmp(savedname,
3039 		    (const xmlChar *) tabptr->zone_rctl_name);
3040 		xmlFree(savedname);
3041 
3042 		if (name_result == 0) {
3043 			xmlUnlinkNode(cur);
3044 			xmlFreeNode(cur);
3045 			return (Z_OK);
3046 		}
3047 	}
3048 	return (Z_NO_RESOURCE_ID);
3049 }
3050 
3051 int
3052 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3053 {
3054 	int err;
3055 
3056 	if (tabptr == NULL || tabptr->zone_rctl_name == NULL)
3057 		return (Z_INVAL);
3058 
3059 	if ((err = operation_prep(handle)) != Z_OK)
3060 		return (err);
3061 
3062 	if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK)
3063 		return (err);
3064 
3065 	return (Z_OK);
3066 }
3067 
3068 int
3069 zonecfg_modify_rctl(
3070 	zone_dochandle_t handle,
3071 	struct zone_rctltab *oldtabptr,
3072 	struct zone_rctltab *newtabptr)
3073 {
3074 	int err;
3075 
3076 	if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL ||
3077 	    newtabptr == NULL || newtabptr->zone_rctl_name == NULL)
3078 		return (Z_INVAL);
3079 
3080 	if ((err = operation_prep(handle)) != Z_OK)
3081 		return (err);
3082 
3083 	if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK)
3084 		return (err);
3085 
3086 	if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK)
3087 		return (err);
3088 
3089 	return (Z_OK);
3090 }
3091 
3092 int
3093 zonecfg_add_rctl_value(
3094 	struct zone_rctltab *tabptr,
3095 	struct zone_rctlvaltab *valtabptr)
3096 {
3097 	struct zone_rctlvaltab *last, *old, *new;
3098 	rctlblk_t *rctlblk = alloca(rctlblk_size());
3099 
3100 	last = tabptr->zone_rctl_valptr;
3101 	for (old = last; old != NULL; old = old->zone_rctlval_next)
3102 		last = old;	/* walk to the end of the list */
3103 	new = valtabptr;	/* alloc'd by caller */
3104 	new->zone_rctlval_next = NULL;
3105 	if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK)
3106 		return (Z_INVAL);
3107 	if (!zonecfg_valid_rctlblk(rctlblk))
3108 		return (Z_INVAL);
3109 	if (last == NULL)
3110 		tabptr->zone_rctl_valptr = new;
3111 	else
3112 		last->zone_rctlval_next = new;
3113 	return (Z_OK);
3114 }
3115 
3116 int
3117 zonecfg_remove_rctl_value(
3118 	struct zone_rctltab *tabptr,
3119 	struct zone_rctlvaltab *valtabptr)
3120 {
3121 	struct zone_rctlvaltab *last, *this, *next;
3122 
3123 	last = tabptr->zone_rctl_valptr;
3124 	for (this = last; this != NULL; this = this->zone_rctlval_next) {
3125 		if (strcmp(this->zone_rctlval_priv,
3126 		    valtabptr->zone_rctlval_priv) == 0 &&
3127 		    strcmp(this->zone_rctlval_limit,
3128 		    valtabptr->zone_rctlval_limit) == 0 &&
3129 		    strcmp(this->zone_rctlval_action,
3130 		    valtabptr->zone_rctlval_action) == 0) {
3131 			next = this->zone_rctlval_next;
3132 			if (this == tabptr->zone_rctl_valptr)
3133 				tabptr->zone_rctl_valptr = next;
3134 			else
3135 				last->zone_rctlval_next = next;
3136 			free(this);
3137 			return (Z_OK);
3138 		} else
3139 			last = this;
3140 	}
3141 	return (Z_NO_PROPERTY_ID);
3142 }
3143 
3144 char *
3145 zonecfg_strerror(int errnum)
3146 {
3147 	switch (errnum) {
3148 	case Z_OK:
3149 		return (dgettext(TEXT_DOMAIN, "OK"));
3150 	case Z_EMPTY_DOCUMENT:
3151 		return (dgettext(TEXT_DOMAIN, "Empty document"));
3152 	case Z_WRONG_DOC_TYPE:
3153 		return (dgettext(TEXT_DOMAIN, "Wrong document type"));
3154 	case Z_BAD_PROPERTY:
3155 		return (dgettext(TEXT_DOMAIN, "Bad document property"));
3156 	case Z_TEMP_FILE:
3157 		return (dgettext(TEXT_DOMAIN,
3158 		    "Problem creating temporary file"));
3159 	case Z_SAVING_FILE:
3160 		return (dgettext(TEXT_DOMAIN, "Problem saving file"));
3161 	case Z_NO_ENTRY:
3162 		return (dgettext(TEXT_DOMAIN, "No such entry"));
3163 	case Z_BOGUS_ZONE_NAME:
3164 		return (dgettext(TEXT_DOMAIN, "Bogus zone name"));
3165 	case Z_REQD_RESOURCE_MISSING:
3166 		return (dgettext(TEXT_DOMAIN, "Required resource missing"));
3167 	case Z_REQD_PROPERTY_MISSING:
3168 		return (dgettext(TEXT_DOMAIN, "Required property missing"));
3169 	case Z_BAD_HANDLE:
3170 		return (dgettext(TEXT_DOMAIN, "Bad handle"));
3171 	case Z_NOMEM:
3172 		return (dgettext(TEXT_DOMAIN, "Out of memory"));
3173 	case Z_INVAL:
3174 		return (dgettext(TEXT_DOMAIN, "Invalid argument"));
3175 	case Z_ACCES:
3176 		return (dgettext(TEXT_DOMAIN, "Permission denied"));
3177 	case Z_TOO_BIG:
3178 		return (dgettext(TEXT_DOMAIN, "Argument list too long"));
3179 	case Z_MISC_FS:
3180 		return (dgettext(TEXT_DOMAIN,
3181 		    "Miscellaneous file system error"));
3182 	case Z_NO_ZONE:
3183 		return (dgettext(TEXT_DOMAIN, "No such zone configured"));
3184 	case Z_NO_RESOURCE_TYPE:
3185 		return (dgettext(TEXT_DOMAIN, "No such resource type"));
3186 	case Z_NO_RESOURCE_ID:
3187 		return (dgettext(TEXT_DOMAIN, "No such resource with that id"));
3188 	case Z_NO_PROPERTY_TYPE:
3189 		return (dgettext(TEXT_DOMAIN, "No such property type"));
3190 	case Z_NO_PROPERTY_ID:
3191 		return (dgettext(TEXT_DOMAIN, "No such property with that id"));
3192 	case Z_BAD_ZONE_STATE:
3193 		return (dgettext(TEXT_DOMAIN,
3194 		    "Zone state is invalid for the requested operation"));
3195 	case Z_INVALID_DOCUMENT:
3196 		return (dgettext(TEXT_DOMAIN, "Invalid document"));
3197 	case Z_NAME_IN_USE:
3198 		return (dgettext(TEXT_DOMAIN, "Zone name already in use"));
3199 	case Z_NO_SUCH_ID:
3200 		return (dgettext(TEXT_DOMAIN, "No such zone ID"));
3201 	case Z_UPDATING_INDEX:
3202 		return (dgettext(TEXT_DOMAIN, "Problem updating index file"));
3203 	case Z_LOCKING_FILE:
3204 		return (dgettext(TEXT_DOMAIN, "Locking index file"));
3205 	case Z_UNLOCKING_FILE:
3206 		return (dgettext(TEXT_DOMAIN, "Unlocking index file"));
3207 	case Z_INSUFFICIENT_SPEC:
3208 		return (dgettext(TEXT_DOMAIN, "Insufficient specification"));
3209 	case Z_RESOLVED_PATH:
3210 		return (dgettext(TEXT_DOMAIN, "Resolved path mismatch"));
3211 	case Z_IPV6_ADDR_PREFIX_LEN:
3212 		return (dgettext(TEXT_DOMAIN,
3213 		    "IPv6 address missing required prefix length"));
3214 	case Z_BOGUS_ADDRESS:
3215 		return (dgettext(TEXT_DOMAIN,
3216 		    "Neither an IPv4 nor an IPv6 address nor a host name"));
3217 	case Z_PRIV_PROHIBITED:
3218 		return (dgettext(TEXT_DOMAIN,
3219 		    "Specified privilege is prohibited"));
3220 	case Z_PRIV_REQUIRED:
3221 		return (dgettext(TEXT_DOMAIN,
3222 		    "Required privilege is missing"));
3223 	case Z_PRIV_UNKNOWN:
3224 		return (dgettext(TEXT_DOMAIN,
3225 		    "Specified privilege is unknown"));
3226 	case Z_BRAND_ERROR:
3227 		return (dgettext(TEXT_DOMAIN,
3228 		    "Brand-specific error"));
3229 	case Z_INCOMPATIBLE:
3230 		return (dgettext(TEXT_DOMAIN, "Incompatible settings"));
3231 	case Z_ALIAS_DISALLOW:
3232 		return (dgettext(TEXT_DOMAIN,
3233 		    "An incompatible rctl already exists for this property"));
3234 	case Z_CLEAR_DISALLOW:
3235 		return (dgettext(TEXT_DOMAIN,
3236 		    "Clearing this property is not allowed"));
3237 	case Z_POOL:
3238 		return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error"));
3239 	case Z_POOLS_NOT_ACTIVE:
3240 		return (dgettext(TEXT_DOMAIN, "Pools facility not active; "
3241 		    "zone will not be bound to pool"));
3242 	case Z_POOL_ENABLE:
3243 		return (dgettext(TEXT_DOMAIN,
3244 		    "Could not enable pools facility"));
3245 	case Z_NO_POOL:
3246 		return (dgettext(TEXT_DOMAIN,
3247 		    "Pool not found; using default pool"));
3248 	case Z_POOL_CREATE:
3249 		return (dgettext(TEXT_DOMAIN,
3250 		    "Could not create a temporary pool"));
3251 	case Z_POOL_BIND:
3252 		return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool"));
3253 	default:
3254 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
3255 	}
3256 }
3257 
3258 /*
3259  * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
3260  * same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
3261  */
3262 
3263 static int
3264 zonecfg_setent(zone_dochandle_t handle)
3265 {
3266 	xmlNodePtr cur;
3267 	int err;
3268 
3269 	if (handle == NULL)
3270 		return (Z_INVAL);
3271 
3272 	if ((err = operation_prep(handle)) != Z_OK) {
3273 		handle->zone_dh_cur = NULL;
3274 		return (err);
3275 	}
3276 	cur = handle->zone_dh_cur;
3277 	cur = cur->xmlChildrenNode;
3278 	handle->zone_dh_cur = cur;
3279 	return (Z_OK);
3280 }
3281 
3282 static int
3283 zonecfg_endent(zone_dochandle_t handle)
3284 {
3285 	if (handle == NULL)
3286 		return (Z_INVAL);
3287 
3288 	handle->zone_dh_cur = handle->zone_dh_top;
3289 	return (Z_OK);
3290 }
3291 
3292 /*
3293  * Do the work required to manipulate a process through libproc.
3294  * If grab_process() returns no errors (0), then release_process()
3295  * must eventually be called.
3296  *
3297  * Return values:
3298  *      0 Successful creation of agent thread
3299  *      1 Error grabbing
3300  *      2 Error creating agent
3301  */
3302 static int
3303 grab_process(pr_info_handle_t *p)
3304 {
3305 	int ret;
3306 
3307 	if ((p->pr = Pgrab(p->pid, 0, &ret)) != NULL) {
3308 
3309 		if (Psetflags(p->pr, PR_RLC) != 0) {
3310 			Prelease(p->pr, 0);
3311 			return (1);
3312 		}
3313 		if (Pcreate_agent(p->pr) == 0) {
3314 			return (0);
3315 
3316 		} else {
3317 			Prelease(p->pr, 0);
3318 			return (2);
3319 		}
3320 	} else {
3321 		return (1);
3322 	}
3323 }
3324 
3325 /*
3326  * Release the specified process. This destroys the agent
3327  * and releases the process. If the process is NULL, nothing
3328  * is done. This function should only be called if grab_process()
3329  * has previously been called and returned success.
3330  *
3331  * This function is Pgrab-safe.
3332  */
3333 static void
3334 release_process(struct ps_prochandle *Pr)
3335 {
3336 	if (Pr == NULL)
3337 		return;
3338 
3339 	Pdestroy_agent(Pr);
3340 	Prelease(Pr, 0);
3341 }
3342 
3343 static boolean_t
3344 grab_zone_proc(char *zonename, pr_info_handle_t *p)
3345 {
3346 	DIR *dirp;
3347 	struct dirent *dentp;
3348 	zoneid_t zoneid;
3349 	int pid_self;
3350 	psinfo_t psinfo;
3351 
3352 	if (zone_get_id(zonename, &zoneid) != 0)
3353 		return (B_FALSE);
3354 
3355 	pid_self = getpid();
3356 
3357 	if ((dirp = opendir("/proc")) == NULL)
3358 		return (B_FALSE);
3359 
3360 	while (dentp = readdir(dirp)) {
3361 		p->pid = atoi(dentp->d_name);
3362 
3363 		/* Skip self */
3364 		if (p->pid == pid_self)
3365 			continue;
3366 
3367 		if (proc_get_psinfo(p->pid, &psinfo) != 0)
3368 			continue;
3369 
3370 		if (psinfo.pr_zoneid != zoneid)
3371 			continue;
3372 
3373 		/* attempt to grab process */
3374 		if (grab_process(p) != 0)
3375 			continue;
3376 
3377 		if (pr_getzoneid(p->pr) != zoneid) {
3378 			release_process(p->pr);
3379 			continue;
3380 		}
3381 
3382 		(void) closedir(dirp);
3383 		return (B_TRUE);
3384 	}
3385 
3386 	(void) closedir(dirp);
3387 	return (B_FALSE);
3388 }
3389 
3390 static boolean_t
3391 get_priv_rctl(struct ps_prochandle *pr, char *name, rctlblk_t *rblk)
3392 {
3393 	if (pr_getrctl(pr, name, NULL, rblk, RCTL_FIRST))
3394 		return (B_FALSE);
3395 
3396 	if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
3397 		return (B_TRUE);
3398 
3399 	while (pr_getrctl(pr, name, rblk, rblk, RCTL_NEXT) == 0) {
3400 		if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
3401 			return (B_TRUE);
3402 	}
3403 
3404 	return (B_FALSE);
3405 }
3406 
3407 /*
3408  * Apply the current rctl settings to the specified, running zone.
3409  */
3410 int
3411 zonecfg_apply_rctls(char *zone_name, zone_dochandle_t handle)
3412 {
3413 	int err;
3414 	int res = Z_OK;
3415 	rctlblk_t *rblk;
3416 	pr_info_handle_t p;
3417 	struct zone_rctltab rctl;
3418 
3419 	if ((err = zonecfg_setrctlent(handle)) != Z_OK)
3420 		return (err);
3421 
3422 	if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
3423 		(void) zonecfg_endrctlent(handle);
3424 		return (Z_NOMEM);
3425 	}
3426 
3427 	if (!grab_zone_proc(zone_name, &p)) {
3428 		(void) zonecfg_endrctlent(handle);
3429 		free(rblk);
3430 		return (Z_SYSTEM);
3431 	}
3432 
3433 	while (zonecfg_getrctlent(handle, &rctl) == Z_OK) {
3434 		char *rname;
3435 		struct zone_rctlvaltab *valptr;
3436 
3437 		rname = rctl.zone_rctl_name;
3438 
3439 		/* first delete all current privileged settings for this rctl */
3440 		while (get_priv_rctl(p.pr, rname, rblk)) {
3441 			if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_DELETE) !=
3442 			    0) {
3443 				res = Z_SYSTEM;
3444 				goto done;
3445 			}
3446 		}
3447 
3448 		/* now set each new value for the rctl */
3449 		for (valptr = rctl.zone_rctl_valptr; valptr != NULL;
3450 		    valptr = valptr->zone_rctlval_next) {
3451 			if ((err = zonecfg_construct_rctlblk(valptr, rblk))
3452 			    != Z_OK) {
3453 				res = errno = err;
3454 				goto done;
3455 			}
3456 
3457 			if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_INSERT)) {
3458 				res = Z_SYSTEM;
3459 				goto done;
3460 			}
3461 		}
3462 	}
3463 
3464 done:
3465 	release_process(p.pr);
3466 	free(rblk);
3467 	(void) zonecfg_endrctlent(handle);
3468 
3469 	return (res);
3470 }
3471 
3472 static const xmlChar *
3473 nm_to_dtd(char *nm)
3474 {
3475 	if (strcmp(nm, "device") == 0)
3476 		return (DTD_ELEM_DEVICE);
3477 	if (strcmp(nm, "fs") == 0)
3478 		return (DTD_ELEM_FS);
3479 	if (strcmp(nm, "inherit-pkg-dir") == 0)
3480 		return (DTD_ELEM_IPD);
3481 	if (strcmp(nm, "net") == 0)
3482 		return (DTD_ELEM_NET);
3483 	if (strcmp(nm, "attr") == 0)
3484 		return (DTD_ELEM_ATTR);
3485 	if (strcmp(nm, "rctl") == 0)
3486 		return (DTD_ELEM_RCTL);
3487 	if (strcmp(nm, "dataset") == 0)
3488 		return (DTD_ELEM_DATASET);
3489 
3490 	return (NULL);
3491 }
3492 
3493 int
3494 zonecfg_num_resources(zone_dochandle_t handle, char *rsrc)
3495 {
3496 	int num = 0;
3497 	const xmlChar *dtd;
3498 	xmlNodePtr cur;
3499 
3500 	if ((dtd = nm_to_dtd(rsrc)) == NULL)
3501 		return (num);
3502 
3503 	if (zonecfg_setent(handle) != Z_OK)
3504 		return (num);
3505 
3506 	for (cur = handle->zone_dh_cur; cur != NULL; cur = cur->next)
3507 		if (xmlStrcmp(cur->name, dtd) == 0)
3508 			num++;
3509 
3510 	(void) zonecfg_endent(handle);
3511 
3512 	return (num);
3513 }
3514 
3515 int
3516 zonecfg_del_all_resources(zone_dochandle_t handle, char *rsrc)
3517 {
3518 	int err;
3519 	const xmlChar *dtd;
3520 	xmlNodePtr cur;
3521 
3522 	if ((dtd = nm_to_dtd(rsrc)) == NULL)
3523 		return (Z_NO_RESOURCE_TYPE);
3524 
3525 	if ((err = zonecfg_setent(handle)) != Z_OK)
3526 		return (err);
3527 
3528 	cur = handle->zone_dh_cur;
3529 	while (cur != NULL) {
3530 		xmlNodePtr tmp;
3531 
3532 		if (xmlStrcmp(cur->name, dtd)) {
3533 			cur = cur->next;
3534 			continue;
3535 		}
3536 
3537 		tmp = cur->next;
3538 		xmlUnlinkNode(cur);
3539 		xmlFreeNode(cur);
3540 		cur = tmp;
3541 	}
3542 
3543 	(void) zonecfg_endent(handle);
3544 	return (Z_OK);
3545 }
3546 
3547 static boolean_t
3548 valid_uint(char *s, uint64_t *n)
3549 {
3550 	char *endp;
3551 
3552 	/* strtoull accepts '-'?! so we want to flag that as an error */
3553 	if (strchr(s, '-') != NULL)
3554 		return (B_FALSE);
3555 
3556 	errno = 0;
3557 	*n = strtoull(s, &endp, 10);
3558 
3559 	if (errno != 0 || *endp != '\0')
3560 		return (B_FALSE);
3561 	return (B_TRUE);
3562 }
3563 
3564 /*
3565  * Convert a string representing a number (possibly a fraction) into an integer.
3566  * The string can have a modifier (K, M, G or T).   The modifiers are treated
3567  * as powers of two (not 10).
3568  */
3569 int
3570 zonecfg_str_to_bytes(char *str, uint64_t *bytes)
3571 {
3572 	long double val;
3573 	char *unitp;
3574 	uint64_t scale;
3575 
3576 	if ((val = strtold(str, &unitp)) < 0)
3577 		return (-1);
3578 
3579 	/* remove any leading white space from units string */
3580 	while (isspace(*unitp) != 0)
3581 		++unitp;
3582 
3583 	/* if no units explicitly set, error */
3584 	if (unitp == NULL || *unitp == '\0') {
3585 		scale = 1;
3586 	} else {
3587 		int i;
3588 		char *units[] = {"K", "M", "G", "T", NULL};
3589 
3590 		scale = 1024;
3591 
3592 		/* update scale based on units */
3593 		for (i = 0; units[i] != NULL; i++) {
3594 			if (strcasecmp(unitp, units[i]) == 0)
3595 				break;
3596 			scale <<= 10;
3597 		}
3598 
3599 		if (units[i] == NULL)
3600 			return (-1);
3601 	}
3602 
3603 	*bytes = (uint64_t)(val * scale);
3604 	return (0);
3605 }
3606 
3607 boolean_t
3608 zonecfg_valid_ncpus(char *lowstr, char *highstr)
3609 {
3610 	uint64_t low, high;
3611 
3612 	if (!valid_uint(lowstr, &low) || !valid_uint(highstr, &high) ||
3613 	    low < 1 || low > high)
3614 		return (B_FALSE);
3615 
3616 	return (B_TRUE);
3617 }
3618 
3619 boolean_t
3620 zonecfg_valid_importance(char *impstr)
3621 {
3622 	uint64_t num;
3623 
3624 	if (!valid_uint(impstr, &num))
3625 		return (B_FALSE);
3626 
3627 	return (B_TRUE);
3628 }
3629 
3630 boolean_t
3631 zonecfg_valid_alias_limit(char *name, char *limitstr, uint64_t *limit)
3632 {
3633 	int i;
3634 
3635 	for (i = 0; aliases[i].shortname != NULL; i++)
3636 		if (strcmp(name, aliases[i].shortname) == 0)
3637 			break;
3638 
3639 	if (aliases[i].shortname == NULL)
3640 		return (B_FALSE);
3641 
3642 	if (!valid_uint(limitstr, limit) || *limit < aliases[i].low_limit)
3643 		return (B_FALSE);
3644 
3645 	return (B_TRUE);
3646 }
3647 
3648 boolean_t
3649 zonecfg_valid_memlimit(char *memstr, uint64_t *mem_val)
3650 {
3651 	if (zonecfg_str_to_bytes(memstr, mem_val) != 0)
3652 		return (B_FALSE);
3653 
3654 	return (B_TRUE);
3655 }
3656 
3657 static int
3658 zerr_pool(char *pool_err, int err_size, int res)
3659 {
3660 	(void) strlcpy(pool_err, pool_strerror(pool_error()), err_size);
3661 	return (res);
3662 }
3663 
3664 static int
3665 create_tmp_pset(char *pool_err, int err_size, pool_conf_t *pconf, pool_t *pool,
3666     char *name, int min, int max)
3667 {
3668 	pool_resource_t *res;
3669 	pool_elem_t *elem;
3670 	pool_value_t *val;
3671 
3672 	if ((res = pool_resource_create(pconf, "pset", name)) == NULL)
3673 		return (zerr_pool(pool_err, err_size, Z_POOL));
3674 
3675 	if (pool_associate(pconf, pool, res) != PO_SUCCESS)
3676 		return (zerr_pool(pool_err, err_size, Z_POOL));
3677 
3678 	if ((elem = pool_resource_to_elem(pconf, res)) == NULL)
3679 		return (zerr_pool(pool_err, err_size, Z_POOL));
3680 
3681 	if ((val = pool_value_alloc()) == NULL)
3682 		return (zerr_pool(pool_err, err_size, Z_POOL));
3683 
3684 	/* set the maximum number of cpus for the pset */
3685 	pool_value_set_uint64(val, (uint64_t)max);
3686 
3687 	if (pool_put_property(pconf, elem, "pset.max", val) != PO_SUCCESS) {
3688 		pool_value_free(val);
3689 		return (zerr_pool(pool_err, err_size, Z_POOL));
3690 	}
3691 
3692 	/* set the minimum number of cpus for the pset */
3693 	pool_value_set_uint64(val, (uint64_t)min);
3694 
3695 	if (pool_put_property(pconf, elem, "pset.min", val) != PO_SUCCESS) {
3696 		pool_value_free(val);
3697 		return (zerr_pool(pool_err, err_size, Z_POOL));
3698 	}
3699 
3700 	pool_value_free(val);
3701 
3702 	return (Z_OK);
3703 }
3704 
3705 static int
3706 create_tmp_pool(char *pool_err, int err_size, pool_conf_t *pconf, char *name,
3707     struct zone_psettab *pset_tab)
3708 {
3709 	pool_t *pool;
3710 	int res = Z_OK;
3711 
3712 	/* create a temporary pool configuration */
3713 	if (pool_conf_open(pconf, NULL, PO_TEMP) != PO_SUCCESS) {
3714 		res = zerr_pool(pool_err, err_size, Z_POOL);
3715 		return (res);
3716 	}
3717 
3718 	if ((pool = pool_create(pconf, name)) == NULL) {
3719 		res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
3720 		goto done;
3721 	}
3722 
3723 	/* set pool importance */
3724 	if (pset_tab->zone_importance[0] != '\0') {
3725 		pool_elem_t *elem;
3726 		pool_value_t *val;
3727 
3728 		if ((elem = pool_to_elem(pconf, pool)) == NULL) {
3729 			res = zerr_pool(pool_err, err_size, Z_POOL);
3730 			goto done;
3731 		}
3732 
3733 		if ((val = pool_value_alloc()) == NULL) {
3734 			res = zerr_pool(pool_err, err_size, Z_POOL);
3735 			goto done;
3736 		}
3737 
3738 		pool_value_set_int64(val,
3739 		    (int64_t)atoi(pset_tab->zone_importance));
3740 
3741 		if (pool_put_property(pconf, elem, "pool.importance", val)
3742 		    != PO_SUCCESS) {
3743 			res = zerr_pool(pool_err, err_size, Z_POOL);
3744 			pool_value_free(val);
3745 			goto done;
3746 		}
3747 
3748 		pool_value_free(val);
3749 	}
3750 
3751 	if ((res = create_tmp_pset(pool_err, err_size, pconf, pool, name,
3752 	    atoi(pset_tab->zone_ncpu_min),
3753 	    atoi(pset_tab->zone_ncpu_max))) != Z_OK)
3754 		goto done;
3755 
3756 	/* validation */
3757 	if (pool_conf_status(pconf) == POF_INVALID) {
3758 		res = zerr_pool(pool_err, err_size, Z_POOL);
3759 		goto done;
3760 	}
3761 
3762 	/*
3763 	 * This validation is the one we expect to fail if the user specified
3764 	 * an invalid configuration (too many cpus) for this system.
3765 	 */
3766 	if (pool_conf_validate(pconf, POV_RUNTIME) != PO_SUCCESS) {
3767 		res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
3768 		goto done;
3769 	}
3770 
3771 	/*
3772 	 * Commit the dynamic configuration but not the pool configuration
3773 	 * file.
3774 	 */
3775 	if (pool_conf_commit(pconf, 1) != PO_SUCCESS)
3776 		res = zerr_pool(pool_err, err_size, Z_POOL);
3777 
3778 done:
3779 	(void) pool_conf_close(pconf);
3780 	return (res);
3781 }
3782 
3783 static int
3784 get_running_tmp_pset(pool_conf_t *pconf, pool_t *pool, pool_resource_t *pset,
3785     struct zone_psettab *pset_tab)
3786 {
3787 	int nfound = 0;
3788 	pool_elem_t *pe;
3789 	pool_value_t *pv = pool_value_alloc();
3790 	uint64_t val_uint;
3791 
3792 	if (pool != NULL) {
3793 		pe = pool_to_elem(pconf, pool);
3794 		if (pool_get_property(pconf, pe, "pool.importance", pv)
3795 		    != POC_INVAL) {
3796 			int64_t val_int;
3797 
3798 			(void) pool_value_get_int64(pv, &val_int);
3799 			(void) snprintf(pset_tab->zone_importance,
3800 			    sizeof (pset_tab->zone_importance), "%d", val_int);
3801 			nfound++;
3802 		}
3803 	}
3804 
3805 	if (pset != NULL) {
3806 		pe = pool_resource_to_elem(pconf, pset);
3807 		if (pool_get_property(pconf, pe, "pset.min", pv) != POC_INVAL) {
3808 			(void) pool_value_get_uint64(pv, &val_uint);
3809 			(void) snprintf(pset_tab->zone_ncpu_min,
3810 			    sizeof (pset_tab->zone_ncpu_min), "%u", val_uint);
3811 			nfound++;
3812 		}
3813 
3814 		if (pool_get_property(pconf, pe, "pset.max", pv) != POC_INVAL) {
3815 			(void) pool_value_get_uint64(pv, &val_uint);
3816 			(void) snprintf(pset_tab->zone_ncpu_max,
3817 			    sizeof (pset_tab->zone_ncpu_max), "%u", val_uint);
3818 			nfound++;
3819 		}
3820 	}
3821 
3822 	pool_value_free(pv);
3823 
3824 	if (nfound == 3)
3825 		return (PO_SUCCESS);
3826 
3827 	return (PO_FAIL);
3828 }
3829 
3830 /*
3831  * Determine if a tmp pool is configured and if so, if the configuration is
3832  * still valid or if it has been changed since the tmp pool was created.
3833  * If the tmp pool configuration is no longer valid, delete the tmp pool.
3834  *
3835  * Set *valid=B_TRUE if there is an existing, valid tmp pool configuration.
3836  */
3837 static int
3838 verify_del_tmp_pool(pool_conf_t *pconf, char *tmp_name, char *pool_err,
3839     int err_size, struct zone_psettab *pset_tab, boolean_t *exists)
3840 {
3841 	int res = Z_OK;
3842 	pool_t *pool;
3843 	pool_resource_t *pset;
3844 	struct zone_psettab pset_current;
3845 
3846 	*exists = B_FALSE;
3847 
3848 	if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
3849 	    != PO_SUCCESS) {
3850 		res = zerr_pool(pool_err, err_size, Z_POOL);
3851 		return (res);
3852 	}
3853 
3854 	pool = pool_get_pool(pconf, tmp_name);
3855 	pset = pool_get_resource(pconf, "pset", tmp_name);
3856 
3857 	if (pool == NULL && pset == NULL) {
3858 		/* no tmp pool configured */
3859 		goto done;
3860 	}
3861 
3862 	/*
3863 	 * If an existing tmp pool for this zone is configured with the proper
3864 	 * settings, then the tmp pool is valid.
3865 	 */
3866 	if (get_running_tmp_pset(pconf, pool, pset, &pset_current)
3867 	    == PO_SUCCESS &&
3868 	    strcmp(pset_tab->zone_ncpu_min,
3869 	    pset_current.zone_ncpu_min) == 0 &&
3870 	    strcmp(pset_tab->zone_ncpu_max,
3871 	    pset_current.zone_ncpu_max) == 0 &&
3872 	    strcmp(pset_tab->zone_importance,
3873 	    pset_current.zone_importance) == 0) {
3874 		*exists = B_TRUE;
3875 
3876 	} else {
3877 		/*
3878 		 * An out-of-date tmp pool configuration exists.  Delete it
3879 		 * so that we can create the correct tmp pool config.
3880 		 */
3881 		if (pset != NULL &&
3882 		    pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
3883 			res = zerr_pool(pool_err, err_size, Z_POOL);
3884 			goto done;
3885 		}
3886 
3887 		if (pool != NULL &&
3888 		    pool_destroy(pconf, pool) != PO_SUCCESS) {
3889 			res = zerr_pool(pool_err, err_size, Z_POOL);
3890 			goto done;
3891 		}
3892 
3893 		/* commit dynamic config */
3894 		if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
3895 			res = zerr_pool(pool_err, err_size, Z_POOL);
3896 	}
3897 
3898 done:
3899 	(void) pool_conf_close(pconf);
3900 
3901 	return (res);
3902 }
3903 
3904 /*
3905  * Destroy any existing tmp pool.
3906  */
3907 int
3908 zonecfg_destroy_tmp_pool(char *zone_name, char *pool_err, int err_size)
3909 {
3910 	int status;
3911 	int res = Z_OK;
3912 	pool_conf_t *pconf;
3913 	pool_t *pool;
3914 	pool_resource_t *pset;
3915 	char tmp_name[MAX_TMP_POOL_NAME];
3916 
3917 	/* if pools not enabled then nothing to do */
3918 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
3919 		return (Z_OK);
3920 
3921 	if ((pconf = pool_conf_alloc()) == NULL)
3922 		return (zerr_pool(pool_err, err_size, Z_POOL));
3923 
3924 	(void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
3925 
3926 	if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
3927 	    != PO_SUCCESS) {
3928 		res = zerr_pool(pool_err, err_size, Z_POOL);
3929 		pool_conf_free(pconf);
3930 		return (res);
3931 	}
3932 
3933 	pool = pool_get_pool(pconf, tmp_name);
3934 	pset = pool_get_resource(pconf, "pset", tmp_name);
3935 
3936 	if (pool == NULL && pset == NULL) {
3937 		/* nothing to destroy, we're done */
3938 		goto done;
3939 	}
3940 
3941 	if (pset != NULL && pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
3942 		res = zerr_pool(pool_err, err_size, Z_POOL);
3943 		goto done;
3944 	}
3945 
3946 	if (pool != NULL && pool_destroy(pconf, pool) != PO_SUCCESS) {
3947 		res = zerr_pool(pool_err, err_size, Z_POOL);
3948 		goto done;
3949 	}
3950 
3951 	/* commit dynamic config */
3952 	if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
3953 		res = zerr_pool(pool_err, err_size, Z_POOL);
3954 
3955 done:
3956 	(void) pool_conf_close(pconf);
3957 	pool_conf_free(pconf);
3958 
3959 	return (res);
3960 }
3961 
3962 /*
3963  * Attempt to bind to a tmp pool for this zone.  If there is no tmp pool
3964  * configured, we just return Z_OK.
3965  *
3966  * We either attempt to create the tmp pool for this zone or rebind to an
3967  * existing tmp pool for this zone.
3968  *
3969  * Rebinding is used when a zone with a tmp pool reboots so that we don't have
3970  * to recreate the tmp pool.  To do this we need to be sure we work correctly
3971  * for the following cases:
3972  *
3973  *	- there is an existing, properly configured tmp pool.
3974  *	- zonecfg added tmp pool after zone was booted, must now create.
3975  *	- zonecfg updated tmp pool config after zone was booted, in this case
3976  *	  we destroy the old tmp pool and create a new one.
3977  */
3978 int
3979 zonecfg_bind_tmp_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
3980     int err_size)
3981 {
3982 	struct zone_psettab pset_tab;
3983 	int err;
3984 	int status;
3985 	pool_conf_t *pconf;
3986 	boolean_t exists;
3987 	char zone_name[ZONENAME_MAX];
3988 	char tmp_name[MAX_TMP_POOL_NAME];
3989 
3990 	(void) getzonenamebyid(zoneid, zone_name, sizeof (zone_name));
3991 
3992 	err = zonecfg_lookup_pset(handle, &pset_tab);
3993 
3994 	/* if no temporary pool configured, we're done */
3995 	if (err == Z_NO_ENTRY)
3996 		return (Z_OK);
3997 
3998 	/*
3999 	 * importance might not have a value but we need to validate it here,
4000 	 * so set the default.
4001 	 */
4002 	if (pset_tab.zone_importance[0] == '\0')
4003 		(void) strlcpy(pset_tab.zone_importance, "1",
4004 		    sizeof (pset_tab.zone_importance));
4005 
4006 	/* if pools not enabled, enable them now */
4007 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
4008 		if (pool_set_status(POOL_ENABLED) != PO_SUCCESS)
4009 			return (Z_POOL_ENABLE);
4010 	}
4011 
4012 	if ((pconf = pool_conf_alloc()) == NULL)
4013 		return (zerr_pool(pool_err, err_size, Z_POOL));
4014 
4015 	(void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
4016 
4017 	/*
4018 	 * Check if a valid tmp pool/pset already exists.  If so, we just
4019 	 * reuse it.
4020 	 */
4021 	if ((err = verify_del_tmp_pool(pconf, tmp_name, pool_err, err_size,
4022 	    &pset_tab, &exists)) != Z_OK) {
4023 		pool_conf_free(pconf);
4024 		return (err);
4025 	}
4026 
4027 	if (!exists)
4028 		err = create_tmp_pool(pool_err, err_size, pconf, tmp_name,
4029 		    &pset_tab);
4030 
4031 	pool_conf_free(pconf);
4032 
4033 	if (err != Z_OK)
4034 		return (err);
4035 
4036 	/* Bind the zone to the pool. */
4037 	if (pool_set_binding(tmp_name, P_ZONEID, zoneid) != PO_SUCCESS)
4038 		return (zerr_pool(pool_err, err_size, Z_POOL_BIND));
4039 
4040 	return (Z_OK);
4041 }
4042 
4043 /*
4044  * Attempt to bind to a permanent pool for this zone.  If there is no
4045  * permanent pool configured, we just return Z_OK.
4046  */
4047 int
4048 zonecfg_bind_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
4049     int err_size)
4050 {
4051 	pool_conf_t *poolconf;
4052 	pool_t *pool;
4053 	char poolname[MAXPATHLEN];
4054 	int status;
4055 	int error;
4056 
4057 	/*
4058 	 * Find the pool mentioned in the zone configuration, and bind to it.
4059 	 */
4060 	error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
4061 	if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
4062 		/*
4063 		 * The property is not set on the zone, so the pool
4064 		 * should be bound to the default pool.  But that's
4065 		 * already done by the kernel, so we can just return.
4066 		 */
4067 		return (Z_OK);
4068 	}
4069 	if (error != Z_OK) {
4070 		/*
4071 		 * Not an error, even though it shouldn't be happening.
4072 		 */
4073 		return (Z_OK);
4074 	}
4075 	/*
4076 	 * Don't do anything if pools aren't enabled.
4077 	 */
4078 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4079 		return (Z_POOLS_NOT_ACTIVE);
4080 
4081 	/*
4082 	 * Try to provide a sane error message if the requested pool doesn't
4083 	 * exist.
4084 	 */
4085 	if ((poolconf = pool_conf_alloc()) == NULL)
4086 		return (zerr_pool(pool_err, err_size, Z_POOL));
4087 
4088 	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
4089 	    PO_SUCCESS) {
4090 		pool_conf_free(poolconf);
4091 		return (zerr_pool(pool_err, err_size, Z_POOL));
4092 	}
4093 	pool = pool_get_pool(poolconf, poolname);
4094 	(void) pool_conf_close(poolconf);
4095 	pool_conf_free(poolconf);
4096 	if (pool == NULL)
4097 		return (Z_NO_POOL);
4098 
4099 	/*
4100 	 * Bind the zone to the pool.
4101 	 */
4102 	if (pool_set_binding(poolname, P_ZONEID, zoneid) != PO_SUCCESS) {
4103 		/* if bind fails, return poolname for the error msg */
4104 		(void) strlcpy(pool_err, poolname, err_size);
4105 		return (Z_POOL_BIND);
4106 	}
4107 
4108 	return (Z_OK);
4109 }
4110 
4111 
4112 static boolean_t
4113 svc_enabled(char *svc_name)
4114 {
4115 	scf_simple_prop_t	*prop;
4116 	boolean_t		found = B_FALSE;
4117 
4118 	prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL,
4119 	    SCF_PROPERTY_ENABLED);
4120 
4121 	if (scf_simple_prop_numvalues(prop) == 1 &&
4122 	    *scf_simple_prop_next_boolean(prop) != 0)
4123 		found = B_TRUE;
4124 
4125 	scf_simple_prop_free(prop);
4126 
4127 	return (found);
4128 }
4129 
4130 /*
4131  * If the zone has capped-memory, make sure the rcap service is enabled.
4132  */
4133 int
4134 zonecfg_enable_rcapd(char *err, int size)
4135 {
4136 	if (!svc_enabled(RCAP_SERVICE) &&
4137 	    smf_enable_instance(RCAP_SERVICE, 0) == -1) {
4138 		(void) strlcpy(err, scf_strerror(scf_error()), size);
4139 		return (Z_SYSTEM);
4140 	}
4141 
4142 	return (Z_OK);
4143 }
4144 
4145 /*
4146  * Return true if pset has cpu range specified and poold is not enabled.
4147  */
4148 boolean_t
4149 zonecfg_warn_poold(zone_dochandle_t handle)
4150 {
4151 	struct zone_psettab pset_tab;
4152 	int min, max;
4153 	int err;
4154 
4155 	err = zonecfg_lookup_pset(handle, &pset_tab);
4156 
4157 	/* if no temporary pool configured, we're done */
4158 	if (err == Z_NO_ENTRY)
4159 		return (B_FALSE);
4160 
4161 	min = atoi(pset_tab.zone_ncpu_min);
4162 	max = atoi(pset_tab.zone_ncpu_max);
4163 
4164 	/* range not specified, no need for poold */
4165 	if (min == max)
4166 		return (B_FALSE);
4167 
4168 	/* we have a range, check if poold service is enabled */
4169 	if (svc_enabled(POOLD_SERVICE))
4170 		return (B_FALSE);
4171 
4172 	return (B_TRUE);
4173 }
4174 
4175 static int
4176 get_pool_sched_class(char *poolname, char *class, int clsize)
4177 {
4178 	int status;
4179 	pool_conf_t *poolconf;
4180 	pool_t *pool;
4181 	pool_elem_t *pe;
4182 	pool_value_t *pv = pool_value_alloc();
4183 	const char *sched_str;
4184 
4185 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4186 		return (Z_NO_POOL);
4187 
4188 	if ((poolconf = pool_conf_alloc()) == NULL)
4189 		return (Z_NO_POOL);
4190 
4191 	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
4192 	    PO_SUCCESS) {
4193 		pool_conf_free(poolconf);
4194 		return (Z_NO_POOL);
4195 	}
4196 
4197 	if ((pool = pool_get_pool(poolconf, poolname)) == NULL) {
4198 		(void) pool_conf_close(poolconf);
4199 		pool_conf_free(poolconf);
4200 		return (Z_NO_POOL);
4201 	}
4202 
4203 	pe = pool_to_elem(poolconf, pool);
4204 	if (pool_get_property(poolconf, pe, "pool.scheduler", pv)
4205 	    != POC_INVAL) {
4206 		(void) pool_value_get_string(pv, &sched_str);
4207 		if (strlcpy(class, sched_str, clsize) >= clsize)
4208 			return (Z_TOO_BIG);
4209 	}
4210 
4211 	(void) pool_conf_close(poolconf);
4212 	pool_conf_free(poolconf);
4213 	return (Z_OK);
4214 }
4215 
4216 /*
4217  * Get the default scheduling class for the zone.  This will either be the
4218  * class set on the zone's pool or the system default scheduling class.
4219  */
4220 int
4221 zonecfg_get_dflt_sched_class(zone_dochandle_t handle, char *class, int clsize)
4222 {
4223 	char poolname[MAXPATHLEN];
4224 
4225 	if (zonecfg_get_pool(handle, poolname, sizeof (poolname)) == Z_OK) {
4226 		/* check if the zone's pool specified a sched class */
4227 		if (get_pool_sched_class(poolname, class, clsize) == Z_OK)
4228 			return (Z_OK);
4229 	}
4230 
4231 	if (priocntl(0, 0, PC_GETDFLCL, class, (uint64_t)clsize) == -1)
4232 		return (Z_TOO_BIG);
4233 
4234 	return (Z_OK);
4235 }
4236 
4237 int
4238 zonecfg_setfsent(zone_dochandle_t handle)
4239 {
4240 	return (zonecfg_setent(handle));
4241 }
4242 
4243 int
4244 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr)
4245 {
4246 	xmlNodePtr cur, options;
4247 	char options_str[MAX_MNTOPT_STR];
4248 	int err;
4249 
4250 	if (handle == NULL)
4251 		return (Z_INVAL);
4252 
4253 	if ((cur = handle->zone_dh_cur) == NULL)
4254 		return (Z_NO_ENTRY);
4255 
4256 	for (; cur != NULL; cur = cur->next)
4257 		if (!xmlStrcmp(cur->name, DTD_ELEM_FS))
4258 			break;
4259 	if (cur == NULL) {
4260 		handle->zone_dh_cur = handle->zone_dh_top;
4261 		return (Z_NO_ENTRY);
4262 	}
4263 
4264 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
4265 	    sizeof (tabptr->zone_fs_special))) != Z_OK) {
4266 		handle->zone_dh_cur = handle->zone_dh_top;
4267 		return (err);
4268 	}
4269 
4270 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
4271 	    sizeof (tabptr->zone_fs_raw))) != Z_OK) {
4272 		handle->zone_dh_cur = handle->zone_dh_top;
4273 		return (err);
4274 	}
4275 
4276 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
4277 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
4278 		handle->zone_dh_cur = handle->zone_dh_top;
4279 		return (err);
4280 	}
4281 
4282 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
4283 	    sizeof (tabptr->zone_fs_type))) != Z_OK) {
4284 		handle->zone_dh_cur = handle->zone_dh_top;
4285 		return (err);
4286 	}
4287 
4288 	/* OK for options to be NULL */
4289 	tabptr->zone_fs_options = NULL;
4290 	for (options = cur->xmlChildrenNode; options != NULL;
4291 	    options = options->next) {
4292 		if (fetchprop(options, DTD_ATTR_NAME, options_str,
4293 		    sizeof (options_str)) != Z_OK)
4294 			break;
4295 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
4296 			break;
4297 	}
4298 
4299 	handle->zone_dh_cur = cur->next;
4300 	return (Z_OK);
4301 }
4302 
4303 int
4304 zonecfg_endfsent(zone_dochandle_t handle)
4305 {
4306 	return (zonecfg_endent(handle));
4307 }
4308 
4309 int
4310 zonecfg_setipdent(zone_dochandle_t handle)
4311 {
4312 	return (zonecfg_setent(handle));
4313 }
4314 
4315 int
4316 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr)
4317 {
4318 	xmlNodePtr cur;
4319 	int err;
4320 
4321 	if (handle == NULL)
4322 		return (Z_INVAL);
4323 
4324 	if ((cur = handle->zone_dh_cur) == NULL)
4325 		return (Z_NO_ENTRY);
4326 
4327 	for (; cur != NULL; cur = cur->next)
4328 		if (!xmlStrcmp(cur->name, DTD_ELEM_IPD))
4329 			break;
4330 	if (cur == NULL) {
4331 		handle->zone_dh_cur = handle->zone_dh_top;
4332 		return (Z_NO_ENTRY);
4333 	}
4334 
4335 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
4336 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
4337 		handle->zone_dh_cur = handle->zone_dh_top;
4338 		return (err);
4339 	}
4340 
4341 	handle->zone_dh_cur = cur->next;
4342 	return (Z_OK);
4343 }
4344 
4345 int
4346 zonecfg_endipdent(zone_dochandle_t handle)
4347 {
4348 	return (zonecfg_endent(handle));
4349 }
4350 
4351 int
4352 zonecfg_setnwifent(zone_dochandle_t handle)
4353 {
4354 	return (zonecfg_setent(handle));
4355 }
4356 
4357 int
4358 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
4359 {
4360 	xmlNodePtr cur;
4361 	int err;
4362 
4363 	if (handle == NULL)
4364 		return (Z_INVAL);
4365 
4366 	if ((cur = handle->zone_dh_cur) == NULL)
4367 		return (Z_NO_ENTRY);
4368 
4369 	for (; cur != NULL; cur = cur->next)
4370 		if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
4371 			break;
4372 	if (cur == NULL) {
4373 		handle->zone_dh_cur = handle->zone_dh_top;
4374 		return (Z_NO_ENTRY);
4375 	}
4376 
4377 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
4378 	    sizeof (tabptr->zone_nwif_address))) != Z_OK) {
4379 		handle->zone_dh_cur = handle->zone_dh_top;
4380 		return (err);
4381 	}
4382 
4383 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
4384 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
4385 		handle->zone_dh_cur = handle->zone_dh_top;
4386 		return (err);
4387 	}
4388 
4389 	handle->zone_dh_cur = cur->next;
4390 	return (Z_OK);
4391 }
4392 
4393 int
4394 zonecfg_endnwifent(zone_dochandle_t handle)
4395 {
4396 	return (zonecfg_endent(handle));
4397 }
4398 
4399 int
4400 zonecfg_setdevent(zone_dochandle_t handle)
4401 {
4402 	return (zonecfg_setent(handle));
4403 }
4404 
4405 int
4406 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
4407 {
4408 	xmlNodePtr cur;
4409 	int err;
4410 
4411 	if (handle == NULL)
4412 		return (Z_INVAL);
4413 
4414 	if ((cur = handle->zone_dh_cur) == NULL)
4415 		return (Z_NO_ENTRY);
4416 
4417 	for (; cur != NULL; cur = cur->next)
4418 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
4419 			break;
4420 	if (cur == NULL) {
4421 		handle->zone_dh_cur = handle->zone_dh_top;
4422 		return (Z_NO_ENTRY);
4423 	}
4424 
4425 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
4426 	    sizeof (tabptr->zone_dev_match))) != Z_OK) {
4427 		handle->zone_dh_cur = handle->zone_dh_top;
4428 		return (err);
4429 	}
4430 
4431 	handle->zone_dh_cur = cur->next;
4432 	return (Z_OK);
4433 }
4434 
4435 int
4436 zonecfg_enddevent(zone_dochandle_t handle)
4437 {
4438 	return (zonecfg_endent(handle));
4439 }
4440 
4441 int
4442 zonecfg_setrctlent(zone_dochandle_t handle)
4443 {
4444 	return (zonecfg_setent(handle));
4445 }
4446 
4447 int
4448 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
4449 {
4450 	xmlNodePtr cur, val;
4451 	struct zone_rctlvaltab *valptr;
4452 	int err;
4453 
4454 	if (handle == NULL)
4455 		return (Z_INVAL);
4456 
4457 	if ((cur = handle->zone_dh_cur) == NULL)
4458 		return (Z_NO_ENTRY);
4459 
4460 	for (; cur != NULL; cur = cur->next)
4461 		if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL))
4462 			break;
4463 	if (cur == NULL) {
4464 		handle->zone_dh_cur = handle->zone_dh_top;
4465 		return (Z_NO_ENTRY);
4466 	}
4467 
4468 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name,
4469 	    sizeof (tabptr->zone_rctl_name))) != Z_OK) {
4470 		handle->zone_dh_cur = handle->zone_dh_top;
4471 		return (err);
4472 	}
4473 
4474 	tabptr->zone_rctl_valptr = NULL;
4475 	for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
4476 		valptr = (struct zone_rctlvaltab *)malloc(
4477 		    sizeof (struct zone_rctlvaltab));
4478 		if (valptr == NULL)
4479 			return (Z_NOMEM);
4480 		if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv,
4481 		    sizeof (valptr->zone_rctlval_priv)) != Z_OK)
4482 			break;
4483 		if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit,
4484 		    sizeof (valptr->zone_rctlval_limit)) != Z_OK)
4485 			break;
4486 		if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action,
4487 		    sizeof (valptr->zone_rctlval_action)) != Z_OK)
4488 			break;
4489 		if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK)
4490 			break;
4491 	}
4492 
4493 	handle->zone_dh_cur = cur->next;
4494 	return (Z_OK);
4495 }
4496 
4497 int
4498 zonecfg_endrctlent(zone_dochandle_t handle)
4499 {
4500 	return (zonecfg_endent(handle));
4501 }
4502 
4503 int
4504 zonecfg_setattrent(zone_dochandle_t handle)
4505 {
4506 	return (zonecfg_setent(handle));
4507 }
4508 
4509 int
4510 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr)
4511 {
4512 	xmlNodePtr cur;
4513 	int err;
4514 
4515 	if (handle == NULL)
4516 		return (Z_INVAL);
4517 
4518 	if ((cur = handle->zone_dh_cur) == NULL)
4519 		return (Z_NO_ENTRY);
4520 
4521 	for (; cur != NULL; cur = cur->next)
4522 		if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR))
4523 			break;
4524 	if (cur == NULL) {
4525 		handle->zone_dh_cur = handle->zone_dh_top;
4526 		return (Z_NO_ENTRY);
4527 	}
4528 
4529 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
4530 	    sizeof (tabptr->zone_attr_name))) != Z_OK) {
4531 		handle->zone_dh_cur = handle->zone_dh_top;
4532 		return (err);
4533 	}
4534 
4535 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
4536 	    sizeof (tabptr->zone_attr_type))) != Z_OK) {
4537 		handle->zone_dh_cur = handle->zone_dh_top;
4538 		return (err);
4539 	}
4540 
4541 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
4542 	    sizeof (tabptr->zone_attr_value))) != Z_OK) {
4543 		handle->zone_dh_cur = handle->zone_dh_top;
4544 		return (err);
4545 	}
4546 
4547 	handle->zone_dh_cur = cur->next;
4548 	return (Z_OK);
4549 }
4550 
4551 int
4552 zonecfg_endattrent(zone_dochandle_t handle)
4553 {
4554 	return (zonecfg_endent(handle));
4555 }
4556 
4557 /*
4558  * The privileges available on the system and described in privileges(5)
4559  * fall into four categories with respect to non-global zones:
4560  *
4561  *      Default set of privileges considered safe for all non-global
4562  *      zones.  These privileges are "safe" in the sense that a
4563  *      privileged process in the zone cannot affect processes in any
4564  *      other zone on the system.
4565  *
4566  *      Set of privileges not currently permitted within a non-global
4567  *      zone.  These privileges are considered by default, "unsafe,"
4568  *      and include ones which affect global resources (such as the
4569  *      system clock or physical memory) or are overly broad and cover
4570  *      more than one mechanism in the system.  In other cases, there
4571  *      has not been sufficient virtualization in the parts of the
4572  *      system the privilege covers to allow its use within a
4573  *      non-global zone.
4574  *
4575  *      Set of privileges required in order to get a zone booted and
4576  *      init(1M) started.  These cannot be removed from the zone's
4577  *      privilege set.
4578  *
4579  * All other privileges are optional and are potentially useful for
4580  * processes executing inside a non-global zone.
4581  *
4582  * When privileges are added to the system, a determination needs to be
4583  * made as to which category the privilege belongs to.  Ideally,
4584  * privileges should be fine-grained enough and the mechanisms they cover
4585  * virtualized enough so that they can be made available to non-global
4586  * zones.
4587  */
4588 
4589 /*
4590  * Define some of the tokens that priv_str_to_set(3C) recognizes.  Since
4591  * the privilege string separator can be any character, although it is
4592  * usually a comma character, define these here as well in the event that
4593  * they change or are augmented in the future.
4594  */
4595 #define	BASIC_TOKEN		"basic"
4596 #define	DEFAULT_TOKEN		"default"
4597 #define	ZONE_TOKEN		"zone"
4598 #define	TOKEN_PRIV_CHAR		','
4599 #define	TOKEN_PRIV_STR		","
4600 
4601 typedef struct priv_node {
4602 	struct priv_node	*pn_next;	/* Next privilege */
4603 	char			*pn_priv;	/* Privileges name */
4604 } priv_node_t;
4605 
4606 /* Privileges lists can differ across brands */
4607 typedef struct priv_lists {
4608 	/* Privileges considered safe for all non-global zones of a brand */
4609 	struct priv_node	*pl_default;
4610 
4611 	/* Privileges not permitted for all non-global zones of a brand */
4612 	struct priv_node	*pl_prohibited;
4613 
4614 	/* Privileges required for all non-global zones of a brand */
4615 	struct priv_node	*pl_required;
4616 
4617 	/*
4618 	 * ip-type of the zone these privileges lists apply to.
4619 	 * It is used to pass ip-type to the callback function,
4620 	 * priv_lists_cb, which has no way of getting the ip-type.
4621 	 */
4622 	const char		*pl_iptype;
4623 } priv_lists_t;
4624 
4625 static int
4626 priv_lists_cb(void *data, priv_iter_t *priv_iter)
4627 {
4628 	priv_lists_t *plp = (priv_lists_t *)data;
4629 	priv_node_t *pnp;
4630 
4631 	/* Skip this privilege if ip-type does not match */
4632 	if ((strcmp(priv_iter->pi_iptype, "all") != 0) &&
4633 	    (strcmp(priv_iter->pi_iptype, plp->pl_iptype) != 0))
4634 		return (0);
4635 
4636 	/* Allocate a new priv list node. */
4637 	if ((pnp = malloc(sizeof (*pnp))) == NULL)
4638 		return (-1);
4639 	if ((pnp->pn_priv = strdup(priv_iter->pi_name)) == NULL) {
4640 		free(pnp);
4641 		return (-1);
4642 	}
4643 
4644 	/* Insert the new priv list node into the right list */
4645 	if (strcmp(priv_iter->pi_set, "default") == 0) {
4646 		pnp->pn_next = plp->pl_default;
4647 		plp->pl_default = pnp;
4648 	} else if (strcmp(priv_iter->pi_set, "prohibited") == 0) {
4649 		pnp->pn_next = plp->pl_prohibited;
4650 		plp->pl_prohibited = pnp;
4651 	} else if (strcmp(priv_iter->pi_set, "required") == 0) {
4652 		pnp->pn_next = plp->pl_required;
4653 		plp->pl_required = pnp;
4654 	} else {
4655 		free(pnp->pn_priv);
4656 		free(pnp);
4657 		return (-1);
4658 	}
4659 	return (0);
4660 }
4661 
4662 static void
4663 priv_lists_destroy(priv_lists_t *plp)
4664 {
4665 	priv_node_t *pnp;
4666 
4667 	assert(plp != NULL);
4668 
4669 	while ((pnp = plp->pl_default) != NULL) {
4670 		plp->pl_default = pnp->pn_next;
4671 		free(pnp->pn_priv);
4672 		free(pnp);
4673 	}
4674 	while ((pnp = plp->pl_prohibited) != NULL) {
4675 		plp->pl_prohibited = pnp->pn_next;
4676 		free(pnp->pn_priv);
4677 		free(pnp);
4678 	}
4679 	while ((pnp = plp->pl_required) != NULL) {
4680 		plp->pl_required = pnp->pn_next;
4681 		free(pnp->pn_priv);
4682 		free(pnp);
4683 	}
4684 	free(plp);
4685 }
4686 
4687 static int
4688 priv_lists_create(zone_dochandle_t handle, priv_lists_t **plpp,
4689     const char *curr_iptype)
4690 {
4691 	priv_lists_t *plp;
4692 	brand_handle_t bh;
4693 	char brand[MAXNAMELEN];
4694 
4695 	if (handle != NULL) {
4696 		if (zonecfg_get_brand(handle, brand, sizeof (brand)) != 0)
4697 			return (Z_BRAND_ERROR);
4698 	} else {
4699 		(void) strlcpy(brand, NATIVE_BRAND_NAME, MAXNAMELEN);
4700 	}
4701 
4702 	if ((bh = brand_open(brand)) == NULL)
4703 		return (Z_BRAND_ERROR);
4704 
4705 	if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) {
4706 		brand_close(bh);
4707 		return (Z_NOMEM);
4708 	}
4709 
4710 	plp->pl_iptype = curr_iptype;
4711 
4712 	/* construct the privilege lists */
4713 	if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) {
4714 		priv_lists_destroy(plp);
4715 		brand_close(bh);
4716 		return (Z_BRAND_ERROR);
4717 	}
4718 
4719 	brand_close(bh);
4720 	*plpp = plp;
4721 	return (Z_OK);
4722 }
4723 
4724 static int
4725 get_default_privset(priv_set_t *privs, priv_lists_t *plp)
4726 {
4727 	priv_node_t *pnp;
4728 	priv_set_t *basic;
4729 
4730 	basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL);
4731 	if (basic == NULL)
4732 		return (errno == ENOMEM ? Z_NOMEM : Z_INVAL);
4733 
4734 	priv_union(basic, privs);
4735 	priv_freeset(basic);
4736 
4737 	for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) {
4738 		if (priv_addset(privs, pnp->pn_priv) != 0)
4739 			return (Z_INVAL);
4740 	}
4741 
4742 	return (Z_OK);
4743 }
4744 
4745 int
4746 zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype)
4747 {
4748 	priv_lists_t *plp;
4749 	int ret;
4750 
4751 	if ((ret = priv_lists_create(NULL, &plp, curr_iptype)) != Z_OK)
4752 		return (ret);
4753 	ret = get_default_privset(privs, plp);
4754 	priv_lists_destroy(plp);
4755 	return (ret);
4756 }
4757 
4758 void
4759 append_priv_token(char *priv, char *str, size_t strlen)
4760 {
4761 	if (*str != '\0')
4762 		(void) strlcat(str, TOKEN_PRIV_STR, strlen);
4763 	(void) strlcat(str, priv, strlen);
4764 }
4765 
4766 /*
4767  * Verify that the supplied string is a valid privilege limit set for a
4768  * non-global zone.  This string must not only be acceptable to
4769  * priv_str_to_set(3C) which parses it, but it also must resolve to a
4770  * privilege set that includes certain required privileges and lacks
4771  * certain prohibited privileges.
4772  */
4773 static int
4774 verify_privset(char *privbuf, priv_set_t *privs, char **privname,
4775     boolean_t add_default, priv_lists_t *plp)
4776 {
4777 	priv_node_t *pnp;
4778 	char *tmp, *cp, *lasts;
4779 	size_t len;
4780 	priv_set_t *mergeset;
4781 	const char *token;
4782 
4783 	/*
4784 	 * The verification of the privilege string occurs in several
4785 	 * phases.  In the first phase, the supplied string is scanned for
4786 	 * the ZONE_TOKEN token which is not support as part of the
4787 	 * "limitpriv" property.
4788 	 *
4789 	 * Duplicate the supplied privilege string since strtok_r(3C)
4790 	 * tokenizes its input by null-terminating the tokens.
4791 	 */
4792 	if ((tmp = strdup(privbuf)) == NULL)
4793 		return (Z_NOMEM);
4794 	for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL;
4795 	    cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) {
4796 		if (strcmp(cp, ZONE_TOKEN) == 0) {
4797 			free(tmp);
4798 			if ((*privname = strdup(ZONE_TOKEN)) == NULL)
4799 				return (Z_NOMEM);
4800 			else
4801 				return (Z_PRIV_UNKNOWN);
4802 		}
4803 	}
4804 	free(tmp);
4805 
4806 	if (add_default) {
4807 		/*
4808 		 * If DEFAULT_TOKEN was specified, a string needs to be
4809 		 * built containing the privileges from the default, safe
4810 		 * set along with those of the "limitpriv" property.
4811 		 */
4812 		len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2;
4813 
4814 		for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
4815 			len += strlen(pnp->pn_priv) + 1;
4816 		tmp = alloca(len);
4817 		*tmp = '\0';
4818 
4819 		append_priv_token(BASIC_TOKEN, tmp, len);
4820 		for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
4821 			append_priv_token(pnp->pn_priv, tmp, len);
4822 		(void) strlcat(tmp, TOKEN_PRIV_STR, len);
4823 		(void) strlcat(tmp, privbuf, len);
4824 	} else {
4825 		tmp = privbuf;
4826 	}
4827 
4828 
4829 	/*
4830 	 * In the next phase, attempt to convert the merged privilege
4831 	 * string into a privilege set.  In the case of an error, either
4832 	 * there was a memory allocation failure or there was an invalid
4833 	 * privilege token in the string.  In either case, return an
4834 	 * appropriate error code but in the event of an invalid token,
4835 	 * allocate a string containing its name and return that back to
4836 	 * the caller.
4837 	 */
4838 	mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token);
4839 	if (mergeset == NULL) {
4840 		if (token == NULL)
4841 			return (Z_NOMEM);
4842 		if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL)
4843 			*cp = '\0';
4844 		if ((*privname = strdup(token)) == NULL)
4845 			return (Z_NOMEM);
4846 		else
4847 			return (Z_PRIV_UNKNOWN);
4848 	}
4849 
4850 	/*
4851 	 * Next, verify that none of the prohibited zone privileges are
4852 	 * present in the merged privilege set.
4853 	 */
4854 	for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) {
4855 		if (priv_ismember(mergeset, pnp->pn_priv)) {
4856 			priv_freeset(mergeset);
4857 			if ((*privname = strdup(pnp->pn_priv)) == NULL)
4858 				return (Z_NOMEM);
4859 			else
4860 				return (Z_PRIV_PROHIBITED);
4861 		}
4862 	}
4863 
4864 	/*
4865 	 * Finally, verify that all of the required zone privileges are
4866 	 * present in the merged privilege set.
4867 	 */
4868 	for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) {
4869 		if (!priv_ismember(mergeset, pnp->pn_priv)) {
4870 			priv_freeset(mergeset);
4871 			if ((*privname = strdup(pnp->pn_priv)) == NULL)
4872 				return (Z_NOMEM);
4873 			else
4874 				return (Z_PRIV_REQUIRED);
4875 		}
4876 	}
4877 
4878 	priv_copyset(mergeset, privs);
4879 	priv_freeset(mergeset);
4880 	return (Z_OK);
4881 }
4882 
4883 /*
4884  * Fill in the supplied privilege set with either the default, safe set of
4885  * privileges suitable for a non-global zone, or one based on the
4886  * "limitpriv" property in the zone's configuration.
4887  *
4888  * In the event of an invalid privilege specification in the
4889  * configuration, a string is allocated and returned containing the
4890  * "privilege" causing the issue.  It is the caller's responsibility to
4891  * free this memory when it is done with it.
4892  */
4893 int
4894 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs,
4895     char **privname)
4896 {
4897 	priv_lists_t *plp;
4898 	char *cp, *limitpriv = NULL;
4899 	int err, limitlen;
4900 	zone_iptype_t iptype;
4901 	const char *curr_iptype;
4902 
4903 	/*
4904 	 * Attempt to lookup the "limitpriv" property.  If it does not
4905 	 * exist or matches the string DEFAULT_TOKEN exactly, then the
4906 	 * default, safe privilege set is returned.
4907 	 */
4908 	if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK)
4909 		return (err);
4910 
4911 	if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
4912 		return (err);
4913 
4914 	switch (iptype) {
4915 	case ZS_SHARED:
4916 		curr_iptype = "shared";
4917 		break;
4918 	case ZS_EXCLUSIVE:
4919 		curr_iptype = "exclusive";
4920 		break;
4921 	}
4922 
4923 	if ((err = priv_lists_create(handle, &plp, curr_iptype)) != Z_OK)
4924 		return (err);
4925 
4926 	limitlen = strlen(limitpriv);
4927 	if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) {
4928 		free(limitpriv);
4929 		err = get_default_privset(privs, plp);
4930 		priv_lists_destroy(plp);
4931 		return (err);
4932 	}
4933 
4934 	/*
4935 	 * Check if the string DEFAULT_TOKEN is the first token in a list
4936 	 * of privileges.
4937 	 */
4938 	cp = strchr(limitpriv, TOKEN_PRIV_CHAR);
4939 	if (cp != NULL &&
4940 	    strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0)
4941 		err = verify_privset(cp + 1, privs, privname, B_TRUE, plp);
4942 	else
4943 		err = verify_privset(limitpriv, privs, privname, B_FALSE, plp);
4944 
4945 	free(limitpriv);
4946 	priv_lists_destroy(plp);
4947 	return (err);
4948 }
4949 
4950 int
4951 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
4952 {
4953 	zone_dochandle_t handle;
4954 	boolean_t found = B_FALSE;
4955 	struct zoneent *ze;
4956 	FILE *cookie;
4957 	int err;
4958 	char *cp;
4959 
4960 	if (zone_name == NULL)
4961 		return (Z_INVAL);
4962 
4963 	(void) strlcpy(zonepath, zonecfg_root, rp_sz);
4964 	cp = zonepath + strlen(zonepath);
4965 	while (cp > zonepath && cp[-1] == '/')
4966 		*--cp = '\0';
4967 
4968 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
4969 		if (zonepath[0] == '\0')
4970 			(void) strlcpy(zonepath, "/", rp_sz);
4971 		return (Z_OK);
4972 	}
4973 
4974 	/*
4975 	 * First check the index file.  Because older versions did not have
4976 	 * a copy of the zone path, allow for it to be zero length, in which
4977 	 * case we ignore this result and fall back to the XML files.
4978 	 */
4979 	cookie = setzoneent();
4980 	while ((ze = getzoneent_private(cookie)) != NULL) {
4981 		if (strcmp(ze->zone_name, zone_name) == 0) {
4982 			found = B_TRUE;
4983 			if (ze->zone_path[0] != '\0')
4984 				(void) strlcpy(cp, ze->zone_path,
4985 				    rp_sz - (cp - zonepath));
4986 		}
4987 		free(ze);
4988 		if (found)
4989 			break;
4990 	}
4991 	endzoneent(cookie);
4992 	if (found && *cp != '\0')
4993 		return (Z_OK);
4994 
4995 	/* Fall back to the XML files. */
4996 	if ((handle = zonecfg_init_handle()) == NULL)
4997 		return (Z_NOMEM);
4998 
4999 	/*
5000 	 * Check the snapshot first: if a zone is running, its zonepath
5001 	 * may have changed.
5002 	 */
5003 	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
5004 		if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) {
5005 			zonecfg_fini_handle(handle);
5006 			return (err);
5007 		}
5008 	}
5009 	err = zonecfg_get_zonepath(handle, zonepath, rp_sz);
5010 	zonecfg_fini_handle(handle);
5011 	return (err);
5012 }
5013 
5014 int
5015 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz)
5016 {
5017 	int err;
5018 
5019 	/* This function makes sense for non-global zones only. */
5020 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5021 		return (Z_BOGUS_ZONE_NAME);
5022 	if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK)
5023 		return (err);
5024 	if (strlcat(rootpath, "/root", rp_sz) >= rp_sz)
5025 		return (Z_TOO_BIG);
5026 	return (Z_OK);
5027 }
5028 
5029 int
5030 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz)
5031 {
5032 	int err;
5033 	zone_dochandle_t handle;
5034 	char myzone[MAXNAMELEN];
5035 	int myzoneid = getzoneid();
5036 
5037 	/*
5038 	 * If we are not in the global zone, then we don't have the zone
5039 	 * .xml files with the brand name available.  Thus, we are going to
5040 	 * have to ask the kernel for the information.
5041 	 */
5042 	if (myzoneid != GLOBAL_ZONEID) {
5043 		if (is_system_labeled()) {
5044 			(void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz);
5045 			return (Z_OK);
5046 		}
5047 		if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone,
5048 		    sizeof (myzone)) < 0)
5049 			return (Z_NO_ZONE);
5050 		if (strncmp(zone_name, myzone, MAXNAMELEN) != NULL)
5051 			return (Z_NO_ZONE);
5052 		err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz);
5053 		if (err < 0)
5054 			return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5055 		return (Z_OK);
5056 	}
5057 
5058 	if (strcmp(zone_name, "global") == NULL) {
5059 		(void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz);
5060 		return (Z_OK);
5061 	}
5062 	if ((handle = zonecfg_init_handle()) == NULL)
5063 		return (Z_NOMEM);
5064 
5065 	err = zonecfg_get_handle((char *)zone_name, handle);
5066 	if (err == Z_OK)
5067 		err = zonecfg_get_brand(handle, brandname, rp_sz);
5068 
5069 	zonecfg_fini_handle(handle);
5070 	return (err);
5071 }
5072 
5073 /*
5074  * Return the appropriate root for the active /dev.
5075  * For normal zone, the path is $ZONEPATH/root;
5076  * for scratch zone, the dev path is $ZONEPATH/lu.
5077  */
5078 int
5079 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5080 {
5081 	int err;
5082 	char *suffix;
5083 	zone_state_t state;
5084 
5085 	/* This function makes sense for non-global zones only. */
5086 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5087 		return (Z_BOGUS_ZONE_NAME);
5088 	if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5089 		return (err);
5090 
5091 	if (zone_get_state(zone_name, &state) == Z_OK &&
5092 	    state == ZONE_STATE_MOUNTED)
5093 		suffix = "/lu";
5094 	else
5095 		suffix = "/root";
5096 	if (strlcat(devroot, suffix, rp_sz) >= rp_sz)
5097 		return (Z_TOO_BIG);
5098 	return (Z_OK);
5099 }
5100 
5101 static zone_state_t
5102 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state)
5103 {
5104 	char zoneroot[MAXPATHLEN];
5105 	size_t zlen;
5106 
5107 	assert(kernel_state <= ZONE_MAX_STATE);
5108 	switch (kernel_state) {
5109 		case ZONE_IS_UNINITIALIZED:
5110 			return (ZONE_STATE_READY);
5111 		case ZONE_IS_READY:
5112 			/*
5113 			 * If the zone's root is mounted on $ZONEPATH/lu, then
5114 			 * it's a mounted scratch zone.
5115 			 */
5116 			if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
5117 			    sizeof (zoneroot)) >= 0) {
5118 				zlen = strlen(zoneroot);
5119 				if (zlen > 3 &&
5120 				    strcmp(zoneroot + zlen - 3, "/lu") == 0)
5121 					return (ZONE_STATE_MOUNTED);
5122 			}
5123 			return (ZONE_STATE_READY);
5124 		case ZONE_IS_BOOTING:
5125 		case ZONE_IS_RUNNING:
5126 			return (ZONE_STATE_RUNNING);
5127 		case ZONE_IS_SHUTTING_DOWN:
5128 		case ZONE_IS_EMPTY:
5129 			return (ZONE_STATE_SHUTTING_DOWN);
5130 		case ZONE_IS_DOWN:
5131 		case ZONE_IS_DYING:
5132 		case ZONE_IS_DEAD:
5133 		default:
5134 			return (ZONE_STATE_DOWN);
5135 	}
5136 	/* NOTREACHED */
5137 }
5138 
5139 int
5140 zone_get_state(char *zone_name, zone_state_t *state_num)
5141 {
5142 	zone_status_t status;
5143 	zoneid_t zone_id;
5144 	struct zoneent *ze;
5145 	boolean_t found = B_FALSE;
5146 	FILE *cookie;
5147 	char kernzone[ZONENAME_MAX];
5148 	FILE *fp;
5149 
5150 	if (zone_name == NULL)
5151 		return (Z_INVAL);
5152 
5153 	/*
5154 	 * If we're looking at an alternate root, then we need to query the
5155 	 * kernel using the scratch zone name.
5156 	 */
5157 	zone_id = -1;
5158 	if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
5159 		if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
5160 			if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
5161 			    kernzone, sizeof (kernzone)) == 0)
5162 				zone_id = getzoneidbyname(kernzone);
5163 			zonecfg_close_scratch(fp);
5164 		}
5165 	} else {
5166 		zone_id = getzoneidbyname(zone_name);
5167 	}
5168 
5169 	/* check to see if zone is running */
5170 	if (zone_id != -1 &&
5171 	    zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
5172 	    sizeof (status)) >= 0) {
5173 		*state_num = kernel_state_to_user_state(zone_id, status);
5174 		return (Z_OK);
5175 	}
5176 
5177 	cookie = setzoneent();
5178 	while ((ze = getzoneent_private(cookie)) != NULL) {
5179 		if (strcmp(ze->zone_name, zone_name) == 0) {
5180 			found = B_TRUE;
5181 			*state_num = ze->zone_state;
5182 		}
5183 		free(ze);
5184 		if (found)
5185 			break;
5186 	}
5187 	endzoneent(cookie);
5188 	return ((found) ? Z_OK : Z_NO_ZONE);
5189 }
5190 
5191 int
5192 zone_set_state(char *zone, zone_state_t state)
5193 {
5194 	struct zoneent ze;
5195 
5196 	if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
5197 	    state != ZONE_STATE_INCOMPLETE)
5198 		return (Z_INVAL);
5199 
5200 	bzero(&ze, sizeof (ze));
5201 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
5202 	ze.zone_state = state;
5203 	(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
5204 	return (putzoneent(&ze, PZE_MODIFY));
5205 }
5206 
5207 /*
5208  * Get id (if any) for specified zone.  There are four possible outcomes:
5209  * - If the string corresponds to the numeric id of an active (booted)
5210  *   zone, sets *zip to the zone id and returns 0.
5211  * - If the string corresponds to the name of an active (booted) zone,
5212  *   sets *zip to the zone id and returns 0.
5213  * - If the string is a name in the configuration but is not booted,
5214  *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
5215  * - Otherwise, leaves *zip unchanged and returns -1.
5216  *
5217  * This function acts as an auxiliary filter on the function of the same
5218  * name in libc; the linker binds to this version if libzonecfg exists,
5219  * and the libc version if it doesn't.  Any changes to this version of
5220  * the function should probably be reflected in the libc version as well.
5221  */
5222 int
5223 zone_get_id(const char *str, zoneid_t *zip)
5224 {
5225 	zone_dochandle_t hdl;
5226 	zoneid_t zoneid;
5227 	char *cp;
5228 	int err;
5229 
5230 	/* first try looking for active zone by id */
5231 	errno = 0;
5232 	zoneid = (zoneid_t)strtol(str, &cp, 0);
5233 	if (errno == 0 && cp != str && *cp == '\0' &&
5234 	    getzonenamebyid(zoneid, NULL, 0) != -1) {
5235 		*zip = zoneid;
5236 		return (0);
5237 	}
5238 
5239 	/* then look for active zone by name */
5240 	if ((zoneid = getzoneidbyname(str)) != -1) {
5241 		*zip = zoneid;
5242 		return (0);
5243 	}
5244 
5245 	/* if in global zone, try looking up name in configuration database */
5246 	if (getzoneid() != GLOBAL_ZONEID ||
5247 	    (hdl = zonecfg_init_handle()) == NULL)
5248 		return (-1);
5249 
5250 	if (zonecfg_get_handle(str, hdl) == Z_OK) {
5251 		/* zone exists but isn't active */
5252 		*zip = ZONE_ID_UNDEFINED;
5253 		err = 0;
5254 	} else {
5255 		err = -1;
5256 	}
5257 
5258 	zonecfg_fini_handle(hdl);
5259 	return (err);
5260 }
5261 
5262 char *
5263 zone_state_str(zone_state_t state_num)
5264 {
5265 	switch (state_num) {
5266 	case ZONE_STATE_CONFIGURED:
5267 		return (ZONE_STATE_STR_CONFIGURED);
5268 	case ZONE_STATE_INCOMPLETE:
5269 		return (ZONE_STATE_STR_INCOMPLETE);
5270 	case ZONE_STATE_INSTALLED:
5271 		return (ZONE_STATE_STR_INSTALLED);
5272 	case ZONE_STATE_READY:
5273 		return (ZONE_STATE_STR_READY);
5274 	case ZONE_STATE_MOUNTED:
5275 		return (ZONE_STATE_STR_MOUNTED);
5276 	case ZONE_STATE_RUNNING:
5277 		return (ZONE_STATE_STR_RUNNING);
5278 	case ZONE_STATE_SHUTTING_DOWN:
5279 		return (ZONE_STATE_STR_SHUTTING_DOWN);
5280 	case ZONE_STATE_DOWN:
5281 		return (ZONE_STATE_STR_DOWN);
5282 	default:
5283 		return ("unknown");
5284 	}
5285 }
5286 
5287 /*
5288  * Given a UUID value, find an associated zone name.  This is intended to be
5289  * used by callers who set up some 'default' name (corresponding to the
5290  * expected name for the zone) in the zonename buffer, and thus the function
5291  * doesn't touch this buffer on failure.
5292  */
5293 int
5294 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen)
5295 {
5296 	FILE *fp;
5297 	struct zoneent *ze;
5298 	uchar_t *uuid;
5299 
5300 	/*
5301 	 * A small amount of subterfuge via casts is necessary here because
5302 	 * libuuid doesn't use const correctly, but we don't want to export
5303 	 * this brokenness to our clients.
5304 	 */
5305 	uuid = (uchar_t *)uuidin;
5306 	if (uuid_is_null(uuid))
5307 		return (Z_NO_ZONE);
5308 	if ((fp = setzoneent()) == NULL)
5309 		return (Z_NO_ZONE);
5310 	while ((ze = getzoneent_private(fp)) != NULL) {
5311 		if (uuid_compare(uuid, ze->zone_uuid) == 0)
5312 			break;
5313 		free(ze);
5314 	}
5315 	endzoneent(fp);
5316 	if (ze != NULL) {
5317 		(void) strlcpy(zonename, ze->zone_name, namelen);
5318 		free(ze);
5319 		return (Z_OK);
5320 	} else {
5321 		return (Z_NO_ZONE);
5322 	}
5323 }
5324 
5325 /*
5326  * Given a zone name, get its UUID.  Returns a "NULL" UUID value if the zone
5327  * exists but the file doesn't have a value set yet.  Returns an error if the
5328  * zone cannot be located.
5329  */
5330 int
5331 zonecfg_get_uuid(const char *zonename, uuid_t uuid)
5332 {
5333 	FILE *fp;
5334 	struct zoneent *ze;
5335 
5336 	if ((fp = setzoneent()) == NULL)
5337 		return (Z_NO_ZONE);
5338 	while ((ze = getzoneent_private(fp)) != NULL) {
5339 		if (strcmp(ze->zone_name, zonename) == 0)
5340 			break;
5341 		free(ze);
5342 	}
5343 	endzoneent(fp);
5344 	if (ze != NULL) {
5345 		uuid_copy(uuid, ze->zone_uuid);
5346 		free(ze);
5347 		return (Z_OK);
5348 	} else {
5349 		return (Z_NO_ZONE);
5350 	}
5351 }
5352 
5353 /*
5354  * File-system convenience functions.
5355  */
5356 boolean_t
5357 zonecfg_valid_fs_type(const char *type)
5358 {
5359 	/*
5360 	 * We already know which FS types don't work.
5361 	 */
5362 	if (strcmp(type, "proc") == 0 ||
5363 	    strcmp(type, "mntfs") == 0 ||
5364 	    strcmp(type, "autofs") == 0 ||
5365 	    strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 ||
5366 	    strcmp(type, "cachefs") == 0)
5367 		return (B_FALSE);
5368 	/*
5369 	 * The caller may do more detailed verification to make sure other
5370 	 * aspects of this filesystem type make sense.
5371 	 */
5372 	return (B_TRUE);
5373 }
5374 
5375 /*
5376  * Generally uninteresting rctl convenience functions.
5377  */
5378 
5379 int
5380 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
5381     rctlblk_t *rctlblk)
5382 {
5383 	unsigned long long ull;
5384 	char *endp;
5385 	rctl_priv_t priv;
5386 	rctl_qty_t limit;
5387 	uint_t action;
5388 
5389 	/* Get the privilege */
5390 	if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
5391 		priv = RCPRIV_BASIC;
5392 	} else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
5393 		priv = RCPRIV_PRIVILEGED;
5394 	} else {
5395 		/* Invalid privilege */
5396 		return (Z_INVAL);
5397 	}
5398 
5399 	/* deal with negative input; strtoull(3c) doesn't do what we want */
5400 	if (rctlval->zone_rctlval_limit[0] == '-')
5401 		return (Z_INVAL);
5402 	/* Get the limit */
5403 	errno = 0;
5404 	ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
5405 	if (errno != 0 || *endp != '\0') {
5406 		/* parse failed */
5407 		return (Z_INVAL);
5408 	}
5409 	limit = (rctl_qty_t)ull;
5410 
5411 	/* Get the action */
5412 	if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
5413 		action = RCTL_LOCAL_NOACTION;
5414 	} else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
5415 		action = RCTL_LOCAL_SIGNAL;
5416 	} else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
5417 		action = RCTL_LOCAL_DENY;
5418 	} else {
5419 		/* Invalid Action */
5420 		return (Z_INVAL);
5421 	}
5422 	rctlblk_set_local_action(rctlblk, action, 0);
5423 	rctlblk_set_privilege(rctlblk, priv);
5424 	rctlblk_set_value(rctlblk, limit);
5425 	return (Z_OK);
5426 }
5427 
5428 static int
5429 rctl_check(const char *rctlname, void *arg)
5430 {
5431 	const char *attrname = arg;
5432 
5433 	/*
5434 	 * Returning 1 here is our signal to zonecfg_is_rctl() that it is
5435 	 * indeed an rctl name recognized by the system.
5436 	 */
5437 	return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
5438 }
5439 
5440 boolean_t
5441 zonecfg_is_rctl(const char *name)
5442 {
5443 	return (rctl_walk(rctl_check, (void *)name) == 1);
5444 }
5445 
5446 boolean_t
5447 zonecfg_valid_rctlname(const char *name)
5448 {
5449 	const char *c;
5450 
5451 	if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
5452 		return (B_FALSE);
5453 	if (strlen(name) == sizeof ("zone.") - 1)
5454 		return (B_FALSE);
5455 	for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
5456 		if (!isalpha(*c) && *c != '-')
5457 			return (B_FALSE);
5458 	}
5459 	return (B_TRUE);
5460 }
5461 
5462 boolean_t
5463 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
5464 {
5465 	rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
5466 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
5467 
5468 	if (priv != RCPRIV_PRIVILEGED)
5469 		return (B_FALSE);
5470 	if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
5471 		return (B_FALSE);
5472 	return (B_TRUE);
5473 }
5474 
5475 boolean_t
5476 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
5477 {
5478 	rctlblk_t *current, *next;
5479 	rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
5480 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
5481 	uint_t global_flags;
5482 
5483 	if (!zonecfg_valid_rctlblk(rctlblk))
5484 		return (B_FALSE);
5485 	if (!zonecfg_valid_rctlname(name))
5486 		return (B_FALSE);
5487 
5488 	current = alloca(rctlblk_size());
5489 	if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
5490 		return (B_TRUE);	/* not an rctl on this system */
5491 	/*
5492 	 * Make sure the proposed value isn't greater than the current system
5493 	 * value.
5494 	 */
5495 	next = alloca(rctlblk_size());
5496 	while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
5497 		rctlblk_t *tmp;
5498 
5499 		if (getrctl(name, current, next, RCTL_NEXT) != 0)
5500 			return (B_FALSE);	/* shouldn't happen */
5501 		tmp = current;
5502 		current = next;
5503 		next = tmp;
5504 	}
5505 	if (limit > rctlblk_get_value(current))
5506 		return (B_FALSE);
5507 
5508 	/*
5509 	 * Make sure the proposed action is allowed.
5510 	 */
5511 	global_flags = rctlblk_get_global_flags(current);
5512 	if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
5513 	    action == RCTL_LOCAL_DENY)
5514 		return (B_FALSE);
5515 	if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
5516 	    action == RCTL_LOCAL_NOACTION)
5517 		return (B_FALSE);
5518 
5519 	return (B_TRUE);
5520 }
5521 
5522 /*
5523  * There is always a race condition between reading the initial copy of
5524  * a zones state and its state changing.  We address this by providing
5525  * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
5526  * When zonecfg_critical_enter is called, sets the state field to LOCKED
5527  * and aquires biglock. Biglock protects against other threads executing
5528  * critical_enter and the state field protects against state changes during
5529  * the critical period.
5530  *
5531  * If any state changes occur, zn_cb will set the failed field of the znotify
5532  * structure.  This will cause the critical_exit function to re-lock the
5533  * channel and return an error. Since evsnts may be delayed, the critical_exit
5534  * function "flushes" the queue by putting an event on the queue and waiting for
5535  * zn_cb to notify critical_exit that it received the ping event.
5536  */
5537 static const char *
5538 string_get_tok(const char *in, char delim, int num)
5539 {
5540 	int i = 0;
5541 
5542 	for (; i < num; in++) {
5543 		if (*in == delim)
5544 			i++;
5545 		if (*in == 0)
5546 			return (NULL);
5547 	}
5548 	return (in);
5549 }
5550 
5551 static boolean_t
5552 is_ping(sysevent_t *ev)
5553 {
5554 	if (strcmp(sysevent_get_subclass_name(ev),
5555 	    ZONE_EVENT_PING_SUBCLASS) == 0) {
5556 		return (B_TRUE);
5557 	} else {
5558 		return (B_FALSE);
5559 	}
5560 }
5561 
5562 static boolean_t
5563 is_my_ping(sysevent_t *ev)
5564 {
5565 	const char *sender;
5566 	char mypid[sizeof (pid_t) * 3 + 1];
5567 
5568 	(void) snprintf(mypid, sizeof (mypid), "%i", getpid());
5569 	sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
5570 	if (sender == NULL)
5571 		return (B_FALSE);
5572 	if (strcmp(sender, mypid) != 0)
5573 		return (B_FALSE);
5574 	return (B_TRUE);
5575 }
5576 
5577 static int
5578 do_callback(struct znotify *zevtchan, sysevent_t *ev)
5579 {
5580 	nvlist_t *l;
5581 	int zid;
5582 	char *zonename;
5583 	char *newstate;
5584 	char *oldstate;
5585 	int ret;
5586 	hrtime_t when;
5587 
5588 	if (strcmp(sysevent_get_subclass_name(ev),
5589 	    ZONE_EVENT_STATUS_SUBCLASS) == 0) {
5590 
5591 		if (sysevent_get_attr_list(ev, &l) != 0) {
5592 			if (errno == ENOMEM) {
5593 				zevtchan->zn_failure_count++;
5594 				return (EAGAIN);
5595 			}
5596 			return (0);
5597 		}
5598 		ret = 0;
5599 
5600 		if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
5601 		    (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
5602 		    == 0) &&
5603 		    (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
5604 		    == 0) &&
5605 		    (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
5606 		    (uint64_t *)&when) == 0) &&
5607 		    (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
5608 			ret = zevtchan->zn_callback(zonename, zid, newstate,
5609 			    oldstate, when, zevtchan->zn_private);
5610 		}
5611 
5612 		zevtchan->zn_failure_count = 0;
5613 		nvlist_free(l);
5614 		return (ret);
5615 	} else {
5616 		/*
5617 		 * We have received an event in an unknown subclass. Ignore.
5618 		 */
5619 		zevtchan->zn_failure_count = 0;
5620 		return (0);
5621 	}
5622 }
5623 
5624 static int
5625 zn_cb(sysevent_t *ev, void *p)
5626 {
5627 	struct znotify *zevtchan = p;
5628 	int error;
5629 
5630 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
5631 
5632 	if (is_ping(ev) && !is_my_ping(ev)) {
5633 		(void) pthread_mutex_unlock((&zevtchan->zn_mutex));
5634 		return (0);
5635 	}
5636 
5637 	if (zevtchan->zn_state == ZN_LOCKED) {
5638 		assert(!is_ping(ev));
5639 		zevtchan->zn_failed = B_TRUE;
5640 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5641 		return (0);
5642 	}
5643 
5644 	if (zevtchan->zn_state == ZN_PING_INFLIGHT) {
5645 		if (is_ping(ev)) {
5646 			zevtchan->zn_state = ZN_PING_RECEIVED;
5647 			(void) pthread_cond_signal(&(zevtchan->zn_cond));
5648 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5649 			return (0);
5650 		} else {
5651 			zevtchan->zn_failed = B_TRUE;
5652 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5653 			return (0);
5654 		}
5655 	}
5656 
5657 	if (zevtchan->zn_state == ZN_UNLOCKED) {
5658 
5659 		error = do_callback(zevtchan, ev);
5660 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5661 		/*
5662 		 * Every ENOMEM failure causes do_callback to increment
5663 		 * zn_failure_count and every success causes it to
5664 		 * set zn_failure_count to zero.  If we got EAGAIN,
5665 		 * we will sleep for zn_failure_count seconds and return
5666 		 * EAGAIN to gpec to try again.
5667 		 *
5668 		 * After 55 seconds, or 10 try's we give up and drop the
5669 		 * event.
5670 		 */
5671 		if (error == EAGAIN) {
5672 			if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) {
5673 				return (0);
5674 			}
5675 			(void) sleep(zevtchan->zn_failure_count);
5676 		}
5677 		return (error);
5678 	}
5679 
5680 	if (zevtchan->zn_state == ZN_PING_RECEIVED) {
5681 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5682 		return (0);
5683 	}
5684 
5685 	abort();
5686 	return (0);
5687 }
5688 
5689 void
5690 zonecfg_notify_critical_enter(void *h)
5691 {
5692 	struct znotify *zevtchan = h;
5693 
5694 	(void) pthread_mutex_lock(&(zevtchan->zn_bigmutex));
5695 	zevtchan->zn_state = ZN_LOCKED;
5696 }
5697 
5698 int
5699 zonecfg_notify_critical_exit(void * h)
5700 {
5701 
5702 	struct znotify *zevtchan = h;
5703 
5704 	if (zevtchan->zn_state == ZN_UNLOCKED)
5705 		return (0);
5706 
5707 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
5708 	zevtchan->zn_state = ZN_PING_INFLIGHT;
5709 
5710 	(void) sysevent_evc_publish(zevtchan->zn_eventchan,
5711 	    ZONE_EVENT_STATUS_CLASS,
5712 	    ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER,
5713 	    zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP);
5714 
5715 	while (zevtchan->zn_state != ZN_PING_RECEIVED) {
5716 		(void) pthread_cond_wait(&(zevtchan->zn_cond),
5717 		    &(zevtchan->zn_mutex));
5718 	}
5719 
5720 	if (zevtchan->zn_failed == B_TRUE) {
5721 		zevtchan->zn_state = ZN_LOCKED;
5722 		zevtchan->zn_failed = B_FALSE;
5723 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5724 		return (1);
5725 	}
5726 
5727 	zevtchan->zn_state = ZN_UNLOCKED;
5728 	(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5729 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
5730 	return (0);
5731 }
5732 
5733 void
5734 zonecfg_notify_critical_abort(void *h)
5735 {
5736 	struct znotify *zevtchan = h;
5737 
5738 	zevtchan->zn_state = ZN_UNLOCKED;
5739 	zevtchan->zn_failed = B_FALSE;
5740 	/*
5741 	 * Don't do anything about zn_lock. If it is held, it could only be
5742 	 * held by zn_cb and it will be unlocked soon.
5743 	 */
5744 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
5745 }
5746 
5747 void *
5748 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
5749     const char *newstate, const char *oldstate, hrtime_t when, void *p),
5750     void *p)
5751 {
5752 	struct znotify *zevtchan;
5753 	int i = 1;
5754 	int r;
5755 
5756 	zevtchan = malloc(sizeof (struct znotify));
5757 
5758 	if (zevtchan == NULL)
5759 		return (NULL);
5760 
5761 	zevtchan->zn_private = p;
5762 	zevtchan->zn_callback = func;
5763 	zevtchan->zn_state = ZN_UNLOCKED;
5764 	zevtchan->zn_failed = B_FALSE;
5765 
5766 	if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL))
5767 		goto out3;
5768 	if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) {
5769 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
5770 		goto out3;
5771 	}
5772 	if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) {
5773 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
5774 		(void) pthread_cond_destroy(&(zevtchan->zn_cond));
5775 		goto out3;
5776 	}
5777 
5778 	if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan),
5779 	    0) != 0)
5780 		goto out2;
5781 
5782 	do {
5783 		/*
5784 		 * At 4 digits the subscriber ID gets too long and we have
5785 		 * no chance of successfully registering.
5786 		 */
5787 		if (i > 999)
5788 			goto out1;
5789 
5790 		(void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i",
5791 		    getpid() % 999999l, i);
5792 
5793 		r = sysevent_evc_subscribe(zevtchan->zn_eventchan,
5794 		    zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb,
5795 		    zevtchan, 0);
5796 
5797 		i++;
5798 
5799 	} while (r);
5800 
5801 	return (zevtchan);
5802 out1:
5803 	sysevent_evc_unbind(zevtchan->zn_eventchan);
5804 out2:
5805 	(void) pthread_mutex_destroy(&zevtchan->zn_mutex);
5806 	(void) pthread_cond_destroy(&zevtchan->zn_cond);
5807 	(void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex));
5808 out3:
5809 	free(zevtchan);
5810 
5811 	return (NULL);
5812 }
5813 
5814 void
5815 zonecfg_notify_unbind(void *handle)
5816 {
5817 
5818 	int ret;
5819 
5820 	sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan);
5821 	/*
5822 	 * Check that all evc threads have gone away. This should be
5823 	 * enforced by sysevent_evc_unbind.
5824 	 */
5825 	ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex);
5826 
5827 	if (ret)
5828 		abort();
5829 
5830 	(void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex);
5831 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex);
5832 	(void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond);
5833 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex);
5834 
5835 	free(handle);
5836 }
5837 
5838 static int
5839 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
5840 {
5841 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
5842 	int err;
5843 
5844 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL);
5845 	if ((err = newprop(newnode, DTD_ATTR_NAME,
5846 	    tabptr->zone_dataset_name)) != Z_OK)
5847 		return (err);
5848 	return (Z_OK);
5849 }
5850 
5851 int
5852 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5853 {
5854 	int err;
5855 
5856 	if (tabptr == NULL)
5857 		return (Z_INVAL);
5858 
5859 	if ((err = operation_prep(handle)) != Z_OK)
5860 		return (err);
5861 
5862 	if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK)
5863 		return (err);
5864 
5865 	return (Z_OK);
5866 }
5867 
5868 static int
5869 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
5870 {
5871 	xmlNodePtr cur = handle->zone_dh_cur;
5872 
5873 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
5874 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5875 			continue;
5876 
5877 		if (match_prop(cur, DTD_ATTR_NAME,
5878 		    tabptr->zone_dataset_name)) {
5879 			xmlUnlinkNode(cur);
5880 			xmlFreeNode(cur);
5881 			return (Z_OK);
5882 		}
5883 	}
5884 	return (Z_NO_RESOURCE_ID);
5885 }
5886 
5887 int
5888 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5889 {
5890 	int err;
5891 
5892 	if (tabptr == NULL)
5893 		return (Z_INVAL);
5894 
5895 	if ((err = operation_prep(handle)) != Z_OK)
5896 		return (err);
5897 
5898 	if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK)
5899 		return (err);
5900 
5901 	return (Z_OK);
5902 }
5903 
5904 int
5905 zonecfg_modify_ds(
5906 	zone_dochandle_t handle,
5907 	struct zone_dstab *oldtabptr,
5908 	struct zone_dstab *newtabptr)
5909 {
5910 	int err;
5911 
5912 	if (oldtabptr == NULL || newtabptr == NULL)
5913 		return (Z_INVAL);
5914 
5915 	if ((err = operation_prep(handle)) != Z_OK)
5916 		return (err);
5917 
5918 	if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK)
5919 		return (err);
5920 
5921 	if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK)
5922 		return (err);
5923 
5924 	return (Z_OK);
5925 }
5926 
5927 int
5928 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5929 {
5930 	xmlNodePtr cur, firstmatch;
5931 	int err;
5932 	char dataset[MAXNAMELEN];
5933 
5934 	if (tabptr == NULL)
5935 		return (Z_INVAL);
5936 
5937 	if ((err = operation_prep(handle)) != Z_OK)
5938 		return (err);
5939 
5940 	cur = handle->zone_dh_cur;
5941 	firstmatch = NULL;
5942 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
5943 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5944 			continue;
5945 		if (strlen(tabptr->zone_dataset_name) > 0) {
5946 			if ((fetchprop(cur, DTD_ATTR_NAME, dataset,
5947 			    sizeof (dataset)) == Z_OK) &&
5948 			    (strcmp(tabptr->zone_dataset_name,
5949 			    dataset) == 0)) {
5950 				if (firstmatch == NULL)
5951 					firstmatch = cur;
5952 				else
5953 					return (Z_INSUFFICIENT_SPEC);
5954 			}
5955 		}
5956 	}
5957 	if (firstmatch == NULL)
5958 		return (Z_NO_RESOURCE_ID);
5959 
5960 	cur = firstmatch;
5961 
5962 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
5963 	    sizeof (tabptr->zone_dataset_name))) != Z_OK)
5964 		return (err);
5965 
5966 	return (Z_OK);
5967 }
5968 
5969 int
5970 zonecfg_setdsent(zone_dochandle_t handle)
5971 {
5972 	return (zonecfg_setent(handle));
5973 }
5974 
5975 int
5976 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
5977 {
5978 	xmlNodePtr cur;
5979 	int err;
5980 
5981 	if (handle == NULL)
5982 		return (Z_INVAL);
5983 
5984 	if ((cur = handle->zone_dh_cur) == NULL)
5985 		return (Z_NO_ENTRY);
5986 
5987 	for (; cur != NULL; cur = cur->next)
5988 		if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5989 			break;
5990 	if (cur == NULL) {
5991 		handle->zone_dh_cur = handle->zone_dh_top;
5992 		return (Z_NO_ENTRY);
5993 	}
5994 
5995 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
5996 	    sizeof (tabptr->zone_dataset_name))) != Z_OK) {
5997 		handle->zone_dh_cur = handle->zone_dh_top;
5998 		return (err);
5999 	}
6000 
6001 	handle->zone_dh_cur = cur->next;
6002 	return (Z_OK);
6003 }
6004 
6005 int
6006 zonecfg_enddsent(zone_dochandle_t handle)
6007 {
6008 	return (zonecfg_endent(handle));
6009 }
6010 
6011 /*
6012  * Support for aliased rctls; that is, rctls that have simplified names in
6013  * zonecfg.  For example, max-lwps is an alias for a well defined zone.max-lwps
6014  * rctl.  If there are multiple existing values for one of these rctls or if
6015  * there is a single value that does not match the well defined template (i.e.
6016  * it has a different action) then we cannot treat the rctl as having an alias
6017  * so we return Z_ALIAS_DISALLOW.  That means that the rctl cannot be
6018  * managed in zonecfg via an alias and that the standard rctl syntax must be
6019  * used.
6020  *
6021  * The possible return values are:
6022  *	Z_NO_PROPERTY_ID - invalid alias name
6023  *	Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition
6024  *	Z_NO_ENTRY - no rctl is configured for this alias
6025  *	Z_OK - we got a valid rctl for the specified alias
6026  */
6027 int
6028 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval)
6029 {
6030 	boolean_t found = B_FALSE;
6031 	boolean_t found_val = B_FALSE;
6032 	xmlNodePtr cur, val;
6033 	char savedname[MAXNAMELEN];
6034 	struct zone_rctlvaltab rctl;
6035 	int i;
6036 	int err;
6037 
6038 	for (i = 0; aliases[i].shortname != NULL; i++)
6039 		if (strcmp(name, aliases[i].shortname) == 0)
6040 			break;
6041 
6042 	if (aliases[i].shortname == NULL)
6043 		return (Z_NO_PROPERTY_ID);
6044 
6045 	if ((err = operation_prep(handle)) != Z_OK)
6046 		return (err);
6047 
6048 	cur = handle->zone_dh_cur;
6049 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6050 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0)
6051 			continue;
6052 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
6053 		    sizeof (savedname)) == Z_OK) &&
6054 		    (strcmp(savedname, aliases[i].realname) == 0)) {
6055 
6056 			/*
6057 			 * If we already saw one of these, we can't have an
6058 			 * alias since we just found another.
6059 			 */
6060 			if (found)
6061 				return (Z_ALIAS_DISALLOW);
6062 			found = B_TRUE;
6063 
6064 			for (val = cur->xmlChildrenNode; val != NULL;
6065 			    val = val->next) {
6066 				/*
6067 				 * If we already have one value, we can't have
6068 				 * an alias since we just found another.
6069 				 */
6070 				if (found_val)
6071 					return (Z_ALIAS_DISALLOW);
6072 				found_val = B_TRUE;
6073 
6074 				if ((fetchprop(val, DTD_ATTR_PRIV,
6075 				    rctl.zone_rctlval_priv,
6076 				    sizeof (rctl.zone_rctlval_priv)) != Z_OK))
6077 					break;
6078 				if ((fetchprop(val, DTD_ATTR_LIMIT,
6079 				    rctl.zone_rctlval_limit,
6080 				    sizeof (rctl.zone_rctlval_limit)) != Z_OK))
6081 					break;
6082 				if ((fetchprop(val, DTD_ATTR_ACTION,
6083 				    rctl.zone_rctlval_action,
6084 				    sizeof (rctl.zone_rctlval_action)) != Z_OK))
6085 					break;
6086 			}
6087 
6088 			/* check priv and action match the expected vals */
6089 			if (strcmp(rctl.zone_rctlval_priv,
6090 			    aliases[i].priv) != 0 ||
6091 			    strcmp(rctl.zone_rctlval_action,
6092 			    aliases[i].action) != 0)
6093 				return (Z_ALIAS_DISALLOW);
6094 		}
6095 	}
6096 
6097 	if (found) {
6098 		*rval = strtoull(rctl.zone_rctlval_limit, NULL, 10);
6099 		return (Z_OK);
6100 	}
6101 
6102 	return (Z_NO_ENTRY);
6103 }
6104 
6105 int
6106 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name)
6107 {
6108 	int i;
6109 	uint64_t val;
6110 	struct zone_rctltab rctltab;
6111 
6112 	/*
6113 	 * First check that we have a valid aliased rctl to remove.
6114 	 * This will catch an rctl entry with non-standard values or
6115 	 * multiple rctl values for this name.  We need to ignore those
6116 	 * rctl entries.
6117 	 */
6118 	if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK)
6119 		return (Z_OK);
6120 
6121 	for (i = 0; aliases[i].shortname != NULL; i++)
6122 		if (strcmp(name, aliases[i].shortname) == 0)
6123 			break;
6124 
6125 	if (aliases[i].shortname == NULL)
6126 		return (Z_NO_RESOURCE_ID);
6127 
6128 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6129 	    sizeof (rctltab.zone_rctl_name));
6130 
6131 	return (zonecfg_delete_rctl(handle, &rctltab));
6132 }
6133 
6134 boolean_t
6135 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name)
6136 {
6137 	uint64_t tmp_val;
6138 
6139 	switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) {
6140 	case Z_OK:
6141 		/*FALLTHRU*/
6142 	case Z_NO_ENTRY:
6143 		return (B_TRUE);
6144 	default:
6145 		return (B_FALSE);
6146 	}
6147 }
6148 
6149 int
6150 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val)
6151 {
6152 	int i;
6153 	int err;
6154 	struct zone_rctltab rctltab;
6155 	struct zone_rctlvaltab *rctlvaltab;
6156 	char buf[128];
6157 
6158 	if (!zonecfg_aliased_rctl_ok(handle, name))
6159 		return (Z_ALIAS_DISALLOW);
6160 
6161 	for (i = 0; aliases[i].shortname != NULL; i++)
6162 		if (strcmp(name, aliases[i].shortname) == 0)
6163 			break;
6164 
6165 	if (aliases[i].shortname == NULL)
6166 		return (Z_NO_RESOURCE_ID);
6167 
6168 	/* remove any pre-existing definition for this rctl */
6169 	(void) zonecfg_rm_aliased_rctl(handle, name);
6170 
6171 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6172 	    sizeof (rctltab.zone_rctl_name));
6173 
6174 	rctltab.zone_rctl_valptr = NULL;
6175 
6176 	if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL)
6177 		return (Z_NOMEM);
6178 
6179 	(void) snprintf(buf, sizeof (buf), "%llu", (long long)val);
6180 
6181 	(void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv,
6182 	    sizeof (rctlvaltab->zone_rctlval_priv));
6183 	(void) strlcpy(rctlvaltab->zone_rctlval_limit, buf,
6184 	    sizeof (rctlvaltab->zone_rctlval_limit));
6185 	(void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action,
6186 	    sizeof (rctlvaltab->zone_rctlval_action));
6187 
6188 	rctlvaltab->zone_rctlval_next = NULL;
6189 
6190 	if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK)
6191 		return (err);
6192 
6193 	return (zonecfg_add_rctl(handle, &rctltab));
6194 }
6195 
6196 static int
6197 delete_tmp_pool(zone_dochandle_t handle)
6198 {
6199 	int err;
6200 	xmlNodePtr cur = handle->zone_dh_cur;
6201 
6202 	if ((err = operation_prep(handle)) != Z_OK)
6203 		return (err);
6204 
6205 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6206 		if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6207 			xmlUnlinkNode(cur);
6208 			xmlFreeNode(cur);
6209 			return (Z_OK);
6210 		}
6211 	}
6212 
6213 	return (Z_NO_RESOURCE_ID);
6214 }
6215 
6216 static int
6217 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance)
6218 {
6219 	int err;
6220 	xmlNodePtr cur = handle->zone_dh_cur;
6221 	xmlNodePtr newnode;
6222 
6223 	err = delete_tmp_pool(handle);
6224 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6225 		return (err);
6226 
6227 	if (*pool_importance != '\0') {
6228 		if ((err = operation_prep(handle)) != Z_OK)
6229 			return (err);
6230 
6231 		newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL);
6232 		if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE,
6233 		    pool_importance)) != Z_OK)
6234 			return (err);
6235 	}
6236 
6237 	return (Z_OK);
6238 }
6239 
6240 static int
6241 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr)
6242 {
6243 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6244 	int err;
6245 
6246 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL);
6247 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN,
6248 	    tabptr->zone_ncpu_min)) != Z_OK)
6249 		return (err);
6250 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX,
6251 	    tabptr->zone_ncpu_max)) != Z_OK)
6252 		return (err);
6253 
6254 	if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK)
6255 		return (err);
6256 
6257 	return (Z_OK);
6258 }
6259 
6260 int
6261 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6262 {
6263 	int err;
6264 
6265 	if (tabptr == NULL)
6266 		return (Z_INVAL);
6267 
6268 	if ((err = operation_prep(handle)) != Z_OK)
6269 		return (err);
6270 
6271 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
6272 		return (err);
6273 
6274 	return (Z_OK);
6275 }
6276 
6277 int
6278 zonecfg_delete_pset(zone_dochandle_t handle)
6279 {
6280 	int err;
6281 	int res = Z_NO_RESOURCE_ID;
6282 	xmlNodePtr cur = handle->zone_dh_cur;
6283 
6284 	if ((err = operation_prep(handle)) != Z_OK)
6285 		return (err);
6286 
6287 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6288 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
6289 			xmlUnlinkNode(cur);
6290 			xmlFreeNode(cur);
6291 			res = Z_OK;
6292 			break;
6293 		}
6294 	}
6295 
6296 	/*
6297 	 * Once we have msets, we should check that a mset
6298 	 * do not exist before we delete the tmp_pool data.
6299 	 */
6300 	err = delete_tmp_pool(handle);
6301 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6302 		return (err);
6303 
6304 	return (res);
6305 }
6306 
6307 int
6308 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6309 {
6310 	int err;
6311 
6312 	if (tabptr == NULL)
6313 		return (Z_INVAL);
6314 
6315 	if ((err = zonecfg_delete_pset(handle)) != Z_OK)
6316 		return (err);
6317 
6318 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
6319 		return (err);
6320 
6321 	return (Z_OK);
6322 }
6323 
6324 int
6325 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6326 {
6327 	xmlNodePtr cur;
6328 	int err;
6329 	int res = Z_NO_ENTRY;
6330 
6331 	if (tabptr == NULL)
6332 		return (Z_INVAL);
6333 
6334 	if ((err = operation_prep(handle)) != Z_OK)
6335 		return (err);
6336 
6337 	/* this is an optional component */
6338 	tabptr->zone_importance[0] = '\0';
6339 
6340 	cur = handle->zone_dh_cur;
6341 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6342 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
6343 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN,
6344 			    tabptr->zone_ncpu_min,
6345 			    sizeof (tabptr->zone_ncpu_min))) != Z_OK) {
6346 				handle->zone_dh_cur = handle->zone_dh_top;
6347 				return (err);
6348 			}
6349 
6350 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX,
6351 			    tabptr->zone_ncpu_max,
6352 			    sizeof (tabptr->zone_ncpu_max))) != Z_OK) {
6353 				handle->zone_dh_cur = handle->zone_dh_top;
6354 				return (err);
6355 			}
6356 
6357 			res = Z_OK;
6358 
6359 		} else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6360 			if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE,
6361 			    tabptr->zone_importance,
6362 			    sizeof (tabptr->zone_importance))) != Z_OK) {
6363 				handle->zone_dh_cur = handle->zone_dh_top;
6364 				return (err);
6365 			}
6366 		}
6367 	}
6368 
6369 	return (res);
6370 }
6371 
6372 int
6373 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
6374 {
6375 	int err;
6376 
6377 	if ((err = zonecfg_setent(handle)) != Z_OK)
6378 		return (err);
6379 
6380 	err = zonecfg_lookup_pset(handle, tabptr);
6381 
6382 	(void) zonecfg_endent(handle);
6383 
6384 	return (err);
6385 }
6386 
6387 static int
6388 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6389 {
6390 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6391 	int err;
6392 
6393 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
6394 	if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
6395 	    != Z_OK)
6396 		return (err);
6397 
6398 	return (Z_OK);
6399 }
6400 
6401 int
6402 zonecfg_delete_mcap(zone_dochandle_t handle)
6403 {
6404 	int err;
6405 	xmlNodePtr cur = handle->zone_dh_cur;
6406 
6407 	if ((err = operation_prep(handle)) != Z_OK)
6408 		return (err);
6409 
6410 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6411 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6412 			continue;
6413 
6414 		xmlUnlinkNode(cur);
6415 		xmlFreeNode(cur);
6416 		return (Z_OK);
6417 	}
6418 	return (Z_NO_RESOURCE_ID);
6419 }
6420 
6421 int
6422 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6423 {
6424 	int err;
6425 
6426 	if (tabptr == NULL)
6427 		return (Z_INVAL);
6428 
6429 	err = zonecfg_delete_mcap(handle);
6430 	/* it is ok if there is no mcap entry */
6431 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6432 		return (err);
6433 
6434 	if ((err = add_mcap(handle, tabptr)) != Z_OK)
6435 		return (err);
6436 
6437 	return (Z_OK);
6438 }
6439 
6440 int
6441 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6442 {
6443 	xmlNodePtr cur;
6444 	int err;
6445 
6446 	if (tabptr == NULL)
6447 		return (Z_INVAL);
6448 
6449 	if ((err = operation_prep(handle)) != Z_OK)
6450 		return (err);
6451 
6452 	cur = handle->zone_dh_cur;
6453 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6454 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6455 			continue;
6456 		if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
6457 		    tabptr->zone_physmem_cap,
6458 		    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6459 			handle->zone_dh_cur = handle->zone_dh_top;
6460 			return (err);
6461 		}
6462 
6463 		return (Z_OK);
6464 	}
6465 
6466 	return (Z_NO_ENTRY);
6467 }
6468 
6469 static int
6470 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6471 {
6472 	xmlNodePtr cur;
6473 	int err;
6474 
6475 	if (handle == NULL)
6476 		return (Z_INVAL);
6477 
6478 	if ((cur = handle->zone_dh_cur) == NULL)
6479 		return (Z_NO_ENTRY);
6480 
6481 	for (; cur != NULL; cur = cur->next)
6482 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
6483 			break;
6484 	if (cur == NULL) {
6485 		handle->zone_dh_cur = handle->zone_dh_top;
6486 		return (Z_NO_ENTRY);
6487 	}
6488 
6489 	if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
6490 	    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6491 		handle->zone_dh_cur = handle->zone_dh_top;
6492 		return (err);
6493 	}
6494 
6495 	handle->zone_dh_cur = cur->next;
6496 	return (Z_OK);
6497 }
6498 
6499 int
6500 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6501 {
6502 	int err;
6503 
6504 	if ((err = zonecfg_setent(handle)) != Z_OK)
6505 		return (err);
6506 
6507 	err = getmcapent_core(handle, tabptr);
6508 
6509 	(void) zonecfg_endent(handle);
6510 
6511 	return (err);
6512 }
6513 
6514 /*
6515  * Get the full tree of pkg/patch metadata in a set of nested AVL trees.
6516  * pkgs_avl is an AVL tree of pkgs.  Each pkg element contains a
6517  * zpe_patches_avl member which holds an AVL tree of patches for that pkg.
6518  * The patch elements have the same zpe_patches_avl member, each of which can
6519  * hold an AVL tree of patches that are obsoleted by the patch.
6520  *
6521  * The zone xml data contains DTD_ELEM_PACKAGE elements, followed by
6522  * DTD_ELEM_PATCH elements.  The DTD_ELEM_PATCH patch element applies to the
6523  * DTD_ELEM_PACKAGE that precedes it.  The DTD_ELEM_PATCH element may have
6524  * child DTD_ELEM_OBSOLETES nodes associated with it.  The DTD_ELEM_PACKAGE
6525  * really should have had the DTD_ELEM_PATCH elements as children but it
6526  * was not defined that way initially so we are stuck with the DTD definition
6527  * now.  However, we can safely assume the ordering for compatibility.
6528  */
6529 int
6530 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
6531     uu_avl_t *pkgs_avl)
6532 {
6533 	xmlNodePtr cur;
6534 	int res;
6535 	zone_pkg_entry_t *pkg;
6536 	char name[MAXNAMELEN];
6537 	char version[ZONE_PKG_VERSMAX];
6538 
6539 	if (handle == NULL)
6540 		return (Z_INVAL);
6541 
6542 	if ((res = zonecfg_setent(handle)) != Z_OK)
6543 		return (res);
6544 
6545 	if ((cur = handle->zone_dh_cur) == NULL) {
6546 		res = Z_NO_ENTRY;
6547 		goto done;
6548 	}
6549 
6550 	for (; cur != NULL; cur = cur->next) {
6551 		if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) {
6552 			uu_avl_index_t where;
6553 
6554 			if ((res = fetchprop(cur, DTD_ATTR_NAME, name,
6555 			    sizeof (name))) != Z_OK)
6556 				goto done;
6557 
6558 			if ((res = fetchprop(cur, DTD_ATTR_VERSION, version,
6559 			    sizeof (version))) != Z_OK)
6560 				goto done;
6561 
6562 			if ((pkg = (zone_pkg_entry_t *)
6563 			    malloc(sizeof (zone_pkg_entry_t))) == NULL) {
6564 				res = Z_NOMEM;
6565 				goto done;
6566 			}
6567 
6568 			if ((pkg->zpe_name = strdup(name)) == NULL) {
6569 				free(pkg);
6570 				res = Z_NOMEM;
6571 				goto done;
6572 			}
6573 
6574 			if ((pkg->zpe_vers = strdup(version)) == NULL) {
6575 				free(pkg->zpe_name);
6576 				free(pkg);
6577 				res = Z_NOMEM;
6578 				goto done;
6579 			}
6580 
6581 			pkg->zpe_patches_avl = NULL;
6582 
6583 			uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool);
6584 			if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) {
6585 				free(pkg->zpe_name);
6586 				free(pkg->zpe_vers);
6587 				free(pkg);
6588 			} else {
6589 				uu_avl_insert(pkgs_avl, pkg, where);
6590 			}
6591 
6592 		} else if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) {
6593 			zone_pkg_entry_t *patch;
6594 			uu_avl_index_t where;
6595 			char *p;
6596 			char *dashp = NULL;
6597 			xmlNodePtr child;
6598 
6599 			if ((res = fetchprop(cur, DTD_ATTR_ID, name,
6600 			    sizeof (name))) != Z_OK)
6601 				goto done;
6602 
6603 			if ((patch = (zone_pkg_entry_t *)
6604 			    malloc(sizeof (zone_pkg_entry_t))) == NULL) {
6605 				res = Z_NOMEM;
6606 				goto done;
6607 			}
6608 
6609 			if ((p = strchr(name, '-')) != NULL) {
6610 				dashp = p;
6611 				*p++ = '\0';
6612 			} else {
6613 				p = "";
6614 			}
6615 
6616 			if ((patch->zpe_name = strdup(name)) == NULL) {
6617 				free(patch);
6618 				res = Z_NOMEM;
6619 				goto done;
6620 			}
6621 
6622 			if ((patch->zpe_vers = strdup(p)) == NULL) {
6623 				free(patch->zpe_name);
6624 				free(patch);
6625 				res = Z_NOMEM;
6626 				goto done;
6627 			}
6628 
6629 			if (dashp != NULL)
6630 				*dashp = '-';
6631 
6632 			patch->zpe_patches_avl = NULL;
6633 
6634 			if (pkg->zpe_patches_avl == NULL) {
6635 				pkg->zpe_patches_avl = uu_avl_create(pkg_pool,
6636 				    NULL, UU_DEFAULT);
6637 				if (pkg->zpe_patches_avl == NULL) {
6638 					free(patch->zpe_name);
6639 					free(patch->zpe_vers);
6640 					free(patch);
6641 					res = Z_NOMEM;
6642 					goto done;
6643 				}
6644 			}
6645 
6646 			uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool);
6647 			if (uu_avl_find(pkg->zpe_patches_avl, patch, NULL,
6648 			    &where) != NULL) {
6649 				free(patch->zpe_name);
6650 				free(patch->zpe_vers);
6651 				free(patch);
6652 			} else {
6653 				uu_avl_insert(pkg->zpe_patches_avl, patch,
6654 				    where);
6655 			}
6656 
6657 			/* Add any patches this patch obsoletes. */
6658 			for (child = cur->xmlChildrenNode; child != NULL;
6659 			    child = child->next) {
6660 				zone_pkg_entry_t *obs;
6661 
6662 				if (xmlStrcmp(child->name, DTD_ELEM_OBSOLETES)
6663 				    != 0)
6664 					continue;
6665 
6666 				if ((res = fetchprop(child, DTD_ATTR_ID,
6667 				    name, sizeof (name))) != Z_OK)
6668 					goto done;
6669 
6670 				if ((obs = (zone_pkg_entry_t *)malloc(
6671 				    sizeof (zone_pkg_entry_t))) == NULL) {
6672 					res = Z_NOMEM;
6673 					goto done;
6674 				}
6675 
6676 				if ((obs->zpe_name = strdup(name)) == NULL) {
6677 					free(obs);
6678 					res = Z_NOMEM;
6679 					goto done;
6680 				}
6681 				/*
6682 				 * The version doesn't matter for obsoleted
6683 				 * patches.
6684 				 */
6685 				obs->zpe_vers = NULL;
6686 				obs->zpe_patches_avl = NULL;
6687 
6688 				/*
6689 				 * If this is the first obsolete patch, add an
6690 				 * AVL tree to the parent patch element.
6691 				 */
6692 				if (patch->zpe_patches_avl == NULL) {
6693 					patch->zpe_patches_avl =
6694 					    uu_avl_create(pkg_pool, NULL,
6695 					    UU_DEFAULT);
6696 					if (patch->zpe_patches_avl == NULL) {
6697 						free(obs->zpe_name);
6698 						free(obs);
6699 						res = Z_NOMEM;
6700 						goto done;
6701 					}
6702 				}
6703 
6704 				/* Insert obsolete patch into the AVL tree. */
6705 				uu_avl_node_init(obs, &obs->zpe_entry,
6706 				    pkg_pool);
6707 				if (uu_avl_find(patch->zpe_patches_avl, obs,
6708 				    NULL, &where) != NULL) {
6709 					free(obs->zpe_name);
6710 					free(obs);
6711 				} else {
6712 					uu_avl_insert(patch->zpe_patches_avl,
6713 					    obs, where);
6714 				}
6715 			}
6716 		}
6717 	}
6718 
6719 done:
6720 	(void) zonecfg_endent(handle);
6721 	return (res);
6722 }
6723 
6724 int
6725 zonecfg_setdevperment(zone_dochandle_t handle)
6726 {
6727 	return (zonecfg_setent(handle));
6728 }
6729 
6730 int
6731 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr)
6732 {
6733 	xmlNodePtr cur;
6734 	int err;
6735 	char buf[128];
6736 
6737 	tabptr->zone_devperm_acl = NULL;
6738 
6739 	if (handle == NULL)
6740 		return (Z_INVAL);
6741 
6742 	if ((cur = handle->zone_dh_cur) == NULL)
6743 		return (Z_NO_ENTRY);
6744 
6745 	for (; cur != NULL; cur = cur->next)
6746 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM))
6747 			break;
6748 	if (cur == NULL) {
6749 		handle->zone_dh_cur = handle->zone_dh_top;
6750 		return (Z_NO_ENTRY);
6751 	}
6752 
6753 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name,
6754 	    sizeof (tabptr->zone_devperm_name))) != Z_OK) {
6755 		handle->zone_dh_cur = handle->zone_dh_top;
6756 		return (err);
6757 	}
6758 
6759 	if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) {
6760 		handle->zone_dh_cur = handle->zone_dh_top;
6761 		return (err);
6762 	}
6763 	tabptr->zone_devperm_uid = (uid_t)atol(buf);
6764 
6765 	if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) {
6766 		handle->zone_dh_cur = handle->zone_dh_top;
6767 		return (err);
6768 	}
6769 	tabptr->zone_devperm_gid = (gid_t)atol(buf);
6770 
6771 	if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) {
6772 		handle->zone_dh_cur = handle->zone_dh_top;
6773 		return (err);
6774 	}
6775 	tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8);
6776 
6777 	if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL,
6778 	    &(tabptr->zone_devperm_acl))) != Z_OK) {
6779 		handle->zone_dh_cur = handle->zone_dh_top;
6780 		return (err);
6781 	}
6782 
6783 	handle->zone_dh_cur = cur->next;
6784 	return (Z_OK);
6785 }
6786 
6787 int
6788 zonecfg_enddevperment(zone_dochandle_t handle)
6789 {
6790 	return (zonecfg_endent(handle));
6791 }
6792 
6793 /*
6794  * Maintain a space separated list of unique pkg names.  PATH_MAX is used in
6795  * the pkg code as the maximum size for a pkg name.
6796  */
6797 static int
6798 add_pkg_to_str(char **str, char *pkg)
6799 {
6800 	int len, newlen;
6801 	char tstr[PATH_MAX + 3];
6802 	char *tmp;
6803 
6804 	len = strlen(pkg);
6805 	if (*str == NULL) {
6806 		/* space for str + 2 spaces + NULL */
6807 		if ((*str = (char *)malloc(len + 3)) == NULL)
6808 			return (Z_NOMEM);
6809 		(void) snprintf(*str, len + 3, " %s ", pkg);
6810 		return (Z_OK);
6811 	}
6812 
6813 	(void) snprintf(tstr, sizeof (tstr), " %s ", pkg);
6814 	if (strstr(*str, tstr) != NULL)
6815 		return (Z_OK);
6816 
6817 	/* space for str + 1 space + NULL */
6818 	newlen = strlen(*str) + len + 2;
6819 	if ((tmp = (char *)realloc(*str, newlen)) == NULL)
6820 		return (Z_NOMEM);
6821 	*str = tmp;
6822 	(void) strlcat(*str, pkg, newlen);
6823 	(void) strlcat(*str, " ", newlen);
6824 	return (Z_OK);
6825 }
6826 
6827 /*
6828  * Process a list of pkgs from an entry in the contents file, adding each pkg
6829  * name to the list of pkgs.
6830  *
6831  * It is possible for the pkg name to be preceeded by a special character
6832  * which indicates some bookkeeping information for pkging.  Check if the
6833  * first char is not an Alpha char.  If so, skip over it.
6834  */
6835 static int
6836 add_pkg_list(char *lastp, char ***plist, int *pcnt, char **pkg_warn)
6837 {
6838 	char	*p;
6839 	int	pkg_cnt = *pcnt;
6840 	char	**pkgs = *plist;
6841 	int	res = Z_OK;
6842 
6843 	while ((p = strtok_r(NULL, " ", &lastp)) != NULL) {
6844 		char	**tmpp;
6845 		int	i;
6846 
6847 		/* skip over any special pkg bookkeeping char */
6848 		if (!isalpha(*p)) {
6849 			p++;
6850 			if ((res = add_pkg_to_str(pkg_warn, p)) != Z_OK)
6851 				break;
6852 		}
6853 
6854 		/* Check if the pkg is already in the list */
6855 		for (i = 0; i < pkg_cnt; i++) {
6856 			if (strcmp(p, pkgs[i]) == 0)
6857 				break;
6858 		}
6859 
6860 		if (i < pkg_cnt)
6861 			continue;
6862 
6863 		/* The pkg is not in the list; add it. */
6864 		if ((tmpp = (char **)realloc(pkgs,
6865 		    sizeof (char *) * (pkg_cnt + 1))) == NULL) {
6866 			res = Z_NOMEM;
6867 			break;
6868 		}
6869 		pkgs = tmpp;
6870 
6871 		if ((pkgs[pkg_cnt] = strdup(p)) == NULL) {
6872 			res = Z_NOMEM;
6873 			break;
6874 		}
6875 		pkg_cnt++;
6876 	}
6877 
6878 	*plist = pkgs;
6879 	*pcnt = pkg_cnt;
6880 
6881 	return (res);
6882 }
6883 
6884 /*
6885  * Process an entry from the contents file (type "directory").  If the
6886  * directory path is in the list of ipds and is not under a lofs mount within
6887  * the ipd then add the associated list of pkgs to the pkg list.  The input
6888  * parameter "entry" will be broken up by the parser within this function so
6889  * its value will be modified when this function exits.
6890  *
6891  * The entries we are looking for will look something like:
6892  *	/usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf ....
6893  */
6894 static int
6895 get_path_pkgs(char *entry, char **ipds, char **fss, char ***pkgs, int *pkg_cnt,
6896     char **pkg_warn)
6897 {
6898 	char	*f1;
6899 	char	*f2;
6900 	char	*lastp;
6901 	int	i;
6902 	char	*nlp;
6903 
6904 	if ((f1 = strtok_r(entry, " ", &lastp)) == NULL ||
6905 	    (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0)
6906 		return (Z_OK);
6907 
6908 	/* Check if this directory entry is in the list of ipds. */
6909 	for (i = 0; ipds[i] != NULL; i++) {
6910 		char wildcard[MAXPATHLEN];
6911 
6912 		/*
6913 		 * We want to match on the path and any other directory
6914 		 * entries under this path.  When we use FNM_PATHNAME then
6915 		 * that means '/' will not be matched by a wildcard (*) so
6916 		 * we omit FNM_PATHNAME on the call with the wildcard matching.
6917 		 */
6918 		(void) snprintf(wildcard, sizeof (wildcard), "%s/*", ipds[i]);
6919 		if (fnmatch(ipds[i], f1, FNM_PATHNAME) == 0 ||
6920 		    fnmatch(wildcard, f1, 0) == 0) {
6921 			/* It looks like we do want the pkgs for this path. */
6922 			break;
6923 		}
6924 	}
6925 
6926 	/* This entry did not match any of the ipds. */
6927 	if (ipds[i] == NULL)
6928 		return (Z_OK);
6929 
6930 	/*
6931 	 * Check if there is a fs mounted under the ipd.  If so, ignore this
6932 	 * entry.
6933 	 */
6934 	for (i = 0; fss[i] != NULL; i++) {
6935 		char wildcard[MAXPATHLEN];
6936 
6937 		(void) snprintf(wildcard, sizeof (wildcard), "%s/*", fss[i]);
6938 		if (fnmatch(fss[i], f1, FNM_PATHNAME) == 0 ||
6939 		    fnmatch(wildcard, f1, 0) == 0) {
6940 			/* We should ignore this path. */
6941 			break;
6942 		}
6943 	}
6944 
6945 	/* If not null, then we matched an fs mount point so ignore entry. */
6946 	if (fss[i] != NULL)
6947 		return (Z_OK);
6948 
6949 	/*
6950 	 * We do want the pkgs for this entry.  First, skip over the next 4
6951 	 * fields in the entry so that we call add_pkg_list starting with the
6952 	 * pkg names.
6953 	 */
6954 	for (i = 0; i < 4 && strtok_r(NULL, " ", &lastp) != NULL; i++)
6955 		;
6956 	/* If there are < 4 fields this entry is corrupt, just skip it. */
6957 	if (i < 4)
6958 		return (Z_OK);
6959 
6960 	/* strip newline from the line */
6961 	nlp = (lastp + strlen(lastp) - 1);
6962 	if (*nlp == '\n')
6963 		*nlp = '\0';
6964 
6965 	return (add_pkg_list(lastp, pkgs, pkg_cnt, pkg_warn));
6966 }
6967 
6968 /*
6969  * Read an entry from a pkginfo or contents file.  Some of these lines can
6970  * either be arbitrarily long or be continued by a backslash at the end of
6971  * the line.  This function coalesces lines that are longer than the read
6972  * buffer, and lines that are continued, into one buffer which is returned.
6973  * The caller must free this memory.  NULL is returned when we hit EOF or
6974  * if we run out of memory (errno is set to ENOMEM).
6975  */
6976 static char *
6977 read_pkg_data(FILE *fp)
6978 {
6979 	char *start;
6980 	char *inp;
6981 	char *p;
6982 	int char_cnt = 0;
6983 
6984 	errno = 0;
6985 	if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) {
6986 		errno = ENOMEM;
6987 		return (NULL);
6988 	}
6989 
6990 	inp = start;
6991 	while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) {
6992 		int len;
6993 
6994 		len = strlen(inp);
6995 		if (inp[len - 1] == '\n' &&
6996 		    (len == 1 || inp[len - 2] != '\\')) {
6997 			char_cnt = len;
6998 			break;
6999 		}
7000 
7001 		if (inp[len - 2] == '\\')
7002 			char_cnt += len - 2;
7003 		else
7004 			char_cnt += PKGINFO_RD_LEN - 1;
7005 
7006 		if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) {
7007 			errno = ENOMEM;
7008 			break;
7009 		}
7010 
7011 		start = p;
7012 		inp = start + char_cnt;
7013 	}
7014 
7015 	if (errno == ENOMEM || (p == NULL && char_cnt == 0)) {
7016 		free(start);
7017 		start = NULL;
7018 	}
7019 
7020 	return (start);
7021 }
7022 
7023 static void
7024 free_ipd_pkgs(char **pkgs, int cnt)
7025 {
7026 	int i;
7027 
7028 	for (i = 0; i < cnt; i++)
7029 		free(pkgs[i]);
7030 	free(pkgs);
7031 }
7032 
7033 /*
7034  * Get a list of the inherited pkg dirs or fs entries configured for the
7035  * zone.  The type parameter will be either ZONE_IPD or ZONE_FS.
7036  */
7037 static int
7038 get_ipd_fs_list(zone_dochandle_t handle, enum zn_ipd_fs type, char ***list)
7039 {
7040 	int	res;
7041 	struct zone_fstab fstab;
7042 	int	cnt = 0;
7043 	char	**entries = NULL;
7044 	int	i;
7045 	int	(*fp)(zone_dochandle_t, struct zone_fstab *);
7046 
7047 	if (type == ZONE_IPD) {
7048 		fp = zonecfg_getipdent;
7049 		res = zonecfg_setipdent(handle);
7050 	} else {
7051 		fp = zonecfg_getfsent;
7052 		res = zonecfg_setfsent(handle);
7053 	}
7054 
7055 	if (res != Z_OK)
7056 		return (res);
7057 
7058 	while (fp(handle, &fstab) == Z_OK) {
7059 		char	**p;
7060 
7061 		if ((p = (char **)realloc(entries,
7062 		    sizeof (char *) * (cnt + 1))) == NULL) {
7063 			res = Z_NOMEM;
7064 			break;
7065 		}
7066 		entries = p;
7067 
7068 		if ((entries[cnt] = strdup(fstab.zone_fs_dir)) == NULL) {
7069 			res = Z_NOMEM;
7070 			break;
7071 		}
7072 
7073 		cnt++;
7074 	}
7075 
7076 	if (type == ZONE_IPD)
7077 		(void) zonecfg_endipdent(handle);
7078 	else
7079 		(void) zonecfg_endfsent(handle);
7080 
7081 	/* Add a NULL terminating element. */
7082 	if (res == Z_OK) {
7083 		char	**p;
7084 
7085 		if ((p = (char **)realloc(entries,
7086 		    sizeof (char *) * (cnt + 1))) == NULL) {
7087 			res = Z_NOMEM;
7088 		} else {
7089 			entries = p;
7090 			entries[cnt] = NULL;
7091 		}
7092 	}
7093 
7094 	if (res != Z_OK) {
7095 		if (entries != NULL) {
7096 			for (i = 0; i < cnt; i++)
7097 				free(entries[i]);
7098 			free(entries);
7099 		}
7100 		return (res);
7101 	}
7102 
7103 	*list = entries;
7104 	return (Z_OK);
7105 }
7106 
7107 /*
7108  * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the
7109  * list of pkgs that deliver into those dirs.
7110  */
7111 static int
7112 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt)
7113 {
7114 	int	res;
7115 	char	**ipds;
7116 	char	**fss;
7117 	int	pkg_cnt = 0;
7118 	char	**pkgs = NULL;
7119 	int	i;
7120 
7121 	if ((res = get_ipd_fs_list(handle, ZONE_IPD, &ipds)) != Z_OK)
7122 		return (res);
7123 
7124 	if ((res = get_ipd_fs_list(handle, ZONE_FS, &fss)) != Z_OK) {
7125 		for (i = 0; ipds[i] != NULL; i++)
7126 			free(ipds[i]);
7127 		free(ipds);
7128 		return (res);
7129 	}
7130 
7131 	/* We only have to process the contents file if we have ipds. */
7132 	if (ipds != NULL) {
7133 		FILE	*fp;
7134 
7135 		if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) {
7136 			char	*buf;
7137 			char	*pkg_warn = NULL;
7138 
7139 			while ((buf = read_pkg_data(fp)) != NULL) {
7140 				res = get_path_pkgs(buf, ipds, fss, &pkgs,
7141 				    &pkg_cnt, &pkg_warn);
7142 				free(buf);
7143 				if (res != Z_OK)
7144 					break;
7145 			}
7146 
7147 			(void) fclose(fp);
7148 
7149 			if (pkg_warn != NULL) {
7150 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
7151 				    "WARNING: package operation in progress "
7152 				    "on the following packages:\n   %s\n"),
7153 				    pkg_warn);
7154 				free(pkg_warn);
7155 			}
7156 		}
7157 	}
7158 
7159 	for (i = 0; ipds[i] != NULL; i++)
7160 		free(ipds[i]);
7161 	free(ipds);
7162 
7163 	for (i = 0; fss[i] != NULL; i++)
7164 		free(fss[i]);
7165 	free(fss);
7166 
7167 	if (res != Z_OK) {
7168 		free_ipd_pkgs(pkgs, pkg_cnt);
7169 	} else {
7170 		*pkg_list = pkgs;
7171 		*cnt = pkg_cnt;
7172 	}
7173 
7174 	return (res);
7175 }
7176 
7177 /*
7178  * Return true if pkg_name is in the list of pkgs that deliver into an
7179  * inherited pkg directory for the zone.
7180  */
7181 static boolean_t
7182 dir_pkg(char *pkg_name, char **pkg_list, int cnt)
7183 {
7184 	int i;
7185 
7186 	for (i = 0; i < cnt; i++) {
7187 		if (strcmp(pkg_name, pkg_list[i]) == 0)
7188 			return (B_TRUE);
7189 	}
7190 
7191 	return (B_FALSE);
7192 }
7193 
7194 /*
7195  * Keep track of obsoleted patches for this specific patch.  We don't need to
7196  * keep track of the patch version since once a patch is obsoleted, all prior
7197  * versions are also obsolete and there won't be any new versions.
7198  */
7199 static int
7200 add_obs_patch(patch_node_t *patch, char *num, uu_list_pool_t *patches_pool)
7201 {
7202 	obs_patch_node_t *obs;
7203 
7204 	if (patch->obs_patches == NULL) {
7205 		if ((patch->obs_patches = uu_list_create(patches_pool, NULL,
7206 		    0)) == NULL)
7207 			return (Z_NOMEM);
7208 	}
7209 
7210 	if ((obs = (obs_patch_node_t *)malloc(sizeof (obs_patch_node_t)))
7211 	    == NULL)
7212 		return (Z_NOMEM);
7213 
7214 	if ((obs->patch_num = strdup(num)) == NULL) {
7215 		free(obs);
7216 		return (Z_NOMEM);
7217 	}
7218 
7219 	uu_list_node_init(obs, &obs->link, patches_pool);
7220 	(void) uu_list_insert_before(patch->obs_patches, NULL, obs);
7221 
7222 	return (Z_OK);
7223 }
7224 
7225 /*
7226  * Keep track of obsoleted patches.  We don't need to keep track of the patch
7227  * version since once a patch is obsoleted, all prior versions are also
7228  * obsolete and there won't be any new versions.
7229  */
7230 static int
7231 save_obs_patch(char *num, uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches)
7232 {
7233 	patch_node_t	*patch;
7234 	uu_avl_index_t where;
7235 
7236 	if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL)
7237 		return (Z_NOMEM);
7238 
7239 	if ((patch->patch_num = strdup(num)) == NULL) {
7240 		free(patch);
7241 		return (Z_NOMEM);
7242 	}
7243 
7244 	patch->patch_vers = NULL;
7245 	patch->obs_patches = NULL;
7246 
7247 	uu_avl_node_init(patch, &patch->patch_node, patches_pool);
7248 
7249 	if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL) {
7250 		free(patch->patch_num);
7251 		free(patch);
7252 		return (Z_OK);
7253 	}
7254 
7255 	uu_avl_insert(obs_patches, patch, where);
7256 	return (Z_OK);
7257 }
7258 
7259 /*
7260  * Keep a list of patches for a pkg.  If we see a newer version of a patch,
7261  * we only keep track of the newer version.
7262  */
7263 static void
7264 save_patch(patch_node_t *patch, uu_avl_t *patches_avl)
7265 {
7266 	patch_node_t *existing;
7267 	uu_avl_index_t where;
7268 
7269 	/* Check if this is a newer version of a patch we already have. */
7270 	if ((existing = (patch_node_t *)uu_avl_find(patches_avl, patch, NULL,
7271 	    &where)) != NULL) {
7272 		char *endptr;
7273 		ulong_t pvers, evers;
7274 
7275 		pvers = strtoul(patch->patch_vers, &endptr, 10);
7276 		evers = strtoul(existing->patch_vers, &endptr, 10);
7277 
7278 		if (pvers > evers) {
7279 			free(existing->patch_vers);
7280 			existing->patch_vers = patch->patch_vers;
7281 			free(patch->patch_num);
7282 			free(patch);
7283 			return;
7284 		}
7285 	}
7286 
7287 	uu_avl_insert(patches_avl, patch, where);
7288 }
7289 
7290 /*
7291  * Check if a patch is on the list of obsoleted patches.  We don't need to
7292  * check the patch version since once a patch is obsoleted, all prior versions
7293  * are also obsolete and there won't be any new versions.
7294  */
7295 static boolean_t
7296 obsolete_patch(patch_node_t *patch, uu_avl_t *obs_patches)
7297 {
7298 	uu_avl_index_t	where;
7299 
7300 	if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL)
7301 		return (B_TRUE);
7302 
7303 	return (B_FALSE);
7304 }
7305 
7306 /* ARGSUSED */
7307 static int
7308 patch_node_compare(const void *l_arg, const void *r_arg, void *private)
7309 {
7310 	patch_node_t *l = (patch_node_t *)l_arg;
7311 	patch_node_t *r = (patch_node_t *)r_arg;
7312 	char *endptr;
7313 	ulong_t lnum, rnum;
7314 
7315 	lnum = strtoul(l->patch_num, &endptr, 10);
7316 	rnum = strtoul(r->patch_num, &endptr, 10);
7317 
7318 	if (lnum > rnum)
7319 		return (1);
7320 	if (lnum < rnum)
7321 		return (-1);
7322 	return (0);
7323 }
7324 
7325 /*
7326  * Parse the patchinfo string for the patch.
7327  *
7328  * We are parsing entries of the form:
7329  * PATCH_INFO_121454-02=Installed: Wed Dec  7 07:13:51 PST 2005 From: mum \
7330  *	Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \
7331  *	119255-06 Incompatibles:
7332  *
7333  * A backed out patch will have "backed out\n" as the status.  We should
7334  * skip these patches.  We also ignore any entries that seem to be
7335  * corrupted.  Obsolete patches are saved in the obs_patches parameter
7336  * AVL list.
7337  */
7338 static int
7339 parse_info(char *patchinfo, uu_avl_pool_t *patches_pool, uu_avl_t *patches_avl,
7340     uu_avl_t *obs_patches, uu_list_pool_t *list_pool)
7341 {
7342 	char		*p;
7343 	char		*lastp;
7344 	char		*ep;
7345 	char		*pvers;
7346 	boolean_t	add_info = B_FALSE;
7347 	patch_node_t	*patch;
7348 
7349 	if (strlen(patchinfo) < (sizeof (PATCHINFO) - 1))
7350 		return (Z_OK);
7351 
7352 	/* Skip over "PATCH_INFO_" to get the patch id. */
7353 	p = patchinfo + sizeof (PATCHINFO) - 1;
7354 	if ((ep = strchr(p, '=')) == NULL)
7355 		return (Z_OK);
7356 
7357 	*ep++ = '\0';
7358 
7359 	/* Ignore all but installed patches. */
7360 	if (strncmp(ep, "Installed:", 10) != 0)
7361 		return (Z_OK);
7362 
7363 	/* remove newline */
7364 	lastp = (ep + strlen(ep) - 1);
7365 	if (*lastp == '\n')
7366 		*lastp = '\0';
7367 
7368 	if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL)
7369 		return (Z_NOMEM);
7370 
7371 	if ((pvers = strchr(p, '-')) != NULL)
7372 		*pvers++ = '\0';
7373 	else
7374 		pvers = "";
7375 
7376 	if ((patch->patch_num = strdup(p)) == NULL) {
7377 		free(patch);
7378 		return (Z_NOMEM);
7379 	}
7380 	if ((patch->patch_vers = strdup(pvers)) == NULL) {
7381 		free(patch->patch_num);
7382 		free(patch);
7383 		return (Z_NOMEM);
7384 	}
7385 	patch->obs_patches = NULL;
7386 
7387 	uu_avl_node_init(patch, &patch->patch_node, patches_pool);
7388 	save_patch(patch, patches_avl);
7389 
7390 	/*
7391 	 * Start with the first token.  This will probably be "Installed:".
7392 	 * If we can't tokenize this entry, just return.
7393 	 */
7394 	if ((p = strtok_r(ep, " ", &lastp)) == NULL)
7395 		return (Z_OK);
7396 
7397 	do {
7398 		if (strcmp(p, "Installed:") == 0 ||
7399 		    strcmp(p, "Requires:") == 0 ||
7400 		    strcmp(p, "From:") == 0 ||
7401 		    strcmp(p, "Incompatibles:") == 0) {
7402 			add_info = B_FALSE;
7403 			continue;
7404 		} else if (strcmp(p, "Obsoletes:") == 0) {
7405 			add_info = B_TRUE;
7406 			continue;
7407 		}
7408 
7409 		if (!add_info)
7410 			continue;
7411 
7412 		if ((pvers = strchr(p, '-')) != NULL)
7413 			*pvers = '\0';
7414 
7415 		/*
7416 		 * We save all of the obsolete patches in one big list in the
7417 		 * obs_patches AVL tree so that we know not to output those as
7418 		 * part of the sw dependencies.  However, we also need to save
7419 		 * the obsolete patch information for this sepcific patch so
7420 		 * so that we can do the cross manifest patch checking
7421 		 * correctly.
7422 		 */
7423 		if (save_obs_patch(p, patches_pool, obs_patches) != Z_OK)
7424 			return (Z_NOMEM);
7425 		if (add_obs_patch(patch, p, list_pool) != Z_OK)
7426 			return (Z_NOMEM);
7427 	} while ((p = strtok_r(NULL, " ", &lastp)) != NULL);
7428 
7429 	return (Z_OK);
7430 }
7431 
7432 /*
7433  * AVL walker callback used to add patch to XML manifest.
7434  *
7435  * PATH_MAX is used in the pkg/patch code as the maximum size for the patch
7436  * number/version string.
7437  */
7438 static int
7439 add_patch(void *e, void *p)
7440 {
7441 	xmlNodePtr	node;
7442 	xmlNodePtr	cur;
7443 	char		id[PATH_MAX];
7444 	patch_node_t	*patch;
7445 	patch_parms_t	*args;
7446 
7447 	patch = e;
7448 	args = p;
7449 
7450 	/* skip this patch if it has been obsoleted */
7451 	if (obsolete_patch(patch, args->obs_patches_avl))
7452 		return (UU_WALK_NEXT);
7453 
7454 	if (patch->patch_vers[0] == '\0')
7455 		(void) snprintf(id, sizeof (id), "%s", patch->patch_num);
7456 	else
7457 		(void) snprintf(id, sizeof (id), "%s-%s", patch->patch_num,
7458 		    patch->patch_vers);
7459 
7460 	if ((args->res = operation_prep(args->handle)) != Z_OK)
7461 		return (UU_WALK_DONE);
7462 
7463 	cur = args->handle->zone_dh_cur;
7464 	node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL);
7465 	if ((args->res = newprop(node, DTD_ATTR_ID, id)) != Z_OK)
7466 		return (UU_WALK_DONE);
7467 
7468 	if (patch->obs_patches != NULL) {
7469 		obs_patch_node_t *op;
7470 		xmlNodePtr	node2;
7471 
7472 		for (op = uu_list_first(patch->obs_patches); op != NULL;
7473 		    op = uu_list_next(patch->obs_patches, op)) {
7474 			(void) snprintf(id, sizeof (id), "%s", op->patch_num);
7475 			node2 = xmlNewTextChild(node, NULL, DTD_ELEM_OBSOLETES,
7476 			    NULL);
7477 			if ((args->res = newprop(node2, DTD_ATTR_ID, id))
7478 			    != Z_OK)
7479 				return (UU_WALK_DONE);
7480 		}
7481 	}
7482 
7483 	return (UU_WALK_NEXT);
7484 }
7485 
7486 static void
7487 patch_avl_delete(uu_avl_t *patches_avl)
7488 {
7489 	if (patches_avl != NULL) {
7490 		patch_node_t *p;
7491 		void *cookie = NULL;
7492 
7493 		while ((p = (patch_node_t *)uu_avl_teardown(patches_avl,
7494 		    &cookie)) != NULL) {
7495 			free(p->patch_num);
7496 			free(p->patch_vers);
7497 
7498 			if (p->obs_patches != NULL) {
7499 				obs_patch_node_t *op;
7500 				void *cookie2 = NULL;
7501 
7502 				while ((op = uu_list_teardown(p->obs_patches,
7503 				    &cookie2)) != NULL) {
7504 					free(op->patch_num);
7505 					free(op);
7506 				}
7507 				uu_list_destroy(p->obs_patches);
7508 			}
7509 
7510 			free(p);
7511 		}
7512 
7513 		uu_avl_destroy(patches_avl);
7514 	}
7515 }
7516 
7517 /*
7518  * Add the unique, highest version patches that are associated with this pkg
7519  * to the sw inventory on the handle.
7520  */
7521 static int
7522 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop,
7523     uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches,
7524     uu_list_pool_t *list_pool)
7525 {
7526 	int		i;
7527 	int		res;
7528 	uu_avl_t 	*patches_avl;
7529 	patch_parms_t	args;
7530 
7531 	if ((patches_avl = uu_avl_create(patches_pool, NULL, UU_DEFAULT))
7532 	    == NULL)
7533 		return (Z_NOMEM);
7534 
7535 	for (i = 0; i < infop->zpi_patch_cnt; i++) {
7536 		if ((res = parse_info(infop->zpi_patchinfo[i], patches_pool,
7537 		    patches_avl, obs_patches, list_pool)) != Z_OK) {
7538 			patch_avl_delete(patches_avl);
7539 			return (res);
7540 		}
7541 	}
7542 
7543 	args.obs_patches_avl = obs_patches;
7544 	args.handle = handle;
7545 	args.res = Z_OK;
7546 
7547 	(void) uu_avl_walk(patches_avl, add_patch, &args, 0);
7548 
7549 	patch_avl_delete(patches_avl);
7550 	return (args.res);
7551 }
7552 
7553 /*
7554  * Keep track of the pkgs we have already processed so that we can quickly
7555  * skip those pkgs while recursively doing dependents.
7556  */
7557 static boolean_t
7558 pkg_in_manifest(uu_avl_t *saw_pkgs, char *pname, uu_avl_pool_t *pkgs_pool)
7559 {
7560 	uu_avl_index_t where;
7561 
7562 	if (uu_avl_find(saw_pkgs, pname, NULL, &where) == NULL) {
7563 		zone_pkg_entry_t *pkg;
7564 
7565 		/*
7566 		 * We need to add it.  If we don't have memory we just skip
7567 		 * this pkg since this routine improves performance but the
7568 		 * algorithm is still correct without it.
7569 		 */
7570 		if ((pkg = (zone_pkg_entry_t *)
7571 		    malloc(sizeof (zone_pkg_entry_t))) == NULL)
7572 			return (B_FALSE);
7573 
7574 		if ((pkg->zpe_name = strdup(pname)) == NULL) {
7575 			free(pkg);
7576 			return (B_FALSE);
7577 		}
7578 
7579 		pkg->zpe_vers = NULL;
7580 		pkg->zpe_patches_avl = NULL;
7581 
7582 		/* Insert pkg into the AVL tree. */
7583 		uu_avl_node_init(pkg, &pkg->zpe_entry, pkgs_pool);
7584 		uu_avl_insert(saw_pkgs, pkg, where);
7585 		return (B_FALSE);
7586 	}
7587 
7588 	return (B_TRUE);
7589 }
7590 
7591 /*
7592  * Add the pkg to the sw inventory on the handle.
7593  */
7594 static int
7595 add_pkg(zone_dochandle_t handle, char *name, char *version)
7596 {
7597 	xmlNodePtr newnode;
7598 	xmlNodePtr cur;
7599 	int err;
7600 
7601 	if ((err = operation_prep(handle)) != Z_OK)
7602 		return (err);
7603 
7604 	cur = handle->zone_dh_cur;
7605 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL);
7606 	if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK)
7607 		return (err);
7608 	if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK)
7609 		return (err);
7610 	return (Z_OK);
7611 }
7612 
7613 static void
7614 free_pkginfo(struct zone_pkginfo *infop)
7615 {
7616 	free(infop->zpi_version);
7617 	if (infop->zpi_patch_cnt > 0) {
7618 		int i;
7619 
7620 		for (i = 0; i < infop->zpi_patch_cnt; i++)
7621 			free(infop->zpi_patchinfo[i]);
7622 		free(infop->zpi_patchinfo);
7623 	}
7624 }
7625 
7626 /*
7627  * Read the pkginfo file and populate the structure with the data we need
7628  * from this pkg for a sw inventory.
7629  */
7630 static int
7631 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop)
7632 {
7633 	FILE	*fp;
7634 	char	*buf;
7635 	int	err = 0;
7636 
7637 	infop->zpi_all_zones = B_FALSE;
7638 	infop->zpi_this_zone = B_FALSE;
7639 	infop->zpi_version = NULL;
7640 	infop->zpi_patch_cnt = 0;
7641 	infop->zpi_patchinfo = NULL;
7642 
7643 	if ((fp = fopen(pkginfo, "r")) == NULL)
7644 		return (errno);
7645 
7646 	while ((buf = read_pkg_data(fp)) != NULL) {
7647 		if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) {
7648 			int len;
7649 
7650 			if ((infop->zpi_version =
7651 			    strdup(buf + sizeof (VERSION) - 1)) == NULL) {
7652 				err = ENOMEM;
7653 				break;
7654 			}
7655 
7656 			/* remove trailing newline */
7657 			len = strlen(infop->zpi_version);
7658 			*(infop->zpi_version + len - 1) = 0;
7659 
7660 		} else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) {
7661 			infop->zpi_all_zones = B_TRUE;
7662 
7663 		} else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) {
7664 			infop->zpi_this_zone = B_TRUE;
7665 
7666 		} else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1)
7667 		    == 0) {
7668 			char **p;
7669 
7670 			if ((p = (char **)realloc(infop->zpi_patchinfo,
7671 			    sizeof (char *) * (infop->zpi_patch_cnt + 1)))
7672 			    == NULL) {
7673 				err = ENOMEM;
7674 				break;
7675 			}
7676 			infop->zpi_patchinfo = p;
7677 
7678 			if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] =
7679 			    strdup(buf)) == NULL) {
7680 				err = ENOMEM;
7681 				break;
7682 			}
7683 			infop->zpi_patch_cnt++;
7684 		}
7685 
7686 		free(buf);
7687 	}
7688 
7689 	free(buf);
7690 
7691 	if (errno == ENOMEM) {
7692 		err = ENOMEM;
7693 		/* Clean up anything we did manage to allocate. */
7694 		free_pkginfo(infop);
7695 	}
7696 
7697 	(void) fclose(fp);
7698 
7699 	return (err);
7700 }
7701 
7702 /*
7703  * Add any dependent pkgs to the list.  The pkg depend file lists pkg
7704  * dependencies, one per line with an entry that looks like:
7705  *	P SUNWcar       Core Architecture, (Root)
7706  * See the depend(4) man page.
7707  */
7708 static int
7709 add_dependents(zone_dochandle_t handle, char *pname,
7710     uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches,
7711     uu_list_pool_t *list_pool, uu_avl_t *saw_pkgs, uu_avl_pool_t *pkgs_pool)
7712 {
7713 	int		res = Z_OK;
7714 	FILE		*fp;
7715 	char		depend[MAXPATHLEN];
7716 	char		*buf;
7717 	struct stat	sbuf;
7718 
7719 	(void) snprintf(depend, sizeof (depend), "%s/%s/install/depend",
7720 	    PKG_PATH, pname);
7721 
7722 	if (stat(depend, &sbuf) == -1 || !S_ISREG(sbuf.st_mode))
7723 		return (Z_OK);
7724 
7725 	if ((fp = fopen(depend, "r")) == NULL)
7726 		return (Z_OK);
7727 
7728 	while ((buf = read_pkg_data(fp)) != NULL) {
7729 		char *deppkg;
7730 		char *delims = " \t";
7731 		char pkginfo[MAXPATHLEN];
7732 		struct zone_pkginfo info;
7733 
7734 		if (*buf != 'P') {
7735 			free(buf);
7736 			continue;
7737 		}
7738 
7739 		/* Skip past the leading 'P '. */
7740 		if ((deppkg = strtok(buf + 2, delims)) == NULL) {
7741 			free(buf);
7742 			continue;
7743 		}
7744 
7745 		/* If the pkg is already in the manifest don't add it again. */
7746 		if (pkg_in_manifest(saw_pkgs, deppkg, pkgs_pool)) {
7747 			free(buf);
7748 			continue;
7749 		}
7750 
7751 		(void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo",
7752 		    PKG_PATH, deppkg);
7753 
7754 		if (stat(pkginfo, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) {
7755 			free(buf);
7756 			continue;
7757 		}
7758 
7759 		if (get_pkginfo(pkginfo, &info) != 0) {
7760 			res = Z_NOMEM;
7761 			free(buf);
7762 			break;
7763 		}
7764 
7765 		if ((res = add_dependents(handle, deppkg, patches_pool,
7766 		    obs_patches, list_pool, saw_pkgs, pkgs_pool)) == Z_OK &&
7767 		    (res = add_pkg(handle, deppkg, info.zpi_version)) == Z_OK) {
7768 			if (info.zpi_patch_cnt > 0)
7769 				res = add_patches(handle, &info, patches_pool,
7770 				    obs_patches, list_pool);
7771 		}
7772 
7773 		free(buf);
7774 		free_pkginfo(&info);
7775 
7776 		if (res != Z_OK)
7777 			break;
7778 	}
7779 
7780 	(void) fclose(fp);
7781 	return (res);
7782 }
7783 
7784 /* ARGSUSED */
7785 static int
7786 pkg_entry_compare(const void *l_arg, const void *r_arg, void *private)
7787 {
7788 	zone_pkg_entry_t *pkg = (zone_pkg_entry_t *)l_arg;
7789 	char *name = (char *)r_arg;
7790 
7791 	return (strcmp(pkg->zpe_name, name));
7792 }
7793 
7794 static void
7795 pkg_avl_delete(uu_avl_t *pavl)
7796 {
7797 	if (pavl != NULL) {
7798 		zone_pkg_entry_t *p;
7799 		void *cookie = NULL;
7800 
7801 		while ((p = uu_avl_teardown(pavl, &cookie)) != NULL) {
7802 			free(p->zpe_name);
7803 			free(p);
7804 		}
7805 
7806 		uu_avl_destroy(pavl);
7807 	}
7808 }
7809 
7810 /*
7811  * Take a software inventory of the global zone.  We need to get the set of
7812  * packages and patches that are on the global zone that the specified
7813  * non-global zone depends on.  The packages we need in the inventory are:
7814  *
7815  * - skip the package if SUNW_PKG_THISZONE is 'true'
7816  * otherwise,
7817  * - add the package if
7818  * a) SUNW_PKG_ALLZONES is 'true',
7819  * or
7820  * b) any file delivered by the package is in a file system that is inherited
7821  * from the global zone.
7822  * If the zone does not inherit any file systems (whole root)
7823  * then (b) will be skipped.
7824  *
7825  * For each of the packages that is being added to the inventory, we will also
7826  * add its dependent packages to the inventory.
7827  *
7828  * For each of the packages that is being added to the inventory, we will also
7829  * add all of the associated, unique patches to the inventory.
7830  *
7831  * See the comment for zonecfg_getpkgdata() for compatability restrictions on
7832  * how we must save the XML representation of the software inventory.
7833  */
7834 static int
7835 zonecfg_sw_inventory(zone_dochandle_t handle)
7836 {
7837 	char		pkginfo[MAXPATHLEN];
7838 	int		res;
7839 	struct dirent	*dp;
7840 	DIR		*dirp;
7841 	struct stat	buf;
7842 	struct zone_pkginfo	info;
7843 	int		pkg_cnt = 0;
7844 	char		**pkgs = NULL;
7845 	uu_avl_pool_t 	*pkgs_pool = NULL;
7846 	uu_avl_pool_t 	*patches_pool = NULL;
7847 	uu_list_pool_t 	*list_pool = NULL;
7848 	uu_avl_t	*saw_pkgs = NULL;
7849 	uu_avl_t 	*obs_patches = NULL;
7850 
7851 	if ((pkgs_pool = uu_avl_pool_create("pkgs_pool",
7852 	    sizeof (zone_pkg_entry_t), offsetof(zone_pkg_entry_t, zpe_entry),
7853 	    pkg_entry_compare, UU_DEFAULT)) == NULL) {
7854 		res = Z_NOMEM;
7855 		goto done;
7856 	}
7857 
7858 	if ((saw_pkgs = uu_avl_create(pkgs_pool, NULL, UU_DEFAULT)) == NULL) {
7859 		res = Z_NOMEM;
7860 		goto done;
7861 	}
7862 
7863 	if ((patches_pool = uu_avl_pool_create("patches_pool",
7864 	    sizeof (patch_node_t), offsetof(patch_node_t, patch_node),
7865 	    patch_node_compare, UU_DEFAULT)) == NULL) {
7866 		res = Z_NOMEM;
7867 		goto done;
7868 	}
7869 
7870 	if ((list_pool = uu_list_pool_create("list_pool",
7871 	    sizeof (obs_patch_node_t), offsetof(obs_patch_node_t, link), NULL,
7872 	    UU_DEFAULT)) == NULL) {
7873 		res = Z_NOMEM;
7874 		goto done;
7875 	}
7876 
7877 	/*
7878 	 * The obs_patches AVL tree saves all of the obsolete patches so
7879 	 * that we know not to output those as part of the sw dependencies.
7880 	 */
7881 	if ((obs_patches = uu_avl_create(patches_pool, NULL, UU_DEFAULT))
7882 	    == NULL) {
7883 		res = Z_NOMEM;
7884 		goto done;
7885 	}
7886 
7887 	if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) {
7888 		res = Z_NOMEM;
7889 		goto done;
7890 	}
7891 
7892 	if ((dirp = opendir(PKG_PATH)) == NULL) {
7893 		res = Z_NOMEM;
7894 		goto done;
7895 	}
7896 
7897 	while ((dp = readdir(dirp)) != (struct dirent *)0) {
7898 		if (strcmp(dp->d_name, ".") == 0 ||
7899 		    strcmp(dp->d_name, "..") == 0)
7900 			continue;
7901 
7902 		(void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo",
7903 		    PKG_PATH, dp->d_name);
7904 
7905 		if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode))
7906 			continue;
7907 
7908 		if (get_pkginfo(pkginfo, &info) != 0) {
7909 			res = Z_NOMEM;
7910 			break;
7911 		}
7912 
7913 		if (!info.zpi_this_zone &&
7914 		    (info.zpi_all_zones ||
7915 		    dir_pkg(dp->d_name, pkgs, pkg_cnt)) &&
7916 		    !pkg_in_manifest(saw_pkgs, dp->d_name, pkgs_pool)) {
7917 			/*
7918 			 * Add dependents first so any patches will get
7919 			 * associated with the right pkg in the xml file.
7920 			 */
7921 			if ((res = add_dependents(handle, dp->d_name,
7922 			    patches_pool, obs_patches, list_pool, saw_pkgs,
7923 			    pkgs_pool)) == Z_OK &&
7924 			    (res = add_pkg(handle, dp->d_name,
7925 			    info.zpi_version)) == Z_OK) {
7926 				if (info.zpi_patch_cnt > 0)
7927 					res = add_patches(handle, &info,
7928 					    patches_pool, obs_patches,
7929 					    list_pool);
7930 			}
7931 		}
7932 
7933 		free_pkginfo(&info);
7934 
7935 		if (res != Z_OK)
7936 			break;
7937 	}
7938 
7939 	(void) closedir(dirp);
7940 
7941 done:
7942 	pkg_avl_delete(saw_pkgs);
7943 	patch_avl_delete(obs_patches);
7944 	if (pkgs_pool != NULL)
7945 		uu_avl_pool_destroy(pkgs_pool);
7946 	if (patches_pool != NULL)
7947 		uu_avl_pool_destroy(patches_pool);
7948 	if (list_pool != NULL)
7949 		uu_list_pool_destroy(list_pool);
7950 	free_ipd_pkgs(pkgs, pkg_cnt);
7951 
7952 	if (res == Z_OK)
7953 		handle->zone_dh_sw_inv = B_TRUE;
7954 
7955 	return (res);
7956 }
7957 
7958 /*
7959  * zonecfg_devwalk call-back function used during detach to generate the
7960  * dev info in the manifest.
7961  */
7962 static int
7963 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
7964     const char *acl, void *hdl)
7965 {
7966 	zone_dochandle_t handle = (zone_dochandle_t)hdl;
7967 	xmlNodePtr newnode;
7968 	xmlNodePtr cur;
7969 	int err;
7970 	char buf[128];
7971 
7972 	if ((err = operation_prep(handle)) != Z_OK)
7973 		return (err);
7974 
7975 	cur = handle->zone_dh_cur;
7976 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
7977 	if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
7978 		return (err);
7979 	(void) snprintf(buf, sizeof (buf), "%lu", uid);
7980 	if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
7981 		return (err);
7982 	(void) snprintf(buf, sizeof (buf), "%lu", gid);
7983 	if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
7984 		return (err);
7985 	(void) snprintf(buf, sizeof (buf), "%o", mode);
7986 	if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
7987 		return (err);
7988 	if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
7989 		return (err);
7990 	return (Z_OK);
7991 }
7992 
7993 /*
7994  * Get the information required to support detaching a zone.  This is
7995  * called on the source system when detaching (the detaching parameter should
7996  * be set to true) and on the destination system before attaching (the
7997  * detaching parameter should be false).
7998  *
7999  * For native Solaris zones, the detach/attach process involves validating
8000  * that the software on the global zone can support the zone when we attach.
8001  * To do this we take a software inventory of the global zone.  We also
8002  * have to keep track of the device configuration so that we can properly
8003  * recreate it on the destination.
8004  */
8005 int
8006 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching)
8007 {
8008 	int		res;
8009 
8010 	if ((res = zonecfg_sw_inventory(handle)) != Z_OK)
8011 		return (res);
8012 
8013 	if (detaching)
8014 		res = zonecfg_devwalk(handle, get_detach_dev_entry, handle);
8015 
8016 	return (res);
8017 }
8018