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