xref: /titanic_50/usr/src/lib/libzonecfg/common/libzonecfg.c (revision c0889d7a91fa87e1cb7ef4457629b0cb51d47b50)
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 		case ZONE_IS_INITIALIZED:
5111 			/* The kernel will not return these two states */
5112 			return (ZONE_STATE_READY);
5113 		case ZONE_IS_READY:
5114 			/*
5115 			 * If the zone's root is mounted on $ZONEPATH/lu, then
5116 			 * it's a mounted scratch zone.
5117 			 */
5118 			if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
5119 			    sizeof (zoneroot)) >= 0) {
5120 				zlen = strlen(zoneroot);
5121 				if (zlen > 3 &&
5122 				    strcmp(zoneroot + zlen - 3, "/lu") == 0)
5123 					return (ZONE_STATE_MOUNTED);
5124 			}
5125 			return (ZONE_STATE_READY);
5126 		case ZONE_IS_BOOTING:
5127 		case ZONE_IS_RUNNING:
5128 			return (ZONE_STATE_RUNNING);
5129 		case ZONE_IS_SHUTTING_DOWN:
5130 		case ZONE_IS_EMPTY:
5131 			return (ZONE_STATE_SHUTTING_DOWN);
5132 		case ZONE_IS_DOWN:
5133 		case ZONE_IS_DYING:
5134 		case ZONE_IS_DEAD:
5135 		default:
5136 			return (ZONE_STATE_DOWN);
5137 	}
5138 	/* NOTREACHED */
5139 }
5140 
5141 int
5142 zone_get_state(char *zone_name, zone_state_t *state_num)
5143 {
5144 	zone_status_t status;
5145 	zoneid_t zone_id;
5146 	struct zoneent *ze;
5147 	boolean_t found = B_FALSE;
5148 	FILE *cookie;
5149 	char kernzone[ZONENAME_MAX];
5150 	FILE *fp;
5151 
5152 	if (zone_name == NULL)
5153 		return (Z_INVAL);
5154 
5155 	/*
5156 	 * If we're looking at an alternate root, then we need to query the
5157 	 * kernel using the scratch zone name.
5158 	 */
5159 	zone_id = -1;
5160 	if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
5161 		if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
5162 			if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
5163 			    kernzone, sizeof (kernzone)) == 0)
5164 				zone_id = getzoneidbyname(kernzone);
5165 			zonecfg_close_scratch(fp);
5166 		}
5167 	} else {
5168 		zone_id = getzoneidbyname(zone_name);
5169 	}
5170 
5171 	/* check to see if zone is running */
5172 	if (zone_id != -1 &&
5173 	    zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
5174 	    sizeof (status)) >= 0) {
5175 		*state_num = kernel_state_to_user_state(zone_id, status);
5176 		return (Z_OK);
5177 	}
5178 
5179 	cookie = setzoneent();
5180 	while ((ze = getzoneent_private(cookie)) != NULL) {
5181 		if (strcmp(ze->zone_name, zone_name) == 0) {
5182 			found = B_TRUE;
5183 			*state_num = ze->zone_state;
5184 		}
5185 		free(ze);
5186 		if (found)
5187 			break;
5188 	}
5189 	endzoneent(cookie);
5190 	return ((found) ? Z_OK : Z_NO_ZONE);
5191 }
5192 
5193 int
5194 zone_set_state(char *zone, zone_state_t state)
5195 {
5196 	struct zoneent ze;
5197 
5198 	if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
5199 	    state != ZONE_STATE_INCOMPLETE)
5200 		return (Z_INVAL);
5201 
5202 	bzero(&ze, sizeof (ze));
5203 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
5204 	ze.zone_state = state;
5205 	(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
5206 	return (putzoneent(&ze, PZE_MODIFY));
5207 }
5208 
5209 /*
5210  * Get id (if any) for specified zone.  There are four possible outcomes:
5211  * - If the string corresponds to the numeric id of an active (booted)
5212  *   zone, sets *zip to the zone id and returns 0.
5213  * - If the string corresponds to the name of an active (booted) zone,
5214  *   sets *zip to the zone id and returns 0.
5215  * - If the string is a name in the configuration but is not booted,
5216  *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
5217  * - Otherwise, leaves *zip unchanged and returns -1.
5218  *
5219  * This function acts as an auxiliary filter on the function of the same
5220  * name in libc; the linker binds to this version if libzonecfg exists,
5221  * and the libc version if it doesn't.  Any changes to this version of
5222  * the function should probably be reflected in the libc version as well.
5223  */
5224 int
5225 zone_get_id(const char *str, zoneid_t *zip)
5226 {
5227 	zone_dochandle_t hdl;
5228 	zoneid_t zoneid;
5229 	char *cp;
5230 	int err;
5231 
5232 	/* first try looking for active zone by id */
5233 	errno = 0;
5234 	zoneid = (zoneid_t)strtol(str, &cp, 0);
5235 	if (errno == 0 && cp != str && *cp == '\0' &&
5236 	    getzonenamebyid(zoneid, NULL, 0) != -1) {
5237 		*zip = zoneid;
5238 		return (0);
5239 	}
5240 
5241 	/* then look for active zone by name */
5242 	if ((zoneid = getzoneidbyname(str)) != -1) {
5243 		*zip = zoneid;
5244 		return (0);
5245 	}
5246 
5247 	/* if in global zone, try looking up name in configuration database */
5248 	if (getzoneid() != GLOBAL_ZONEID ||
5249 	    (hdl = zonecfg_init_handle()) == NULL)
5250 		return (-1);
5251 
5252 	if (zonecfg_get_handle(str, hdl) == Z_OK) {
5253 		/* zone exists but isn't active */
5254 		*zip = ZONE_ID_UNDEFINED;
5255 		err = 0;
5256 	} else {
5257 		err = -1;
5258 	}
5259 
5260 	zonecfg_fini_handle(hdl);
5261 	return (err);
5262 }
5263 
5264 char *
5265 zone_state_str(zone_state_t state_num)
5266 {
5267 	switch (state_num) {
5268 	case ZONE_STATE_CONFIGURED:
5269 		return (ZONE_STATE_STR_CONFIGURED);
5270 	case ZONE_STATE_INCOMPLETE:
5271 		return (ZONE_STATE_STR_INCOMPLETE);
5272 	case ZONE_STATE_INSTALLED:
5273 		return (ZONE_STATE_STR_INSTALLED);
5274 	case ZONE_STATE_READY:
5275 		return (ZONE_STATE_STR_READY);
5276 	case ZONE_STATE_MOUNTED:
5277 		return (ZONE_STATE_STR_MOUNTED);
5278 	case ZONE_STATE_RUNNING:
5279 		return (ZONE_STATE_STR_RUNNING);
5280 	case ZONE_STATE_SHUTTING_DOWN:
5281 		return (ZONE_STATE_STR_SHUTTING_DOWN);
5282 	case ZONE_STATE_DOWN:
5283 		return (ZONE_STATE_STR_DOWN);
5284 	default:
5285 		return ("unknown");
5286 	}
5287 }
5288 
5289 /*
5290  * Given a UUID value, find an associated zone name.  This is intended to be
5291  * used by callers who set up some 'default' name (corresponding to the
5292  * expected name for the zone) in the zonename buffer, and thus the function
5293  * doesn't touch this buffer on failure.
5294  */
5295 int
5296 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen)
5297 {
5298 	FILE *fp;
5299 	struct zoneent *ze;
5300 	uchar_t *uuid;
5301 
5302 	/*
5303 	 * A small amount of subterfuge via casts is necessary here because
5304 	 * libuuid doesn't use const correctly, but we don't want to export
5305 	 * this brokenness to our clients.
5306 	 */
5307 	uuid = (uchar_t *)uuidin;
5308 	if (uuid_is_null(uuid))
5309 		return (Z_NO_ZONE);
5310 	if ((fp = setzoneent()) == NULL)
5311 		return (Z_NO_ZONE);
5312 	while ((ze = getzoneent_private(fp)) != NULL) {
5313 		if (uuid_compare(uuid, ze->zone_uuid) == 0)
5314 			break;
5315 		free(ze);
5316 	}
5317 	endzoneent(fp);
5318 	if (ze != NULL) {
5319 		(void) strlcpy(zonename, ze->zone_name, namelen);
5320 		free(ze);
5321 		return (Z_OK);
5322 	} else {
5323 		return (Z_NO_ZONE);
5324 	}
5325 }
5326 
5327 /*
5328  * Given a zone name, get its UUID.  Returns a "NULL" UUID value if the zone
5329  * exists but the file doesn't have a value set yet.  Returns an error if the
5330  * zone cannot be located.
5331  */
5332 int
5333 zonecfg_get_uuid(const char *zonename, uuid_t uuid)
5334 {
5335 	FILE *fp;
5336 	struct zoneent *ze;
5337 
5338 	if ((fp = setzoneent()) == NULL)
5339 		return (Z_NO_ZONE);
5340 	while ((ze = getzoneent_private(fp)) != NULL) {
5341 		if (strcmp(ze->zone_name, zonename) == 0)
5342 			break;
5343 		free(ze);
5344 	}
5345 	endzoneent(fp);
5346 	if (ze != NULL) {
5347 		uuid_copy(uuid, ze->zone_uuid);
5348 		free(ze);
5349 		return (Z_OK);
5350 	} else {
5351 		return (Z_NO_ZONE);
5352 	}
5353 }
5354 
5355 /*
5356  * File-system convenience functions.
5357  */
5358 boolean_t
5359 zonecfg_valid_fs_type(const char *type)
5360 {
5361 	/*
5362 	 * We already know which FS types don't work.
5363 	 */
5364 	if (strcmp(type, "proc") == 0 ||
5365 	    strcmp(type, "mntfs") == 0 ||
5366 	    strcmp(type, "autofs") == 0 ||
5367 	    strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 ||
5368 	    strcmp(type, "cachefs") == 0)
5369 		return (B_FALSE);
5370 	/*
5371 	 * The caller may do more detailed verification to make sure other
5372 	 * aspects of this filesystem type make sense.
5373 	 */
5374 	return (B_TRUE);
5375 }
5376 
5377 /*
5378  * Generally uninteresting rctl convenience functions.
5379  */
5380 
5381 int
5382 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
5383     rctlblk_t *rctlblk)
5384 {
5385 	unsigned long long ull;
5386 	char *endp;
5387 	rctl_priv_t priv;
5388 	rctl_qty_t limit;
5389 	uint_t action;
5390 
5391 	/* Get the privilege */
5392 	if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
5393 		priv = RCPRIV_BASIC;
5394 	} else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
5395 		priv = RCPRIV_PRIVILEGED;
5396 	} else {
5397 		/* Invalid privilege */
5398 		return (Z_INVAL);
5399 	}
5400 
5401 	/* deal with negative input; strtoull(3c) doesn't do what we want */
5402 	if (rctlval->zone_rctlval_limit[0] == '-')
5403 		return (Z_INVAL);
5404 	/* Get the limit */
5405 	errno = 0;
5406 	ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
5407 	if (errno != 0 || *endp != '\0') {
5408 		/* parse failed */
5409 		return (Z_INVAL);
5410 	}
5411 	limit = (rctl_qty_t)ull;
5412 
5413 	/* Get the action */
5414 	if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
5415 		action = RCTL_LOCAL_NOACTION;
5416 	} else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
5417 		action = RCTL_LOCAL_SIGNAL;
5418 	} else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
5419 		action = RCTL_LOCAL_DENY;
5420 	} else {
5421 		/* Invalid Action */
5422 		return (Z_INVAL);
5423 	}
5424 	rctlblk_set_local_action(rctlblk, action, 0);
5425 	rctlblk_set_privilege(rctlblk, priv);
5426 	rctlblk_set_value(rctlblk, limit);
5427 	return (Z_OK);
5428 }
5429 
5430 static int
5431 rctl_check(const char *rctlname, void *arg)
5432 {
5433 	const char *attrname = arg;
5434 
5435 	/*
5436 	 * Returning 1 here is our signal to zonecfg_is_rctl() that it is
5437 	 * indeed an rctl name recognized by the system.
5438 	 */
5439 	return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
5440 }
5441 
5442 boolean_t
5443 zonecfg_is_rctl(const char *name)
5444 {
5445 	return (rctl_walk(rctl_check, (void *)name) == 1);
5446 }
5447 
5448 boolean_t
5449 zonecfg_valid_rctlname(const char *name)
5450 {
5451 	const char *c;
5452 
5453 	if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
5454 		return (B_FALSE);
5455 	if (strlen(name) == sizeof ("zone.") - 1)
5456 		return (B_FALSE);
5457 	for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
5458 		if (!isalpha(*c) && *c != '-')
5459 			return (B_FALSE);
5460 	}
5461 	return (B_TRUE);
5462 }
5463 
5464 boolean_t
5465 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
5466 {
5467 	rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
5468 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
5469 
5470 	if (priv != RCPRIV_PRIVILEGED)
5471 		return (B_FALSE);
5472 	if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
5473 		return (B_FALSE);
5474 	return (B_TRUE);
5475 }
5476 
5477 boolean_t
5478 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
5479 {
5480 	rctlblk_t *current, *next;
5481 	rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
5482 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
5483 	uint_t global_flags;
5484 
5485 	if (!zonecfg_valid_rctlblk(rctlblk))
5486 		return (B_FALSE);
5487 	if (!zonecfg_valid_rctlname(name))
5488 		return (B_FALSE);
5489 
5490 	current = alloca(rctlblk_size());
5491 	if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
5492 		return (B_TRUE);	/* not an rctl on this system */
5493 	/*
5494 	 * Make sure the proposed value isn't greater than the current system
5495 	 * value.
5496 	 */
5497 	next = alloca(rctlblk_size());
5498 	while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
5499 		rctlblk_t *tmp;
5500 
5501 		if (getrctl(name, current, next, RCTL_NEXT) != 0)
5502 			return (B_FALSE);	/* shouldn't happen */
5503 		tmp = current;
5504 		current = next;
5505 		next = tmp;
5506 	}
5507 	if (limit > rctlblk_get_value(current))
5508 		return (B_FALSE);
5509 
5510 	/*
5511 	 * Make sure the proposed action is allowed.
5512 	 */
5513 	global_flags = rctlblk_get_global_flags(current);
5514 	if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
5515 	    action == RCTL_LOCAL_DENY)
5516 		return (B_FALSE);
5517 	if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
5518 	    action == RCTL_LOCAL_NOACTION)
5519 		return (B_FALSE);
5520 
5521 	return (B_TRUE);
5522 }
5523 
5524 /*
5525  * There is always a race condition between reading the initial copy of
5526  * a zones state and its state changing.  We address this by providing
5527  * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
5528  * When zonecfg_critical_enter is called, sets the state field to LOCKED
5529  * and aquires biglock. Biglock protects against other threads executing
5530  * critical_enter and the state field protects against state changes during
5531  * the critical period.
5532  *
5533  * If any state changes occur, zn_cb will set the failed field of the znotify
5534  * structure.  This will cause the critical_exit function to re-lock the
5535  * channel and return an error. Since evsnts may be delayed, the critical_exit
5536  * function "flushes" the queue by putting an event on the queue and waiting for
5537  * zn_cb to notify critical_exit that it received the ping event.
5538  */
5539 static const char *
5540 string_get_tok(const char *in, char delim, int num)
5541 {
5542 	int i = 0;
5543 
5544 	for (; i < num; in++) {
5545 		if (*in == delim)
5546 			i++;
5547 		if (*in == 0)
5548 			return (NULL);
5549 	}
5550 	return (in);
5551 }
5552 
5553 static boolean_t
5554 is_ping(sysevent_t *ev)
5555 {
5556 	if (strcmp(sysevent_get_subclass_name(ev),
5557 	    ZONE_EVENT_PING_SUBCLASS) == 0) {
5558 		return (B_TRUE);
5559 	} else {
5560 		return (B_FALSE);
5561 	}
5562 }
5563 
5564 static boolean_t
5565 is_my_ping(sysevent_t *ev)
5566 {
5567 	const char *sender;
5568 	char mypid[sizeof (pid_t) * 3 + 1];
5569 
5570 	(void) snprintf(mypid, sizeof (mypid), "%i", getpid());
5571 	sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
5572 	if (sender == NULL)
5573 		return (B_FALSE);
5574 	if (strcmp(sender, mypid) != 0)
5575 		return (B_FALSE);
5576 	return (B_TRUE);
5577 }
5578 
5579 static int
5580 do_callback(struct znotify *zevtchan, sysevent_t *ev)
5581 {
5582 	nvlist_t *l;
5583 	int zid;
5584 	char *zonename;
5585 	char *newstate;
5586 	char *oldstate;
5587 	int ret;
5588 	hrtime_t when;
5589 
5590 	if (strcmp(sysevent_get_subclass_name(ev),
5591 	    ZONE_EVENT_STATUS_SUBCLASS) == 0) {
5592 
5593 		if (sysevent_get_attr_list(ev, &l) != 0) {
5594 			if (errno == ENOMEM) {
5595 				zevtchan->zn_failure_count++;
5596 				return (EAGAIN);
5597 			}
5598 			return (0);
5599 		}
5600 		ret = 0;
5601 
5602 		if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
5603 		    (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
5604 		    == 0) &&
5605 		    (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
5606 		    == 0) &&
5607 		    (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
5608 		    (uint64_t *)&when) == 0) &&
5609 		    (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
5610 			ret = zevtchan->zn_callback(zonename, zid, newstate,
5611 			    oldstate, when, zevtchan->zn_private);
5612 		}
5613 
5614 		zevtchan->zn_failure_count = 0;
5615 		nvlist_free(l);
5616 		return (ret);
5617 	} else {
5618 		/*
5619 		 * We have received an event in an unknown subclass. Ignore.
5620 		 */
5621 		zevtchan->zn_failure_count = 0;
5622 		return (0);
5623 	}
5624 }
5625 
5626 static int
5627 zn_cb(sysevent_t *ev, void *p)
5628 {
5629 	struct znotify *zevtchan = p;
5630 	int error;
5631 
5632 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
5633 
5634 	if (is_ping(ev) && !is_my_ping(ev)) {
5635 		(void) pthread_mutex_unlock((&zevtchan->zn_mutex));
5636 		return (0);
5637 	}
5638 
5639 	if (zevtchan->zn_state == ZN_LOCKED) {
5640 		assert(!is_ping(ev));
5641 		zevtchan->zn_failed = B_TRUE;
5642 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5643 		return (0);
5644 	}
5645 
5646 	if (zevtchan->zn_state == ZN_PING_INFLIGHT) {
5647 		if (is_ping(ev)) {
5648 			zevtchan->zn_state = ZN_PING_RECEIVED;
5649 			(void) pthread_cond_signal(&(zevtchan->zn_cond));
5650 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5651 			return (0);
5652 		} else {
5653 			zevtchan->zn_failed = B_TRUE;
5654 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5655 			return (0);
5656 		}
5657 	}
5658 
5659 	if (zevtchan->zn_state == ZN_UNLOCKED) {
5660 
5661 		error = do_callback(zevtchan, ev);
5662 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5663 		/*
5664 		 * Every ENOMEM failure causes do_callback to increment
5665 		 * zn_failure_count and every success causes it to
5666 		 * set zn_failure_count to zero.  If we got EAGAIN,
5667 		 * we will sleep for zn_failure_count seconds and return
5668 		 * EAGAIN to gpec to try again.
5669 		 *
5670 		 * After 55 seconds, or 10 try's we give up and drop the
5671 		 * event.
5672 		 */
5673 		if (error == EAGAIN) {
5674 			if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) {
5675 				return (0);
5676 			}
5677 			(void) sleep(zevtchan->zn_failure_count);
5678 		}
5679 		return (error);
5680 	}
5681 
5682 	if (zevtchan->zn_state == ZN_PING_RECEIVED) {
5683 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5684 		return (0);
5685 	}
5686 
5687 	abort();
5688 	return (0);
5689 }
5690 
5691 void
5692 zonecfg_notify_critical_enter(void *h)
5693 {
5694 	struct znotify *zevtchan = h;
5695 
5696 	(void) pthread_mutex_lock(&(zevtchan->zn_bigmutex));
5697 	zevtchan->zn_state = ZN_LOCKED;
5698 }
5699 
5700 int
5701 zonecfg_notify_critical_exit(void * h)
5702 {
5703 
5704 	struct znotify *zevtchan = h;
5705 
5706 	if (zevtchan->zn_state == ZN_UNLOCKED)
5707 		return (0);
5708 
5709 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
5710 	zevtchan->zn_state = ZN_PING_INFLIGHT;
5711 
5712 	(void) sysevent_evc_publish(zevtchan->zn_eventchan,
5713 	    ZONE_EVENT_STATUS_CLASS,
5714 	    ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER,
5715 	    zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP);
5716 
5717 	while (zevtchan->zn_state != ZN_PING_RECEIVED) {
5718 		(void) pthread_cond_wait(&(zevtchan->zn_cond),
5719 		    &(zevtchan->zn_mutex));
5720 	}
5721 
5722 	if (zevtchan->zn_failed == B_TRUE) {
5723 		zevtchan->zn_state = ZN_LOCKED;
5724 		zevtchan->zn_failed = B_FALSE;
5725 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5726 		return (1);
5727 	}
5728 
5729 	zevtchan->zn_state = ZN_UNLOCKED;
5730 	(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5731 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
5732 	return (0);
5733 }
5734 
5735 void
5736 zonecfg_notify_critical_abort(void *h)
5737 {
5738 	struct znotify *zevtchan = h;
5739 
5740 	zevtchan->zn_state = ZN_UNLOCKED;
5741 	zevtchan->zn_failed = B_FALSE;
5742 	/*
5743 	 * Don't do anything about zn_lock. If it is held, it could only be
5744 	 * held by zn_cb and it will be unlocked soon.
5745 	 */
5746 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
5747 }
5748 
5749 void *
5750 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
5751     const char *newstate, const char *oldstate, hrtime_t when, void *p),
5752     void *p)
5753 {
5754 	struct znotify *zevtchan;
5755 	int i = 1;
5756 	int r;
5757 
5758 	zevtchan = malloc(sizeof (struct znotify));
5759 
5760 	if (zevtchan == NULL)
5761 		return (NULL);
5762 
5763 	zevtchan->zn_private = p;
5764 	zevtchan->zn_callback = func;
5765 	zevtchan->zn_state = ZN_UNLOCKED;
5766 	zevtchan->zn_failed = B_FALSE;
5767 
5768 	if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL))
5769 		goto out3;
5770 	if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) {
5771 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
5772 		goto out3;
5773 	}
5774 	if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) {
5775 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
5776 		(void) pthread_cond_destroy(&(zevtchan->zn_cond));
5777 		goto out3;
5778 	}
5779 
5780 	if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan),
5781 	    0) != 0)
5782 		goto out2;
5783 
5784 	do {
5785 		/*
5786 		 * At 4 digits the subscriber ID gets too long and we have
5787 		 * no chance of successfully registering.
5788 		 */
5789 		if (i > 999)
5790 			goto out1;
5791 
5792 		(void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i",
5793 		    getpid() % 999999l, i);
5794 
5795 		r = sysevent_evc_subscribe(zevtchan->zn_eventchan,
5796 		    zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb,
5797 		    zevtchan, 0);
5798 
5799 		i++;
5800 
5801 	} while (r);
5802 
5803 	return (zevtchan);
5804 out1:
5805 	sysevent_evc_unbind(zevtchan->zn_eventchan);
5806 out2:
5807 	(void) pthread_mutex_destroy(&zevtchan->zn_mutex);
5808 	(void) pthread_cond_destroy(&zevtchan->zn_cond);
5809 	(void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex));
5810 out3:
5811 	free(zevtchan);
5812 
5813 	return (NULL);
5814 }
5815 
5816 void
5817 zonecfg_notify_unbind(void *handle)
5818 {
5819 
5820 	int ret;
5821 
5822 	sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan);
5823 	/*
5824 	 * Check that all evc threads have gone away. This should be
5825 	 * enforced by sysevent_evc_unbind.
5826 	 */
5827 	ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex);
5828 
5829 	if (ret)
5830 		abort();
5831 
5832 	(void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex);
5833 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex);
5834 	(void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond);
5835 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex);
5836 
5837 	free(handle);
5838 }
5839 
5840 static int
5841 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
5842 {
5843 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
5844 	int err;
5845 
5846 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL);
5847 	if ((err = newprop(newnode, DTD_ATTR_NAME,
5848 	    tabptr->zone_dataset_name)) != Z_OK)
5849 		return (err);
5850 	return (Z_OK);
5851 }
5852 
5853 int
5854 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5855 {
5856 	int err;
5857 
5858 	if (tabptr == NULL)
5859 		return (Z_INVAL);
5860 
5861 	if ((err = operation_prep(handle)) != Z_OK)
5862 		return (err);
5863 
5864 	if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK)
5865 		return (err);
5866 
5867 	return (Z_OK);
5868 }
5869 
5870 static int
5871 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
5872 {
5873 	xmlNodePtr cur = handle->zone_dh_cur;
5874 
5875 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
5876 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5877 			continue;
5878 
5879 		if (match_prop(cur, DTD_ATTR_NAME,
5880 		    tabptr->zone_dataset_name)) {
5881 			xmlUnlinkNode(cur);
5882 			xmlFreeNode(cur);
5883 			return (Z_OK);
5884 		}
5885 	}
5886 	return (Z_NO_RESOURCE_ID);
5887 }
5888 
5889 int
5890 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5891 {
5892 	int err;
5893 
5894 	if (tabptr == NULL)
5895 		return (Z_INVAL);
5896 
5897 	if ((err = operation_prep(handle)) != Z_OK)
5898 		return (err);
5899 
5900 	if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK)
5901 		return (err);
5902 
5903 	return (Z_OK);
5904 }
5905 
5906 int
5907 zonecfg_modify_ds(
5908 	zone_dochandle_t handle,
5909 	struct zone_dstab *oldtabptr,
5910 	struct zone_dstab *newtabptr)
5911 {
5912 	int err;
5913 
5914 	if (oldtabptr == NULL || newtabptr == NULL)
5915 		return (Z_INVAL);
5916 
5917 	if ((err = operation_prep(handle)) != Z_OK)
5918 		return (err);
5919 
5920 	if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK)
5921 		return (err);
5922 
5923 	if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK)
5924 		return (err);
5925 
5926 	return (Z_OK);
5927 }
5928 
5929 int
5930 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5931 {
5932 	xmlNodePtr cur, firstmatch;
5933 	int err;
5934 	char dataset[MAXNAMELEN];
5935 
5936 	if (tabptr == NULL)
5937 		return (Z_INVAL);
5938 
5939 	if ((err = operation_prep(handle)) != Z_OK)
5940 		return (err);
5941 
5942 	cur = handle->zone_dh_cur;
5943 	firstmatch = NULL;
5944 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
5945 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5946 			continue;
5947 		if (strlen(tabptr->zone_dataset_name) > 0) {
5948 			if ((fetchprop(cur, DTD_ATTR_NAME, dataset,
5949 			    sizeof (dataset)) == Z_OK) &&
5950 			    (strcmp(tabptr->zone_dataset_name,
5951 			    dataset) == 0)) {
5952 				if (firstmatch == NULL)
5953 					firstmatch = cur;
5954 				else
5955 					return (Z_INSUFFICIENT_SPEC);
5956 			}
5957 		}
5958 	}
5959 	if (firstmatch == NULL)
5960 		return (Z_NO_RESOURCE_ID);
5961 
5962 	cur = firstmatch;
5963 
5964 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
5965 	    sizeof (tabptr->zone_dataset_name))) != Z_OK)
5966 		return (err);
5967 
5968 	return (Z_OK);
5969 }
5970 
5971 int
5972 zonecfg_setdsent(zone_dochandle_t handle)
5973 {
5974 	return (zonecfg_setent(handle));
5975 }
5976 
5977 int
5978 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
5979 {
5980 	xmlNodePtr cur;
5981 	int err;
5982 
5983 	if (handle == NULL)
5984 		return (Z_INVAL);
5985 
5986 	if ((cur = handle->zone_dh_cur) == NULL)
5987 		return (Z_NO_ENTRY);
5988 
5989 	for (; cur != NULL; cur = cur->next)
5990 		if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5991 			break;
5992 	if (cur == NULL) {
5993 		handle->zone_dh_cur = handle->zone_dh_top;
5994 		return (Z_NO_ENTRY);
5995 	}
5996 
5997 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
5998 	    sizeof (tabptr->zone_dataset_name))) != Z_OK) {
5999 		handle->zone_dh_cur = handle->zone_dh_top;
6000 		return (err);
6001 	}
6002 
6003 	handle->zone_dh_cur = cur->next;
6004 	return (Z_OK);
6005 }
6006 
6007 int
6008 zonecfg_enddsent(zone_dochandle_t handle)
6009 {
6010 	return (zonecfg_endent(handle));
6011 }
6012 
6013 /*
6014  * Support for aliased rctls; that is, rctls that have simplified names in
6015  * zonecfg.  For example, max-lwps is an alias for a well defined zone.max-lwps
6016  * rctl.  If there are multiple existing values for one of these rctls or if
6017  * there is a single value that does not match the well defined template (i.e.
6018  * it has a different action) then we cannot treat the rctl as having an alias
6019  * so we return Z_ALIAS_DISALLOW.  That means that the rctl cannot be
6020  * managed in zonecfg via an alias and that the standard rctl syntax must be
6021  * used.
6022  *
6023  * The possible return values are:
6024  *	Z_NO_PROPERTY_ID - invalid alias name
6025  *	Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition
6026  *	Z_NO_ENTRY - no rctl is configured for this alias
6027  *	Z_OK - we got a valid rctl for the specified alias
6028  */
6029 int
6030 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval)
6031 {
6032 	boolean_t found = B_FALSE;
6033 	boolean_t found_val = B_FALSE;
6034 	xmlNodePtr cur, val;
6035 	char savedname[MAXNAMELEN];
6036 	struct zone_rctlvaltab rctl;
6037 	int i;
6038 	int err;
6039 
6040 	for (i = 0; aliases[i].shortname != NULL; i++)
6041 		if (strcmp(name, aliases[i].shortname) == 0)
6042 			break;
6043 
6044 	if (aliases[i].shortname == NULL)
6045 		return (Z_NO_PROPERTY_ID);
6046 
6047 	if ((err = operation_prep(handle)) != Z_OK)
6048 		return (err);
6049 
6050 	cur = handle->zone_dh_cur;
6051 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6052 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0)
6053 			continue;
6054 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
6055 		    sizeof (savedname)) == Z_OK) &&
6056 		    (strcmp(savedname, aliases[i].realname) == 0)) {
6057 
6058 			/*
6059 			 * If we already saw one of these, we can't have an
6060 			 * alias since we just found another.
6061 			 */
6062 			if (found)
6063 				return (Z_ALIAS_DISALLOW);
6064 			found = B_TRUE;
6065 
6066 			for (val = cur->xmlChildrenNode; val != NULL;
6067 			    val = val->next) {
6068 				/*
6069 				 * If we already have one value, we can't have
6070 				 * an alias since we just found another.
6071 				 */
6072 				if (found_val)
6073 					return (Z_ALIAS_DISALLOW);
6074 				found_val = B_TRUE;
6075 
6076 				if ((fetchprop(val, DTD_ATTR_PRIV,
6077 				    rctl.zone_rctlval_priv,
6078 				    sizeof (rctl.zone_rctlval_priv)) != Z_OK))
6079 					break;
6080 				if ((fetchprop(val, DTD_ATTR_LIMIT,
6081 				    rctl.zone_rctlval_limit,
6082 				    sizeof (rctl.zone_rctlval_limit)) != Z_OK))
6083 					break;
6084 				if ((fetchprop(val, DTD_ATTR_ACTION,
6085 				    rctl.zone_rctlval_action,
6086 				    sizeof (rctl.zone_rctlval_action)) != Z_OK))
6087 					break;
6088 			}
6089 
6090 			/* check priv and action match the expected vals */
6091 			if (strcmp(rctl.zone_rctlval_priv,
6092 			    aliases[i].priv) != 0 ||
6093 			    strcmp(rctl.zone_rctlval_action,
6094 			    aliases[i].action) != 0)
6095 				return (Z_ALIAS_DISALLOW);
6096 		}
6097 	}
6098 
6099 	if (found) {
6100 		*rval = strtoull(rctl.zone_rctlval_limit, NULL, 10);
6101 		return (Z_OK);
6102 	}
6103 
6104 	return (Z_NO_ENTRY);
6105 }
6106 
6107 int
6108 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name)
6109 {
6110 	int i;
6111 	uint64_t val;
6112 	struct zone_rctltab rctltab;
6113 
6114 	/*
6115 	 * First check that we have a valid aliased rctl to remove.
6116 	 * This will catch an rctl entry with non-standard values or
6117 	 * multiple rctl values for this name.  We need to ignore those
6118 	 * rctl entries.
6119 	 */
6120 	if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK)
6121 		return (Z_OK);
6122 
6123 	for (i = 0; aliases[i].shortname != NULL; i++)
6124 		if (strcmp(name, aliases[i].shortname) == 0)
6125 			break;
6126 
6127 	if (aliases[i].shortname == NULL)
6128 		return (Z_NO_RESOURCE_ID);
6129 
6130 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6131 	    sizeof (rctltab.zone_rctl_name));
6132 
6133 	return (zonecfg_delete_rctl(handle, &rctltab));
6134 }
6135 
6136 boolean_t
6137 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name)
6138 {
6139 	uint64_t tmp_val;
6140 
6141 	switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) {
6142 	case Z_OK:
6143 		/*FALLTHRU*/
6144 	case Z_NO_ENTRY:
6145 		return (B_TRUE);
6146 	default:
6147 		return (B_FALSE);
6148 	}
6149 }
6150 
6151 int
6152 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val)
6153 {
6154 	int i;
6155 	int err;
6156 	struct zone_rctltab rctltab;
6157 	struct zone_rctlvaltab *rctlvaltab;
6158 	char buf[128];
6159 
6160 	if (!zonecfg_aliased_rctl_ok(handle, name))
6161 		return (Z_ALIAS_DISALLOW);
6162 
6163 	for (i = 0; aliases[i].shortname != NULL; i++)
6164 		if (strcmp(name, aliases[i].shortname) == 0)
6165 			break;
6166 
6167 	if (aliases[i].shortname == NULL)
6168 		return (Z_NO_RESOURCE_ID);
6169 
6170 	/* remove any pre-existing definition for this rctl */
6171 	(void) zonecfg_rm_aliased_rctl(handle, name);
6172 
6173 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6174 	    sizeof (rctltab.zone_rctl_name));
6175 
6176 	rctltab.zone_rctl_valptr = NULL;
6177 
6178 	if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL)
6179 		return (Z_NOMEM);
6180 
6181 	(void) snprintf(buf, sizeof (buf), "%llu", (long long)val);
6182 
6183 	(void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv,
6184 	    sizeof (rctlvaltab->zone_rctlval_priv));
6185 	(void) strlcpy(rctlvaltab->zone_rctlval_limit, buf,
6186 	    sizeof (rctlvaltab->zone_rctlval_limit));
6187 	(void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action,
6188 	    sizeof (rctlvaltab->zone_rctlval_action));
6189 
6190 	rctlvaltab->zone_rctlval_next = NULL;
6191 
6192 	if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK)
6193 		return (err);
6194 
6195 	return (zonecfg_add_rctl(handle, &rctltab));
6196 }
6197 
6198 static int
6199 delete_tmp_pool(zone_dochandle_t handle)
6200 {
6201 	int err;
6202 	xmlNodePtr cur = handle->zone_dh_cur;
6203 
6204 	if ((err = operation_prep(handle)) != Z_OK)
6205 		return (err);
6206 
6207 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6208 		if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6209 			xmlUnlinkNode(cur);
6210 			xmlFreeNode(cur);
6211 			return (Z_OK);
6212 		}
6213 	}
6214 
6215 	return (Z_NO_RESOURCE_ID);
6216 }
6217 
6218 static int
6219 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance)
6220 {
6221 	int err;
6222 	xmlNodePtr cur = handle->zone_dh_cur;
6223 	xmlNodePtr newnode;
6224 
6225 	err = delete_tmp_pool(handle);
6226 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6227 		return (err);
6228 
6229 	if (*pool_importance != '\0') {
6230 		if ((err = operation_prep(handle)) != Z_OK)
6231 			return (err);
6232 
6233 		newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL);
6234 		if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE,
6235 		    pool_importance)) != Z_OK)
6236 			return (err);
6237 	}
6238 
6239 	return (Z_OK);
6240 }
6241 
6242 static int
6243 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr)
6244 {
6245 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6246 	int err;
6247 
6248 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL);
6249 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN,
6250 	    tabptr->zone_ncpu_min)) != Z_OK)
6251 		return (err);
6252 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX,
6253 	    tabptr->zone_ncpu_max)) != Z_OK)
6254 		return (err);
6255 
6256 	if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK)
6257 		return (err);
6258 
6259 	return (Z_OK);
6260 }
6261 
6262 int
6263 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6264 {
6265 	int err;
6266 
6267 	if (tabptr == NULL)
6268 		return (Z_INVAL);
6269 
6270 	if ((err = operation_prep(handle)) != Z_OK)
6271 		return (err);
6272 
6273 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
6274 		return (err);
6275 
6276 	return (Z_OK);
6277 }
6278 
6279 int
6280 zonecfg_delete_pset(zone_dochandle_t handle)
6281 {
6282 	int err;
6283 	int res = Z_NO_RESOURCE_ID;
6284 	xmlNodePtr cur = handle->zone_dh_cur;
6285 
6286 	if ((err = operation_prep(handle)) != Z_OK)
6287 		return (err);
6288 
6289 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6290 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
6291 			xmlUnlinkNode(cur);
6292 			xmlFreeNode(cur);
6293 			res = Z_OK;
6294 			break;
6295 		}
6296 	}
6297 
6298 	/*
6299 	 * Once we have msets, we should check that a mset
6300 	 * do not exist before we delete the tmp_pool data.
6301 	 */
6302 	err = delete_tmp_pool(handle);
6303 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6304 		return (err);
6305 
6306 	return (res);
6307 }
6308 
6309 int
6310 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6311 {
6312 	int err;
6313 
6314 	if (tabptr == NULL)
6315 		return (Z_INVAL);
6316 
6317 	if ((err = zonecfg_delete_pset(handle)) != Z_OK)
6318 		return (err);
6319 
6320 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
6321 		return (err);
6322 
6323 	return (Z_OK);
6324 }
6325 
6326 int
6327 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6328 {
6329 	xmlNodePtr cur;
6330 	int err;
6331 	int res = Z_NO_ENTRY;
6332 
6333 	if (tabptr == NULL)
6334 		return (Z_INVAL);
6335 
6336 	if ((err = operation_prep(handle)) != Z_OK)
6337 		return (err);
6338 
6339 	/* this is an optional component */
6340 	tabptr->zone_importance[0] = '\0';
6341 
6342 	cur = handle->zone_dh_cur;
6343 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6344 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
6345 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN,
6346 			    tabptr->zone_ncpu_min,
6347 			    sizeof (tabptr->zone_ncpu_min))) != Z_OK) {
6348 				handle->zone_dh_cur = handle->zone_dh_top;
6349 				return (err);
6350 			}
6351 
6352 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX,
6353 			    tabptr->zone_ncpu_max,
6354 			    sizeof (tabptr->zone_ncpu_max))) != Z_OK) {
6355 				handle->zone_dh_cur = handle->zone_dh_top;
6356 				return (err);
6357 			}
6358 
6359 			res = Z_OK;
6360 
6361 		} else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6362 			if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE,
6363 			    tabptr->zone_importance,
6364 			    sizeof (tabptr->zone_importance))) != Z_OK) {
6365 				handle->zone_dh_cur = handle->zone_dh_top;
6366 				return (err);
6367 			}
6368 		}
6369 	}
6370 
6371 	return (res);
6372 }
6373 
6374 int
6375 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
6376 {
6377 	int err;
6378 
6379 	if ((err = zonecfg_setent(handle)) != Z_OK)
6380 		return (err);
6381 
6382 	err = zonecfg_lookup_pset(handle, tabptr);
6383 
6384 	(void) zonecfg_endent(handle);
6385 
6386 	return (err);
6387 }
6388 
6389 static int
6390 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6391 {
6392 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6393 	int err;
6394 
6395 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
6396 	if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
6397 	    != Z_OK)
6398 		return (err);
6399 
6400 	return (Z_OK);
6401 }
6402 
6403 int
6404 zonecfg_delete_mcap(zone_dochandle_t handle)
6405 {
6406 	int err;
6407 	xmlNodePtr cur = handle->zone_dh_cur;
6408 
6409 	if ((err = operation_prep(handle)) != Z_OK)
6410 		return (err);
6411 
6412 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6413 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6414 			continue;
6415 
6416 		xmlUnlinkNode(cur);
6417 		xmlFreeNode(cur);
6418 		return (Z_OK);
6419 	}
6420 	return (Z_NO_RESOURCE_ID);
6421 }
6422 
6423 int
6424 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6425 {
6426 	int err;
6427 
6428 	if (tabptr == NULL)
6429 		return (Z_INVAL);
6430 
6431 	err = zonecfg_delete_mcap(handle);
6432 	/* it is ok if there is no mcap entry */
6433 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6434 		return (err);
6435 
6436 	if ((err = add_mcap(handle, tabptr)) != Z_OK)
6437 		return (err);
6438 
6439 	return (Z_OK);
6440 }
6441 
6442 int
6443 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6444 {
6445 	xmlNodePtr cur;
6446 	int err;
6447 
6448 	if (tabptr == NULL)
6449 		return (Z_INVAL);
6450 
6451 	if ((err = operation_prep(handle)) != Z_OK)
6452 		return (err);
6453 
6454 	cur = handle->zone_dh_cur;
6455 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6456 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6457 			continue;
6458 		if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
6459 		    tabptr->zone_physmem_cap,
6460 		    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6461 			handle->zone_dh_cur = handle->zone_dh_top;
6462 			return (err);
6463 		}
6464 
6465 		return (Z_OK);
6466 	}
6467 
6468 	return (Z_NO_ENTRY);
6469 }
6470 
6471 static int
6472 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6473 {
6474 	xmlNodePtr cur;
6475 	int err;
6476 
6477 	if (handle == NULL)
6478 		return (Z_INVAL);
6479 
6480 	if ((cur = handle->zone_dh_cur) == NULL)
6481 		return (Z_NO_ENTRY);
6482 
6483 	for (; cur != NULL; cur = cur->next)
6484 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
6485 			break;
6486 	if (cur == NULL) {
6487 		handle->zone_dh_cur = handle->zone_dh_top;
6488 		return (Z_NO_ENTRY);
6489 	}
6490 
6491 	if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
6492 	    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6493 		handle->zone_dh_cur = handle->zone_dh_top;
6494 		return (err);
6495 	}
6496 
6497 	handle->zone_dh_cur = cur->next;
6498 	return (Z_OK);
6499 }
6500 
6501 int
6502 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6503 {
6504 	int err;
6505 
6506 	if ((err = zonecfg_setent(handle)) != Z_OK)
6507 		return (err);
6508 
6509 	err = getmcapent_core(handle, tabptr);
6510 
6511 	(void) zonecfg_endent(handle);
6512 
6513 	return (err);
6514 }
6515 
6516 /*
6517  * Get the full tree of pkg/patch metadata in a set of nested AVL trees.
6518  * pkgs_avl is an AVL tree of pkgs.  Each pkg element contains a
6519  * zpe_patches_avl member which holds an AVL tree of patches for that pkg.
6520  * The patch elements have the same zpe_patches_avl member, each of which can
6521  * hold an AVL tree of patches that are obsoleted by the patch.
6522  *
6523  * The zone xml data contains DTD_ELEM_PACKAGE elements, followed by
6524  * DTD_ELEM_PATCH elements.  The DTD_ELEM_PATCH patch element applies to the
6525  * DTD_ELEM_PACKAGE that precedes it.  The DTD_ELEM_PATCH element may have
6526  * child DTD_ELEM_OBSOLETES nodes associated with it.  The DTD_ELEM_PACKAGE
6527  * really should have had the DTD_ELEM_PATCH elements as children but it
6528  * was not defined that way initially so we are stuck with the DTD definition
6529  * now.  However, we can safely assume the ordering for compatibility.
6530  */
6531 int
6532 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
6533     uu_avl_t *pkgs_avl)
6534 {
6535 	xmlNodePtr cur;
6536 	int res;
6537 	zone_pkg_entry_t *pkg;
6538 	char name[MAXNAMELEN];
6539 	char version[ZONE_PKG_VERSMAX];
6540 
6541 	if (handle == NULL)
6542 		return (Z_INVAL);
6543 
6544 	if ((res = zonecfg_setent(handle)) != Z_OK)
6545 		return (res);
6546 
6547 	if ((cur = handle->zone_dh_cur) == NULL) {
6548 		res = Z_NO_ENTRY;
6549 		goto done;
6550 	}
6551 
6552 	for (; cur != NULL; cur = cur->next) {
6553 		if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) {
6554 			uu_avl_index_t where;
6555 
6556 			if ((res = fetchprop(cur, DTD_ATTR_NAME, name,
6557 			    sizeof (name))) != Z_OK)
6558 				goto done;
6559 
6560 			if ((res = fetchprop(cur, DTD_ATTR_VERSION, version,
6561 			    sizeof (version))) != Z_OK)
6562 				goto done;
6563 
6564 			if ((pkg = (zone_pkg_entry_t *)
6565 			    malloc(sizeof (zone_pkg_entry_t))) == NULL) {
6566 				res = Z_NOMEM;
6567 				goto done;
6568 			}
6569 
6570 			if ((pkg->zpe_name = strdup(name)) == NULL) {
6571 				free(pkg);
6572 				res = Z_NOMEM;
6573 				goto done;
6574 			}
6575 
6576 			if ((pkg->zpe_vers = strdup(version)) == NULL) {
6577 				free(pkg->zpe_name);
6578 				free(pkg);
6579 				res = Z_NOMEM;
6580 				goto done;
6581 			}
6582 
6583 			pkg->zpe_patches_avl = NULL;
6584 
6585 			uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool);
6586 			if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) {
6587 				free(pkg->zpe_name);
6588 				free(pkg->zpe_vers);
6589 				free(pkg);
6590 			} else {
6591 				uu_avl_insert(pkgs_avl, pkg, where);
6592 			}
6593 
6594 		} else if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) {
6595 			zone_pkg_entry_t *patch;
6596 			uu_avl_index_t where;
6597 			char *p;
6598 			char *dashp = NULL;
6599 			xmlNodePtr child;
6600 
6601 			if ((res = fetchprop(cur, DTD_ATTR_ID, name,
6602 			    sizeof (name))) != Z_OK)
6603 				goto done;
6604 
6605 			if ((patch = (zone_pkg_entry_t *)
6606 			    malloc(sizeof (zone_pkg_entry_t))) == NULL) {
6607 				res = Z_NOMEM;
6608 				goto done;
6609 			}
6610 
6611 			if ((p = strchr(name, '-')) != NULL) {
6612 				dashp = p;
6613 				*p++ = '\0';
6614 			} else {
6615 				p = "";
6616 			}
6617 
6618 			if ((patch->zpe_name = strdup(name)) == NULL) {
6619 				free(patch);
6620 				res = Z_NOMEM;
6621 				goto done;
6622 			}
6623 
6624 			if ((patch->zpe_vers = strdup(p)) == NULL) {
6625 				free(patch->zpe_name);
6626 				free(patch);
6627 				res = Z_NOMEM;
6628 				goto done;
6629 			}
6630 
6631 			if (dashp != NULL)
6632 				*dashp = '-';
6633 
6634 			patch->zpe_patches_avl = NULL;
6635 
6636 			if (pkg->zpe_patches_avl == NULL) {
6637 				pkg->zpe_patches_avl = uu_avl_create(pkg_pool,
6638 				    NULL, UU_DEFAULT);
6639 				if (pkg->zpe_patches_avl == NULL) {
6640 					free(patch->zpe_name);
6641 					free(patch->zpe_vers);
6642 					free(patch);
6643 					res = Z_NOMEM;
6644 					goto done;
6645 				}
6646 			}
6647 
6648 			uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool);
6649 			if (uu_avl_find(pkg->zpe_patches_avl, patch, NULL,
6650 			    &where) != NULL) {
6651 				free(patch->zpe_name);
6652 				free(patch->zpe_vers);
6653 				free(patch);
6654 			} else {
6655 				uu_avl_insert(pkg->zpe_patches_avl, patch,
6656 				    where);
6657 			}
6658 
6659 			/* Add any patches this patch obsoletes. */
6660 			for (child = cur->xmlChildrenNode; child != NULL;
6661 			    child = child->next) {
6662 				zone_pkg_entry_t *obs;
6663 
6664 				if (xmlStrcmp(child->name, DTD_ELEM_OBSOLETES)
6665 				    != 0)
6666 					continue;
6667 
6668 				if ((res = fetchprop(child, DTD_ATTR_ID,
6669 				    name, sizeof (name))) != Z_OK)
6670 					goto done;
6671 
6672 				if ((obs = (zone_pkg_entry_t *)malloc(
6673 				    sizeof (zone_pkg_entry_t))) == NULL) {
6674 					res = Z_NOMEM;
6675 					goto done;
6676 				}
6677 
6678 				if ((obs->zpe_name = strdup(name)) == NULL) {
6679 					free(obs);
6680 					res = Z_NOMEM;
6681 					goto done;
6682 				}
6683 				/*
6684 				 * The version doesn't matter for obsoleted
6685 				 * patches.
6686 				 */
6687 				obs->zpe_vers = NULL;
6688 				obs->zpe_patches_avl = NULL;
6689 
6690 				/*
6691 				 * If this is the first obsolete patch, add an
6692 				 * AVL tree to the parent patch element.
6693 				 */
6694 				if (patch->zpe_patches_avl == NULL) {
6695 					patch->zpe_patches_avl =
6696 					    uu_avl_create(pkg_pool, NULL,
6697 					    UU_DEFAULT);
6698 					if (patch->zpe_patches_avl == NULL) {
6699 						free(obs->zpe_name);
6700 						free(obs);
6701 						res = Z_NOMEM;
6702 						goto done;
6703 					}
6704 				}
6705 
6706 				/* Insert obsolete patch into the AVL tree. */
6707 				uu_avl_node_init(obs, &obs->zpe_entry,
6708 				    pkg_pool);
6709 				if (uu_avl_find(patch->zpe_patches_avl, obs,
6710 				    NULL, &where) != NULL) {
6711 					free(obs->zpe_name);
6712 					free(obs);
6713 				} else {
6714 					uu_avl_insert(patch->zpe_patches_avl,
6715 					    obs, where);
6716 				}
6717 			}
6718 		}
6719 	}
6720 
6721 done:
6722 	(void) zonecfg_endent(handle);
6723 	return (res);
6724 }
6725 
6726 int
6727 zonecfg_setdevperment(zone_dochandle_t handle)
6728 {
6729 	return (zonecfg_setent(handle));
6730 }
6731 
6732 int
6733 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr)
6734 {
6735 	xmlNodePtr cur;
6736 	int err;
6737 	char buf[128];
6738 
6739 	tabptr->zone_devperm_acl = NULL;
6740 
6741 	if (handle == NULL)
6742 		return (Z_INVAL);
6743 
6744 	if ((cur = handle->zone_dh_cur) == NULL)
6745 		return (Z_NO_ENTRY);
6746 
6747 	for (; cur != NULL; cur = cur->next)
6748 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM))
6749 			break;
6750 	if (cur == NULL) {
6751 		handle->zone_dh_cur = handle->zone_dh_top;
6752 		return (Z_NO_ENTRY);
6753 	}
6754 
6755 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name,
6756 	    sizeof (tabptr->zone_devperm_name))) != Z_OK) {
6757 		handle->zone_dh_cur = handle->zone_dh_top;
6758 		return (err);
6759 	}
6760 
6761 	if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) {
6762 		handle->zone_dh_cur = handle->zone_dh_top;
6763 		return (err);
6764 	}
6765 	tabptr->zone_devperm_uid = (uid_t)atol(buf);
6766 
6767 	if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) {
6768 		handle->zone_dh_cur = handle->zone_dh_top;
6769 		return (err);
6770 	}
6771 	tabptr->zone_devperm_gid = (gid_t)atol(buf);
6772 
6773 	if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) {
6774 		handle->zone_dh_cur = handle->zone_dh_top;
6775 		return (err);
6776 	}
6777 	tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8);
6778 
6779 	if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL,
6780 	    &(tabptr->zone_devperm_acl))) != Z_OK) {
6781 		handle->zone_dh_cur = handle->zone_dh_top;
6782 		return (err);
6783 	}
6784 
6785 	handle->zone_dh_cur = cur->next;
6786 	return (Z_OK);
6787 }
6788 
6789 int
6790 zonecfg_enddevperment(zone_dochandle_t handle)
6791 {
6792 	return (zonecfg_endent(handle));
6793 }
6794 
6795 /*
6796  * Maintain a space separated list of unique pkg names.  PATH_MAX is used in
6797  * the pkg code as the maximum size for a pkg name.
6798  */
6799 static int
6800 add_pkg_to_str(char **str, char *pkg)
6801 {
6802 	int len, newlen;
6803 	char tstr[PATH_MAX + 3];
6804 	char *tmp;
6805 
6806 	len = strlen(pkg);
6807 	if (*str == NULL) {
6808 		/* space for str + 2 spaces + NULL */
6809 		if ((*str = (char *)malloc(len + 3)) == NULL)
6810 			return (Z_NOMEM);
6811 		(void) snprintf(*str, len + 3, " %s ", pkg);
6812 		return (Z_OK);
6813 	}
6814 
6815 	(void) snprintf(tstr, sizeof (tstr), " %s ", pkg);
6816 	if (strstr(*str, tstr) != NULL)
6817 		return (Z_OK);
6818 
6819 	/* space for str + 1 space + NULL */
6820 	newlen = strlen(*str) + len + 2;
6821 	if ((tmp = (char *)realloc(*str, newlen)) == NULL)
6822 		return (Z_NOMEM);
6823 	*str = tmp;
6824 	(void) strlcat(*str, pkg, newlen);
6825 	(void) strlcat(*str, " ", newlen);
6826 	return (Z_OK);
6827 }
6828 
6829 /*
6830  * Process a list of pkgs from an entry in the contents file, adding each pkg
6831  * name to the list of pkgs.
6832  *
6833  * It is possible for the pkg name to be preceeded by a special character
6834  * which indicates some bookkeeping information for pkging.  Check if the
6835  * first char is not an Alpha char.  If so, skip over it.
6836  */
6837 static int
6838 add_pkg_list(char *lastp, char ***plist, int *pcnt, char **pkg_warn)
6839 {
6840 	char	*p;
6841 	int	pkg_cnt = *pcnt;
6842 	char	**pkgs = *plist;
6843 	int	res = Z_OK;
6844 
6845 	while ((p = strtok_r(NULL, " ", &lastp)) != NULL) {
6846 		char	**tmpp;
6847 		int	i;
6848 
6849 		/* skip over any special pkg bookkeeping char */
6850 		if (!isalpha(*p)) {
6851 			p++;
6852 			if ((res = add_pkg_to_str(pkg_warn, p)) != Z_OK)
6853 				break;
6854 		}
6855 
6856 		/* Check if the pkg is already in the list */
6857 		for (i = 0; i < pkg_cnt; i++) {
6858 			if (strcmp(p, pkgs[i]) == 0)
6859 				break;
6860 		}
6861 
6862 		if (i < pkg_cnt)
6863 			continue;
6864 
6865 		/* The pkg is not in the list; add it. */
6866 		if ((tmpp = (char **)realloc(pkgs,
6867 		    sizeof (char *) * (pkg_cnt + 1))) == NULL) {
6868 			res = Z_NOMEM;
6869 			break;
6870 		}
6871 		pkgs = tmpp;
6872 
6873 		if ((pkgs[pkg_cnt] = strdup(p)) == NULL) {
6874 			res = Z_NOMEM;
6875 			break;
6876 		}
6877 		pkg_cnt++;
6878 	}
6879 
6880 	*plist = pkgs;
6881 	*pcnt = pkg_cnt;
6882 
6883 	return (res);
6884 }
6885 
6886 /*
6887  * Process an entry from the contents file (type "directory").  If the
6888  * directory path is in the list of ipds and is not under a lofs mount within
6889  * the ipd then add the associated list of pkgs to the pkg list.  The input
6890  * parameter "entry" will be broken up by the parser within this function so
6891  * its value will be modified when this function exits.
6892  *
6893  * The entries we are looking for will look something like:
6894  *	/usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf ....
6895  */
6896 static int
6897 get_path_pkgs(char *entry, char **ipds, char **fss, char ***pkgs, int *pkg_cnt,
6898     char **pkg_warn)
6899 {
6900 	char	*f1;
6901 	char	*f2;
6902 	char	*lastp;
6903 	int	i;
6904 	char	*nlp;
6905 
6906 	if ((f1 = strtok_r(entry, " ", &lastp)) == NULL ||
6907 	    (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0)
6908 		return (Z_OK);
6909 
6910 	/* Check if this directory entry is in the list of ipds. */
6911 	for (i = 0; ipds[i] != NULL; i++) {
6912 		char wildcard[MAXPATHLEN];
6913 
6914 		/*
6915 		 * We want to match on the path and any other directory
6916 		 * entries under this path.  When we use FNM_PATHNAME then
6917 		 * that means '/' will not be matched by a wildcard (*) so
6918 		 * we omit FNM_PATHNAME on the call with the wildcard matching.
6919 		 */
6920 		(void) snprintf(wildcard, sizeof (wildcard), "%s/*", ipds[i]);
6921 		if (fnmatch(ipds[i], f1, FNM_PATHNAME) == 0 ||
6922 		    fnmatch(wildcard, f1, 0) == 0) {
6923 			/* It looks like we do want the pkgs for this path. */
6924 			break;
6925 		}
6926 	}
6927 
6928 	/* This entry did not match any of the ipds. */
6929 	if (ipds[i] == NULL)
6930 		return (Z_OK);
6931 
6932 	/*
6933 	 * Check if there is a fs mounted under the ipd.  If so, ignore this
6934 	 * entry.
6935 	 */
6936 	for (i = 0; fss[i] != NULL; i++) {
6937 		char wildcard[MAXPATHLEN];
6938 
6939 		(void) snprintf(wildcard, sizeof (wildcard), "%s/*", fss[i]);
6940 		if (fnmatch(fss[i], f1, FNM_PATHNAME) == 0 ||
6941 		    fnmatch(wildcard, f1, 0) == 0) {
6942 			/* We should ignore this path. */
6943 			break;
6944 		}
6945 	}
6946 
6947 	/* If not null, then we matched an fs mount point so ignore entry. */
6948 	if (fss[i] != NULL)
6949 		return (Z_OK);
6950 
6951 	/*
6952 	 * We do want the pkgs for this entry.  First, skip over the next 4
6953 	 * fields in the entry so that we call add_pkg_list starting with the
6954 	 * pkg names.
6955 	 */
6956 	for (i = 0; i < 4 && strtok_r(NULL, " ", &lastp) != NULL; i++)
6957 		;
6958 	/* If there are < 4 fields this entry is corrupt, just skip it. */
6959 	if (i < 4)
6960 		return (Z_OK);
6961 
6962 	/* strip newline from the line */
6963 	nlp = (lastp + strlen(lastp) - 1);
6964 	if (*nlp == '\n')
6965 		*nlp = '\0';
6966 
6967 	return (add_pkg_list(lastp, pkgs, pkg_cnt, pkg_warn));
6968 }
6969 
6970 /*
6971  * Read an entry from a pkginfo or contents file.  Some of these lines can
6972  * either be arbitrarily long or be continued by a backslash at the end of
6973  * the line.  This function coalesces lines that are longer than the read
6974  * buffer, and lines that are continued, into one buffer which is returned.
6975  * The caller must free this memory.  NULL is returned when we hit EOF or
6976  * if we run out of memory (errno is set to ENOMEM).
6977  */
6978 static char *
6979 read_pkg_data(FILE *fp)
6980 {
6981 	char *start;
6982 	char *inp;
6983 	char *p;
6984 	int char_cnt = 0;
6985 
6986 	errno = 0;
6987 	if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) {
6988 		errno = ENOMEM;
6989 		return (NULL);
6990 	}
6991 
6992 	inp = start;
6993 	while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) {
6994 		int len;
6995 
6996 		len = strlen(inp);
6997 		if (inp[len - 1] == '\n' &&
6998 		    (len == 1 || inp[len - 2] != '\\')) {
6999 			char_cnt = len;
7000 			break;
7001 		}
7002 
7003 		if (inp[len - 2] == '\\')
7004 			char_cnt += len - 2;
7005 		else
7006 			char_cnt += PKGINFO_RD_LEN - 1;
7007 
7008 		if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) {
7009 			errno = ENOMEM;
7010 			break;
7011 		}
7012 
7013 		start = p;
7014 		inp = start + char_cnt;
7015 	}
7016 
7017 	if (errno == ENOMEM || (p == NULL && char_cnt == 0)) {
7018 		free(start);
7019 		start = NULL;
7020 	}
7021 
7022 	return (start);
7023 }
7024 
7025 static void
7026 free_ipd_pkgs(char **pkgs, int cnt)
7027 {
7028 	int i;
7029 
7030 	for (i = 0; i < cnt; i++)
7031 		free(pkgs[i]);
7032 	free(pkgs);
7033 }
7034 
7035 /*
7036  * Get a list of the inherited pkg dirs or fs entries configured for the
7037  * zone.  The type parameter will be either ZONE_IPD or ZONE_FS.
7038  */
7039 static int
7040 get_ipd_fs_list(zone_dochandle_t handle, enum zn_ipd_fs type, char ***list)
7041 {
7042 	int	res;
7043 	struct zone_fstab fstab;
7044 	int	cnt = 0;
7045 	char	**entries = NULL;
7046 	int	i;
7047 	int	(*fp)(zone_dochandle_t, struct zone_fstab *);
7048 
7049 	if (type == ZONE_IPD) {
7050 		fp = zonecfg_getipdent;
7051 		res = zonecfg_setipdent(handle);
7052 	} else {
7053 		fp = zonecfg_getfsent;
7054 		res = zonecfg_setfsent(handle);
7055 	}
7056 
7057 	if (res != Z_OK)
7058 		return (res);
7059 
7060 	while (fp(handle, &fstab) == Z_OK) {
7061 		char	**p;
7062 
7063 		if ((p = (char **)realloc(entries,
7064 		    sizeof (char *) * (cnt + 1))) == NULL) {
7065 			res = Z_NOMEM;
7066 			break;
7067 		}
7068 		entries = p;
7069 
7070 		if ((entries[cnt] = strdup(fstab.zone_fs_dir)) == NULL) {
7071 			res = Z_NOMEM;
7072 			break;
7073 		}
7074 
7075 		cnt++;
7076 	}
7077 
7078 	if (type == ZONE_IPD)
7079 		(void) zonecfg_endipdent(handle);
7080 	else
7081 		(void) zonecfg_endfsent(handle);
7082 
7083 	/* Add a NULL terminating element. */
7084 	if (res == Z_OK) {
7085 		char	**p;
7086 
7087 		if ((p = (char **)realloc(entries,
7088 		    sizeof (char *) * (cnt + 1))) == NULL) {
7089 			res = Z_NOMEM;
7090 		} else {
7091 			entries = p;
7092 			entries[cnt] = NULL;
7093 		}
7094 	}
7095 
7096 	if (res != Z_OK) {
7097 		if (entries != NULL) {
7098 			for (i = 0; i < cnt; i++)
7099 				free(entries[i]);
7100 			free(entries);
7101 		}
7102 		return (res);
7103 	}
7104 
7105 	*list = entries;
7106 	return (Z_OK);
7107 }
7108 
7109 /*
7110  * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the
7111  * list of pkgs that deliver into those dirs.
7112  */
7113 static int
7114 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt)
7115 {
7116 	int	res;
7117 	char	**ipds;
7118 	char	**fss;
7119 	int	pkg_cnt = 0;
7120 	char	**pkgs = NULL;
7121 	int	i;
7122 
7123 	if ((res = get_ipd_fs_list(handle, ZONE_IPD, &ipds)) != Z_OK)
7124 		return (res);
7125 
7126 	if ((res = get_ipd_fs_list(handle, ZONE_FS, &fss)) != Z_OK) {
7127 		for (i = 0; ipds[i] != NULL; i++)
7128 			free(ipds[i]);
7129 		free(ipds);
7130 		return (res);
7131 	}
7132 
7133 	/* We only have to process the contents file if we have ipds. */
7134 	if (ipds != NULL) {
7135 		FILE	*fp;
7136 
7137 		if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) {
7138 			char	*buf;
7139 			char	*pkg_warn = NULL;
7140 
7141 			while ((buf = read_pkg_data(fp)) != NULL) {
7142 				res = get_path_pkgs(buf, ipds, fss, &pkgs,
7143 				    &pkg_cnt, &pkg_warn);
7144 				free(buf);
7145 				if (res != Z_OK)
7146 					break;
7147 			}
7148 
7149 			(void) fclose(fp);
7150 
7151 			if (pkg_warn != NULL) {
7152 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
7153 				    "WARNING: package operation in progress "
7154 				    "on the following packages:\n   %s\n"),
7155 				    pkg_warn);
7156 				free(pkg_warn);
7157 			}
7158 		}
7159 	}
7160 
7161 	for (i = 0; ipds[i] != NULL; i++)
7162 		free(ipds[i]);
7163 	free(ipds);
7164 
7165 	for (i = 0; fss[i] != NULL; i++)
7166 		free(fss[i]);
7167 	free(fss);
7168 
7169 	if (res != Z_OK) {
7170 		free_ipd_pkgs(pkgs, pkg_cnt);
7171 	} else {
7172 		*pkg_list = pkgs;
7173 		*cnt = pkg_cnt;
7174 	}
7175 
7176 	return (res);
7177 }
7178 
7179 /*
7180  * Return true if pkg_name is in the list of pkgs that deliver into an
7181  * inherited pkg directory for the zone.
7182  */
7183 static boolean_t
7184 dir_pkg(char *pkg_name, char **pkg_list, int cnt)
7185 {
7186 	int i;
7187 
7188 	for (i = 0; i < cnt; i++) {
7189 		if (strcmp(pkg_name, pkg_list[i]) == 0)
7190 			return (B_TRUE);
7191 	}
7192 
7193 	return (B_FALSE);
7194 }
7195 
7196 /*
7197  * Keep track of obsoleted patches for this specific patch.  We don't need to
7198  * keep track of the patch version since once a patch is obsoleted, all prior
7199  * versions are also obsolete and there won't be any new versions.
7200  */
7201 static int
7202 add_obs_patch(patch_node_t *patch, char *num, uu_list_pool_t *patches_pool)
7203 {
7204 	obs_patch_node_t *obs;
7205 
7206 	if (patch->obs_patches == NULL) {
7207 		if ((patch->obs_patches = uu_list_create(patches_pool, NULL,
7208 		    0)) == NULL)
7209 			return (Z_NOMEM);
7210 	}
7211 
7212 	if ((obs = (obs_patch_node_t *)malloc(sizeof (obs_patch_node_t)))
7213 	    == NULL)
7214 		return (Z_NOMEM);
7215 
7216 	if ((obs->patch_num = strdup(num)) == NULL) {
7217 		free(obs);
7218 		return (Z_NOMEM);
7219 	}
7220 
7221 	uu_list_node_init(obs, &obs->link, patches_pool);
7222 	(void) uu_list_insert_before(patch->obs_patches, NULL, obs);
7223 
7224 	return (Z_OK);
7225 }
7226 
7227 /*
7228  * Keep track of obsoleted patches.  We don't need to keep track of the patch
7229  * version since once a patch is obsoleted, all prior versions are also
7230  * obsolete and there won't be any new versions.
7231  */
7232 static int
7233 save_obs_patch(char *num, uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches)
7234 {
7235 	patch_node_t	*patch;
7236 	uu_avl_index_t where;
7237 
7238 	if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL)
7239 		return (Z_NOMEM);
7240 
7241 	if ((patch->patch_num = strdup(num)) == NULL) {
7242 		free(patch);
7243 		return (Z_NOMEM);
7244 	}
7245 
7246 	patch->patch_vers = NULL;
7247 	patch->obs_patches = NULL;
7248 
7249 	uu_avl_node_init(patch, &patch->patch_node, patches_pool);
7250 
7251 	if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL) {
7252 		free(patch->patch_num);
7253 		free(patch);
7254 		return (Z_OK);
7255 	}
7256 
7257 	uu_avl_insert(obs_patches, patch, where);
7258 	return (Z_OK);
7259 }
7260 
7261 /*
7262  * Keep a list of patches for a pkg.  If we see a newer version of a patch,
7263  * we only keep track of the newer version.
7264  */
7265 static void
7266 save_patch(patch_node_t *patch, uu_avl_t *patches_avl)
7267 {
7268 	patch_node_t *existing;
7269 	uu_avl_index_t where;
7270 
7271 	/* Check if this is a newer version of a patch we already have. */
7272 	if ((existing = (patch_node_t *)uu_avl_find(patches_avl, patch, NULL,
7273 	    &where)) != NULL) {
7274 		char *endptr;
7275 		ulong_t pvers, evers;
7276 
7277 		pvers = strtoul(patch->patch_vers, &endptr, 10);
7278 		evers = strtoul(existing->patch_vers, &endptr, 10);
7279 
7280 		if (pvers > evers) {
7281 			free(existing->patch_vers);
7282 			existing->patch_vers = patch->patch_vers;
7283 			free(patch->patch_num);
7284 			free(patch);
7285 			return;
7286 		}
7287 	}
7288 
7289 	uu_avl_insert(patches_avl, patch, where);
7290 }
7291 
7292 /*
7293  * Check if a patch is on the list of obsoleted patches.  We don't need to
7294  * check the patch version since once a patch is obsoleted, all prior versions
7295  * are also obsolete and there won't be any new versions.
7296  */
7297 static boolean_t
7298 obsolete_patch(patch_node_t *patch, uu_avl_t *obs_patches)
7299 {
7300 	uu_avl_index_t	where;
7301 
7302 	if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL)
7303 		return (B_TRUE);
7304 
7305 	return (B_FALSE);
7306 }
7307 
7308 /* ARGSUSED */
7309 static int
7310 patch_node_compare(const void *l_arg, const void *r_arg, void *private)
7311 {
7312 	patch_node_t *l = (patch_node_t *)l_arg;
7313 	patch_node_t *r = (patch_node_t *)r_arg;
7314 	char *endptr;
7315 	ulong_t lnum, rnum;
7316 
7317 	lnum = strtoul(l->patch_num, &endptr, 10);
7318 	rnum = strtoul(r->patch_num, &endptr, 10);
7319 
7320 	if (lnum > rnum)
7321 		return (1);
7322 	if (lnum < rnum)
7323 		return (-1);
7324 	return (0);
7325 }
7326 
7327 /*
7328  * Parse the patchinfo string for the patch.
7329  *
7330  * We are parsing entries of the form:
7331  * PATCH_INFO_121454-02=Installed: Wed Dec  7 07:13:51 PST 2005 From: mum \
7332  *	Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \
7333  *	119255-06 Incompatibles:
7334  *
7335  * A backed out patch will have "backed out\n" as the status.  We should
7336  * skip these patches.  We also ignore any entries that seem to be
7337  * corrupted.  Obsolete patches are saved in the obs_patches parameter
7338  * AVL list.
7339  */
7340 static int
7341 parse_info(char *patchinfo, uu_avl_pool_t *patches_pool, uu_avl_t *patches_avl,
7342     uu_avl_t *obs_patches, uu_list_pool_t *list_pool)
7343 {
7344 	char		*p;
7345 	char		*lastp;
7346 	char		*ep;
7347 	char		*pvers;
7348 	boolean_t	add_info = B_FALSE;
7349 	patch_node_t	*patch;
7350 
7351 	if (strlen(patchinfo) < (sizeof (PATCHINFO) - 1))
7352 		return (Z_OK);
7353 
7354 	/* Skip over "PATCH_INFO_" to get the patch id. */
7355 	p = patchinfo + sizeof (PATCHINFO) - 1;
7356 	if ((ep = strchr(p, '=')) == NULL)
7357 		return (Z_OK);
7358 
7359 	*ep++ = '\0';
7360 
7361 	/* Ignore all but installed patches. */
7362 	if (strncmp(ep, "Installed:", 10) != 0)
7363 		return (Z_OK);
7364 
7365 	/* remove newline */
7366 	lastp = (ep + strlen(ep) - 1);
7367 	if (*lastp == '\n')
7368 		*lastp = '\0';
7369 
7370 	if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL)
7371 		return (Z_NOMEM);
7372 
7373 	if ((pvers = strchr(p, '-')) != NULL)
7374 		*pvers++ = '\0';
7375 	else
7376 		pvers = "";
7377 
7378 	if ((patch->patch_num = strdup(p)) == NULL) {
7379 		free(patch);
7380 		return (Z_NOMEM);
7381 	}
7382 	if ((patch->patch_vers = strdup(pvers)) == NULL) {
7383 		free(patch->patch_num);
7384 		free(patch);
7385 		return (Z_NOMEM);
7386 	}
7387 	patch->obs_patches = NULL;
7388 
7389 	uu_avl_node_init(patch, &patch->patch_node, patches_pool);
7390 	save_patch(patch, patches_avl);
7391 
7392 	/*
7393 	 * Start with the first token.  This will probably be "Installed:".
7394 	 * If we can't tokenize this entry, just return.
7395 	 */
7396 	if ((p = strtok_r(ep, " ", &lastp)) == NULL)
7397 		return (Z_OK);
7398 
7399 	do {
7400 		if (strcmp(p, "Installed:") == 0 ||
7401 		    strcmp(p, "Requires:") == 0 ||
7402 		    strcmp(p, "From:") == 0 ||
7403 		    strcmp(p, "Incompatibles:") == 0) {
7404 			add_info = B_FALSE;
7405 			continue;
7406 		} else if (strcmp(p, "Obsoletes:") == 0) {
7407 			add_info = B_TRUE;
7408 			continue;
7409 		}
7410 
7411 		if (!add_info)
7412 			continue;
7413 
7414 		if ((pvers = strchr(p, '-')) != NULL)
7415 			*pvers = '\0';
7416 
7417 		/*
7418 		 * We save all of the obsolete patches in one big list in the
7419 		 * obs_patches AVL tree so that we know not to output those as
7420 		 * part of the sw dependencies.  However, we also need to save
7421 		 * the obsolete patch information for this sepcific patch so
7422 		 * so that we can do the cross manifest patch checking
7423 		 * correctly.
7424 		 */
7425 		if (save_obs_patch(p, patches_pool, obs_patches) != Z_OK)
7426 			return (Z_NOMEM);
7427 		if (add_obs_patch(patch, p, list_pool) != Z_OK)
7428 			return (Z_NOMEM);
7429 	} while ((p = strtok_r(NULL, " ", &lastp)) != NULL);
7430 
7431 	return (Z_OK);
7432 }
7433 
7434 /*
7435  * AVL walker callback used to add patch to XML manifest.
7436  *
7437  * PATH_MAX is used in the pkg/patch code as the maximum size for the patch
7438  * number/version string.
7439  */
7440 static int
7441 add_patch(void *e, void *p)
7442 {
7443 	xmlNodePtr	node;
7444 	xmlNodePtr	cur;
7445 	char		id[PATH_MAX];
7446 	patch_node_t	*patch;
7447 	patch_parms_t	*args;
7448 
7449 	patch = e;
7450 	args = p;
7451 
7452 	/* skip this patch if it has been obsoleted */
7453 	if (obsolete_patch(patch, args->obs_patches_avl))
7454 		return (UU_WALK_NEXT);
7455 
7456 	if (patch->patch_vers[0] == '\0')
7457 		(void) snprintf(id, sizeof (id), "%s", patch->patch_num);
7458 	else
7459 		(void) snprintf(id, sizeof (id), "%s-%s", patch->patch_num,
7460 		    patch->patch_vers);
7461 
7462 	if ((args->res = operation_prep(args->handle)) != Z_OK)
7463 		return (UU_WALK_DONE);
7464 
7465 	cur = args->handle->zone_dh_cur;
7466 	node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL);
7467 	if ((args->res = newprop(node, DTD_ATTR_ID, id)) != Z_OK)
7468 		return (UU_WALK_DONE);
7469 
7470 	if (patch->obs_patches != NULL) {
7471 		obs_patch_node_t *op;
7472 		xmlNodePtr	node2;
7473 
7474 		for (op = uu_list_first(patch->obs_patches); op != NULL;
7475 		    op = uu_list_next(patch->obs_patches, op)) {
7476 			(void) snprintf(id, sizeof (id), "%s", op->patch_num);
7477 			node2 = xmlNewTextChild(node, NULL, DTD_ELEM_OBSOLETES,
7478 			    NULL);
7479 			if ((args->res = newprop(node2, DTD_ATTR_ID, id))
7480 			    != Z_OK)
7481 				return (UU_WALK_DONE);
7482 		}
7483 	}
7484 
7485 	return (UU_WALK_NEXT);
7486 }
7487 
7488 static void
7489 patch_avl_delete(uu_avl_t *patches_avl)
7490 {
7491 	if (patches_avl != NULL) {
7492 		patch_node_t *p;
7493 		void *cookie = NULL;
7494 
7495 		while ((p = (patch_node_t *)uu_avl_teardown(patches_avl,
7496 		    &cookie)) != NULL) {
7497 			free(p->patch_num);
7498 			free(p->patch_vers);
7499 
7500 			if (p->obs_patches != NULL) {
7501 				obs_patch_node_t *op;
7502 				void *cookie2 = NULL;
7503 
7504 				while ((op = uu_list_teardown(p->obs_patches,
7505 				    &cookie2)) != NULL) {
7506 					free(op->patch_num);
7507 					free(op);
7508 				}
7509 				uu_list_destroy(p->obs_patches);
7510 			}
7511 
7512 			free(p);
7513 		}
7514 
7515 		uu_avl_destroy(patches_avl);
7516 	}
7517 }
7518 
7519 /*
7520  * Add the unique, highest version patches that are associated with this pkg
7521  * to the sw inventory on the handle.
7522  */
7523 static int
7524 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop,
7525     uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches,
7526     uu_list_pool_t *list_pool)
7527 {
7528 	int		i;
7529 	int		res;
7530 	uu_avl_t 	*patches_avl;
7531 	patch_parms_t	args;
7532 
7533 	if ((patches_avl = uu_avl_create(patches_pool, NULL, UU_DEFAULT))
7534 	    == NULL)
7535 		return (Z_NOMEM);
7536 
7537 	for (i = 0; i < infop->zpi_patch_cnt; i++) {
7538 		if ((res = parse_info(infop->zpi_patchinfo[i], patches_pool,
7539 		    patches_avl, obs_patches, list_pool)) != Z_OK) {
7540 			patch_avl_delete(patches_avl);
7541 			return (res);
7542 		}
7543 	}
7544 
7545 	args.obs_patches_avl = obs_patches;
7546 	args.handle = handle;
7547 	args.res = Z_OK;
7548 
7549 	(void) uu_avl_walk(patches_avl, add_patch, &args, 0);
7550 
7551 	patch_avl_delete(patches_avl);
7552 	return (args.res);
7553 }
7554 
7555 /*
7556  * Keep track of the pkgs we have already processed so that we can quickly
7557  * skip those pkgs while recursively doing dependents.
7558  */
7559 static boolean_t
7560 pkg_in_manifest(uu_avl_t *saw_pkgs, char *pname, uu_avl_pool_t *pkgs_pool)
7561 {
7562 	uu_avl_index_t where;
7563 
7564 	if (uu_avl_find(saw_pkgs, pname, NULL, &where) == NULL) {
7565 		zone_pkg_entry_t *pkg;
7566 
7567 		/*
7568 		 * We need to add it.  If we don't have memory we just skip
7569 		 * this pkg since this routine improves performance but the
7570 		 * algorithm is still correct without it.
7571 		 */
7572 		if ((pkg = (zone_pkg_entry_t *)
7573 		    malloc(sizeof (zone_pkg_entry_t))) == NULL)
7574 			return (B_FALSE);
7575 
7576 		if ((pkg->zpe_name = strdup(pname)) == NULL) {
7577 			free(pkg);
7578 			return (B_FALSE);
7579 		}
7580 
7581 		pkg->zpe_vers = NULL;
7582 		pkg->zpe_patches_avl = NULL;
7583 
7584 		/* Insert pkg into the AVL tree. */
7585 		uu_avl_node_init(pkg, &pkg->zpe_entry, pkgs_pool);
7586 		uu_avl_insert(saw_pkgs, pkg, where);
7587 		return (B_FALSE);
7588 	}
7589 
7590 	return (B_TRUE);
7591 }
7592 
7593 /*
7594  * Add the pkg to the sw inventory on the handle.
7595  */
7596 static int
7597 add_pkg(zone_dochandle_t handle, char *name, char *version)
7598 {
7599 	xmlNodePtr newnode;
7600 	xmlNodePtr cur;
7601 	int err;
7602 
7603 	if ((err = operation_prep(handle)) != Z_OK)
7604 		return (err);
7605 
7606 	cur = handle->zone_dh_cur;
7607 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL);
7608 	if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK)
7609 		return (err);
7610 	if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK)
7611 		return (err);
7612 	return (Z_OK);
7613 }
7614 
7615 static void
7616 free_pkginfo(struct zone_pkginfo *infop)
7617 {
7618 	free(infop->zpi_version);
7619 	if (infop->zpi_patch_cnt > 0) {
7620 		int i;
7621 
7622 		for (i = 0; i < infop->zpi_patch_cnt; i++)
7623 			free(infop->zpi_patchinfo[i]);
7624 		free(infop->zpi_patchinfo);
7625 	}
7626 }
7627 
7628 /*
7629  * Read the pkginfo file and populate the structure with the data we need
7630  * from this pkg for a sw inventory.
7631  */
7632 static int
7633 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop)
7634 {
7635 	FILE	*fp;
7636 	char	*buf;
7637 	int	err = 0;
7638 
7639 	infop->zpi_all_zones = B_FALSE;
7640 	infop->zpi_this_zone = B_FALSE;
7641 	infop->zpi_version = NULL;
7642 	infop->zpi_patch_cnt = 0;
7643 	infop->zpi_patchinfo = NULL;
7644 
7645 	if ((fp = fopen(pkginfo, "r")) == NULL)
7646 		return (errno);
7647 
7648 	while ((buf = read_pkg_data(fp)) != NULL) {
7649 		if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) {
7650 			int len;
7651 
7652 			if ((infop->zpi_version =
7653 			    strdup(buf + sizeof (VERSION) - 1)) == NULL) {
7654 				err = ENOMEM;
7655 				break;
7656 			}
7657 
7658 			/* remove trailing newline */
7659 			len = strlen(infop->zpi_version);
7660 			*(infop->zpi_version + len - 1) = 0;
7661 
7662 		} else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) {
7663 			infop->zpi_all_zones = B_TRUE;
7664 
7665 		} else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) {
7666 			infop->zpi_this_zone = B_TRUE;
7667 
7668 		} else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1)
7669 		    == 0) {
7670 			char **p;
7671 
7672 			if ((p = (char **)realloc(infop->zpi_patchinfo,
7673 			    sizeof (char *) * (infop->zpi_patch_cnt + 1)))
7674 			    == NULL) {
7675 				err = ENOMEM;
7676 				break;
7677 			}
7678 			infop->zpi_patchinfo = p;
7679 
7680 			if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] =
7681 			    strdup(buf)) == NULL) {
7682 				err = ENOMEM;
7683 				break;
7684 			}
7685 			infop->zpi_patch_cnt++;
7686 		}
7687 
7688 		free(buf);
7689 	}
7690 
7691 	free(buf);
7692 
7693 	if (errno == ENOMEM) {
7694 		err = ENOMEM;
7695 		/* Clean up anything we did manage to allocate. */
7696 		free_pkginfo(infop);
7697 	}
7698 
7699 	(void) fclose(fp);
7700 
7701 	return (err);
7702 }
7703 
7704 /*
7705  * Add any dependent pkgs to the list.  The pkg depend file lists pkg
7706  * dependencies, one per line with an entry that looks like:
7707  *	P SUNWcar       Core Architecture, (Root)
7708  * See the depend(4) man page.
7709  */
7710 static int
7711 add_dependents(zone_dochandle_t handle, char *pname,
7712     uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches,
7713     uu_list_pool_t *list_pool, uu_avl_t *saw_pkgs, uu_avl_pool_t *pkgs_pool)
7714 {
7715 	int		res = Z_OK;
7716 	FILE		*fp;
7717 	char		depend[MAXPATHLEN];
7718 	char		*buf;
7719 	struct stat	sbuf;
7720 
7721 	(void) snprintf(depend, sizeof (depend), "%s/%s/install/depend",
7722 	    PKG_PATH, pname);
7723 
7724 	if (stat(depend, &sbuf) == -1 || !S_ISREG(sbuf.st_mode))
7725 		return (Z_OK);
7726 
7727 	if ((fp = fopen(depend, "r")) == NULL)
7728 		return (Z_OK);
7729 
7730 	while ((buf = read_pkg_data(fp)) != NULL) {
7731 		char *deppkg;
7732 		char *delims = " \t";
7733 		char pkginfo[MAXPATHLEN];
7734 		struct zone_pkginfo info;
7735 
7736 		if (*buf != 'P') {
7737 			free(buf);
7738 			continue;
7739 		}
7740 
7741 		/* Skip past the leading 'P '. */
7742 		if ((deppkg = strtok(buf + 2, delims)) == NULL) {
7743 			free(buf);
7744 			continue;
7745 		}
7746 
7747 		/* If the pkg is already in the manifest don't add it again. */
7748 		if (pkg_in_manifest(saw_pkgs, deppkg, pkgs_pool)) {
7749 			free(buf);
7750 			continue;
7751 		}
7752 
7753 		(void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo",
7754 		    PKG_PATH, deppkg);
7755 
7756 		if (stat(pkginfo, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) {
7757 			free(buf);
7758 			continue;
7759 		}
7760 
7761 		if (get_pkginfo(pkginfo, &info) != 0) {
7762 			res = Z_NOMEM;
7763 			free(buf);
7764 			break;
7765 		}
7766 
7767 		if ((res = add_dependents(handle, deppkg, patches_pool,
7768 		    obs_patches, list_pool, saw_pkgs, pkgs_pool)) == Z_OK &&
7769 		    (res = add_pkg(handle, deppkg, info.zpi_version)) == Z_OK) {
7770 			if (info.zpi_patch_cnt > 0)
7771 				res = add_patches(handle, &info, patches_pool,
7772 				    obs_patches, list_pool);
7773 		}
7774 
7775 		free(buf);
7776 		free_pkginfo(&info);
7777 
7778 		if (res != Z_OK)
7779 			break;
7780 	}
7781 
7782 	(void) fclose(fp);
7783 	return (res);
7784 }
7785 
7786 /* ARGSUSED */
7787 static int
7788 pkg_entry_compare(const void *l_arg, const void *r_arg, void *private)
7789 {
7790 	zone_pkg_entry_t *pkg = (zone_pkg_entry_t *)l_arg;
7791 	char *name = (char *)r_arg;
7792 
7793 	return (strcmp(pkg->zpe_name, name));
7794 }
7795 
7796 static void
7797 pkg_avl_delete(uu_avl_t *pavl)
7798 {
7799 	if (pavl != NULL) {
7800 		zone_pkg_entry_t *p;
7801 		void *cookie = NULL;
7802 
7803 		while ((p = uu_avl_teardown(pavl, &cookie)) != NULL) {
7804 			free(p->zpe_name);
7805 			free(p);
7806 		}
7807 
7808 		uu_avl_destroy(pavl);
7809 	}
7810 }
7811 
7812 /*
7813  * Take a software inventory of the global zone.  We need to get the set of
7814  * packages and patches that are on the global zone that the specified
7815  * non-global zone depends on.  The packages we need in the inventory are:
7816  *
7817  * - skip the package if SUNW_PKG_THISZONE is 'true'
7818  * otherwise,
7819  * - add the package if
7820  * a) SUNW_PKG_ALLZONES is 'true',
7821  * or
7822  * b) any file delivered by the package is in a file system that is inherited
7823  * from the global zone.
7824  * If the zone does not inherit any file systems (whole root)
7825  * then (b) will be skipped.
7826  *
7827  * For each of the packages that is being added to the inventory, we will also
7828  * add its dependent packages to the inventory.
7829  *
7830  * For each of the packages that is being added to the inventory, we will also
7831  * add all of the associated, unique patches to the inventory.
7832  *
7833  * See the comment for zonecfg_getpkgdata() for compatability restrictions on
7834  * how we must save the XML representation of the software inventory.
7835  */
7836 static int
7837 zonecfg_sw_inventory(zone_dochandle_t handle)
7838 {
7839 	char		pkginfo[MAXPATHLEN];
7840 	int		res;
7841 	struct dirent	*dp;
7842 	DIR		*dirp;
7843 	struct stat	buf;
7844 	struct zone_pkginfo	info;
7845 	int		pkg_cnt = 0;
7846 	char		**pkgs = NULL;
7847 	uu_avl_pool_t 	*pkgs_pool = NULL;
7848 	uu_avl_pool_t 	*patches_pool = NULL;
7849 	uu_list_pool_t 	*list_pool = NULL;
7850 	uu_avl_t	*saw_pkgs = NULL;
7851 	uu_avl_t 	*obs_patches = NULL;
7852 
7853 	if ((pkgs_pool = uu_avl_pool_create("pkgs_pool",
7854 	    sizeof (zone_pkg_entry_t), offsetof(zone_pkg_entry_t, zpe_entry),
7855 	    pkg_entry_compare, UU_DEFAULT)) == NULL) {
7856 		res = Z_NOMEM;
7857 		goto done;
7858 	}
7859 
7860 	if ((saw_pkgs = uu_avl_create(pkgs_pool, NULL, UU_DEFAULT)) == NULL) {
7861 		res = Z_NOMEM;
7862 		goto done;
7863 	}
7864 
7865 	if ((patches_pool = uu_avl_pool_create("patches_pool",
7866 	    sizeof (patch_node_t), offsetof(patch_node_t, patch_node),
7867 	    patch_node_compare, UU_DEFAULT)) == NULL) {
7868 		res = Z_NOMEM;
7869 		goto done;
7870 	}
7871 
7872 	if ((list_pool = uu_list_pool_create("list_pool",
7873 	    sizeof (obs_patch_node_t), offsetof(obs_patch_node_t, link), NULL,
7874 	    UU_DEFAULT)) == NULL) {
7875 		res = Z_NOMEM;
7876 		goto done;
7877 	}
7878 
7879 	/*
7880 	 * The obs_patches AVL tree saves all of the obsolete patches so
7881 	 * that we know not to output those as part of the sw dependencies.
7882 	 */
7883 	if ((obs_patches = uu_avl_create(patches_pool, NULL, UU_DEFAULT))
7884 	    == NULL) {
7885 		res = Z_NOMEM;
7886 		goto done;
7887 	}
7888 
7889 	if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) {
7890 		res = Z_NOMEM;
7891 		goto done;
7892 	}
7893 
7894 	if ((dirp = opendir(PKG_PATH)) == NULL) {
7895 		res = Z_NOMEM;
7896 		goto done;
7897 	}
7898 
7899 	while ((dp = readdir(dirp)) != (struct dirent *)0) {
7900 		if (strcmp(dp->d_name, ".") == 0 ||
7901 		    strcmp(dp->d_name, "..") == 0)
7902 			continue;
7903 
7904 		(void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo",
7905 		    PKG_PATH, dp->d_name);
7906 
7907 		if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode))
7908 			continue;
7909 
7910 		if (get_pkginfo(pkginfo, &info) != 0) {
7911 			res = Z_NOMEM;
7912 			break;
7913 		}
7914 
7915 		if (!info.zpi_this_zone &&
7916 		    (info.zpi_all_zones ||
7917 		    dir_pkg(dp->d_name, pkgs, pkg_cnt)) &&
7918 		    !pkg_in_manifest(saw_pkgs, dp->d_name, pkgs_pool)) {
7919 			/*
7920 			 * Add dependents first so any patches will get
7921 			 * associated with the right pkg in the xml file.
7922 			 */
7923 			if ((res = add_dependents(handle, dp->d_name,
7924 			    patches_pool, obs_patches, list_pool, saw_pkgs,
7925 			    pkgs_pool)) == Z_OK &&
7926 			    (res = add_pkg(handle, dp->d_name,
7927 			    info.zpi_version)) == Z_OK) {
7928 				if (info.zpi_patch_cnt > 0)
7929 					res = add_patches(handle, &info,
7930 					    patches_pool, obs_patches,
7931 					    list_pool);
7932 			}
7933 		}
7934 
7935 		free_pkginfo(&info);
7936 
7937 		if (res != Z_OK)
7938 			break;
7939 	}
7940 
7941 	(void) closedir(dirp);
7942 
7943 done:
7944 	pkg_avl_delete(saw_pkgs);
7945 	patch_avl_delete(obs_patches);
7946 	if (pkgs_pool != NULL)
7947 		uu_avl_pool_destroy(pkgs_pool);
7948 	if (patches_pool != NULL)
7949 		uu_avl_pool_destroy(patches_pool);
7950 	if (list_pool != NULL)
7951 		uu_list_pool_destroy(list_pool);
7952 	free_ipd_pkgs(pkgs, pkg_cnt);
7953 
7954 	if (res == Z_OK)
7955 		handle->zone_dh_sw_inv = B_TRUE;
7956 
7957 	return (res);
7958 }
7959 
7960 /*
7961  * zonecfg_devwalk call-back function used during detach to generate the
7962  * dev info in the manifest.
7963  */
7964 static int
7965 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
7966     const char *acl, void *hdl)
7967 {
7968 	zone_dochandle_t handle = (zone_dochandle_t)hdl;
7969 	xmlNodePtr newnode;
7970 	xmlNodePtr cur;
7971 	int err;
7972 	char buf[128];
7973 
7974 	if ((err = operation_prep(handle)) != Z_OK)
7975 		return (err);
7976 
7977 	cur = handle->zone_dh_cur;
7978 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
7979 	if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
7980 		return (err);
7981 	(void) snprintf(buf, sizeof (buf), "%lu", uid);
7982 	if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
7983 		return (err);
7984 	(void) snprintf(buf, sizeof (buf), "%lu", gid);
7985 	if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
7986 		return (err);
7987 	(void) snprintf(buf, sizeof (buf), "%o", mode);
7988 	if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
7989 		return (err);
7990 	if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
7991 		return (err);
7992 	return (Z_OK);
7993 }
7994 
7995 /*
7996  * Get the information required to support detaching a zone.  This is
7997  * called on the source system when detaching (the detaching parameter should
7998  * be set to true) and on the destination system before attaching (the
7999  * detaching parameter should be false).
8000  *
8001  * For native Solaris zones, the detach/attach process involves validating
8002  * that the software on the global zone can support the zone when we attach.
8003  * To do this we take a software inventory of the global zone.  We also
8004  * have to keep track of the device configuration so that we can properly
8005  * recreate it on the destination.
8006  */
8007 int
8008 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching)
8009 {
8010 	int		res;
8011 
8012 	if ((res = zonecfg_sw_inventory(handle)) != Z_OK)
8013 		return (res);
8014 
8015 	if (detaching)
8016 		res = zonecfg_devwalk(handle, get_detach_dev_entry, handle);
8017 
8018 	return (res);
8019 }
8020