xref: /titanic_52/usr/src/lib/libzonecfg/common/libzonecfg.c (revision bced1f3360e021f30656c586a265fdfd0cab790f)
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 	/*
2235 	 * Do not add this property when it is not set, for backwards
2236 	 * compatibility and because it is optional.
2237 	 */
2238 	if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
2239 	    ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
2240 	    tabptr->zone_nwif_defrouter)) != Z_OK))
2241 		return (err);
2242 	return (Z_OK);
2243 }
2244 
2245 int
2246 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2247 {
2248 	int err;
2249 
2250 	if (tabptr == NULL)
2251 		return (Z_INVAL);
2252 
2253 	if ((err = operation_prep(handle)) != Z_OK)
2254 		return (err);
2255 
2256 	if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2257 		return (err);
2258 
2259 	return (Z_OK);
2260 }
2261 
2262 static int
2263 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2264 {
2265 	xmlNodePtr cur = handle->zone_dh_cur;
2266 	boolean_t addr_match, phys_match;
2267 
2268 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2269 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2270 			continue;
2271 
2272 		addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2273 		    tabptr->zone_nwif_address);
2274 		phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2275 		    tabptr->zone_nwif_physical);
2276 
2277 		if (addr_match && phys_match) {
2278 			xmlUnlinkNode(cur);
2279 			xmlFreeNode(cur);
2280 			return (Z_OK);
2281 		}
2282 	}
2283 	return (Z_NO_RESOURCE_ID);
2284 }
2285 
2286 int
2287 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2288 {
2289 	int err;
2290 
2291 	if (tabptr == NULL)
2292 		return (Z_INVAL);
2293 
2294 	if ((err = operation_prep(handle)) != Z_OK)
2295 		return (err);
2296 
2297 	if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
2298 		return (err);
2299 
2300 	return (Z_OK);
2301 }
2302 
2303 int
2304 zonecfg_modify_nwif(
2305 	zone_dochandle_t handle,
2306 	struct zone_nwiftab *oldtabptr,
2307 	struct zone_nwiftab *newtabptr)
2308 {
2309 	int err;
2310 
2311 	if (oldtabptr == NULL || newtabptr == NULL)
2312 		return (Z_INVAL);
2313 
2314 	if ((err = operation_prep(handle)) != Z_OK)
2315 		return (err);
2316 
2317 	if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2318 		return (err);
2319 
2320 	if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2321 		return (err);
2322 
2323 	return (Z_OK);
2324 }
2325 
2326 int
2327 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2328 {
2329 	xmlNodePtr cur, firstmatch;
2330 	int err;
2331 	char match[MAXPATHLEN];
2332 
2333 	if (tabptr == NULL)
2334 		return (Z_INVAL);
2335 
2336 	if ((err = operation_prep(handle)) != Z_OK)
2337 		return (err);
2338 
2339 	cur = handle->zone_dh_cur;
2340 	firstmatch = NULL;
2341 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2342 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2343 			continue;
2344 		if (strlen(tabptr->zone_dev_match) == 0)
2345 			continue;
2346 
2347 		if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2348 		    sizeof (match)) == Z_OK)) {
2349 			if (strcmp(tabptr->zone_dev_match,
2350 			    match) == 0) {
2351 				if (firstmatch == NULL)
2352 					firstmatch = cur;
2353 				else if (firstmatch != cur)
2354 					return (Z_INSUFFICIENT_SPEC);
2355 			} else {
2356 				/*
2357 				 * If another property matched but this
2358 				 * one doesn't then reset firstmatch.
2359 				 */
2360 				if (firstmatch == cur)
2361 					firstmatch = NULL;
2362 			}
2363 		}
2364 	}
2365 	if (firstmatch == NULL)
2366 		return (Z_NO_RESOURCE_ID);
2367 
2368 	cur = firstmatch;
2369 
2370 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2371 	    sizeof (tabptr->zone_dev_match))) != Z_OK)
2372 		return (err);
2373 
2374 	return (Z_OK);
2375 }
2376 
2377 static int
2378 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2379 {
2380 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2381 	int err;
2382 
2383 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2384 
2385 	if ((err = newprop(newnode, DTD_ATTR_MATCH,
2386 	    tabptr->zone_dev_match)) != Z_OK)
2387 		return (err);
2388 
2389 	return (Z_OK);
2390 }
2391 
2392 int
2393 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2394 {
2395 	int err;
2396 
2397 	if (tabptr == NULL)
2398 		return (Z_INVAL);
2399 
2400 	if ((err = operation_prep(handle)) != Z_OK)
2401 		return (err);
2402 
2403 	if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2404 		return (err);
2405 
2406 	return (Z_OK);
2407 }
2408 
2409 static int
2410 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2411 {
2412 	xmlNodePtr cur = handle->zone_dh_cur;
2413 	int match_match;
2414 
2415 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2416 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2417 			continue;
2418 
2419 		match_match = match_prop(cur, DTD_ATTR_MATCH,
2420 		    tabptr->zone_dev_match);
2421 
2422 		if (match_match) {
2423 			xmlUnlinkNode(cur);
2424 			xmlFreeNode(cur);
2425 			return (Z_OK);
2426 		}
2427 	}
2428 	return (Z_NO_RESOURCE_ID);
2429 }
2430 
2431 int
2432 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2433 {
2434 	int err;
2435 
2436 	if (tabptr == NULL)
2437 		return (Z_INVAL);
2438 
2439 	if ((err = operation_prep(handle)) != Z_OK)
2440 		return (err);
2441 
2442 	if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
2443 		return (err);
2444 
2445 	return (Z_OK);
2446 }
2447 
2448 int
2449 zonecfg_modify_dev(
2450 	zone_dochandle_t handle,
2451 	struct zone_devtab *oldtabptr,
2452 	struct zone_devtab *newtabptr)
2453 {
2454 	int err;
2455 
2456 	if (oldtabptr == NULL || newtabptr == NULL)
2457 		return (Z_INVAL);
2458 
2459 	if ((err = operation_prep(handle)) != Z_OK)
2460 		return (err);
2461 
2462 	if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
2463 		return (err);
2464 
2465 	if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
2466 		return (err);
2467 
2468 	return (Z_OK);
2469 }
2470 
2471 /* Lock to serialize all zonecfg_devwalks */
2472 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
2473 /*
2474  * Global variables used to pass data from zonecfg_devwalk to the nftw
2475  * call-back (zonecfg_devwalk_cb).  g_devwalk_data is really the void*
2476  * parameter and g_devwalk_cb is really the *cb parameter from zonecfg_devwalk.
2477  */
2478 static void *g_devwalk_data;
2479 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *,
2480     void *);
2481 static size_t g_devwalk_skip_prefix;
2482 
2483 /*
2484  * This is the nftw call-back function used by zonecfg_devwalk.  It is
2485  * responsible for calling the actual call-back that is passed in to
2486  * zonecfg_devwalk as the *cb argument.
2487  */
2488 /* ARGSUSED2 */
2489 static int
2490 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f,
2491     struct FTW *ftw)
2492 {
2493 	acl_t *acl;
2494 	char *acl_txt = NULL;
2495 
2496 	/* skip all but character and block devices */
2497 	if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
2498 		return (0);
2499 
2500 	if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) &&
2501 	    acl != NULL) {
2502 		acl_txt = acl_totext(acl, ACL_NORESOLVE);
2503 		acl_free(acl);
2504 	}
2505 
2506 	if (strlen(path) <= g_devwalk_skip_prefix)
2507 		return (0);
2508 
2509 	g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid,
2510 	    st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "",
2511 	    g_devwalk_data);
2512 	free(acl_txt);
2513 	return (0);
2514 }
2515 
2516 /*
2517  * Walk the dev tree for the zone specified by hdl and call the call-back (cb)
2518  * function for each entry in the tree.  The call-back will be passed the
2519  * name, uid, gid, mode, acl string and the void *data input parameter
2520  * for each dev entry.
2521  *
2522  * Data is passed to the zonecfg_devwalk_cb through the global variables
2523  * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix.  The
2524  * zonecfg_devwalk_cb function will actually call *cb.
2525  */
2526 int
2527 zonecfg_devwalk(zone_dochandle_t hdl,
2528     int (*cb)(const char *, uid_t, gid_t, mode_t, const char *, void *),
2529     void *data)
2530 {
2531 	char path[MAXPATHLEN];
2532 	int ret;
2533 
2534 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
2535 		return (ret);
2536 
2537 	if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path))
2538 		return (Z_TOO_BIG);
2539 	g_devwalk_skip_prefix = strlen(path) + 1;
2540 
2541 	/*
2542 	 * We have to serialize all zonecfg_devwalks in the same process
2543 	 * (which should be fine), since nftw() is so badly designed.
2544 	 */
2545 	(void) pthread_mutex_lock(&zonecfg_devwalk_lock);
2546 
2547 	g_devwalk_data = data;
2548 	g_devwalk_cb = cb;
2549 	(void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS);
2550 
2551 	(void) pthread_mutex_unlock(&zonecfg_devwalk_lock);
2552 	return (Z_OK);
2553 }
2554 
2555 /*
2556  * Update the owner, group, mode and acl on the specified dev (inpath) for
2557  * the zone (hdl).  This function can be used to fix up the dev tree after
2558  * attaching a migrated zone.
2559  */
2560 int
2561 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner,
2562     gid_t group, mode_t mode, const char *acltxt)
2563 {
2564 	int ret;
2565 	char path[MAXPATHLEN];
2566 	struct stat st;
2567 	acl_t *aclp;
2568 
2569 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
2570 		return (ret);
2571 
2572 	if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path))
2573 		return (Z_TOO_BIG);
2574 	if (strlcat(path, inpath, sizeof (path)) >= sizeof (path))
2575 		return (Z_TOO_BIG);
2576 
2577 	if (stat(path, &st) == -1)
2578 		return (Z_INVAL);
2579 
2580 	/* make sure we're only touching device nodes */
2581 	if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
2582 		return (Z_INVAL);
2583 
2584 	if (chown(path, owner, group) == -1)
2585 		return (Z_SYSTEM);
2586 
2587 	if (chmod(path, mode) == -1)
2588 		return (Z_SYSTEM);
2589 
2590 	if ((acltxt == NULL) || (strcmp(acltxt, "") == 0))
2591 		return (Z_OK);
2592 
2593 	if (acl_fromtext(acltxt, &aclp) != 0)
2594 		return (Z_SYSTEM);
2595 
2596 	errno = 0;
2597 	if (acl_set(path, aclp) == -1) {
2598 		free(aclp);
2599 		return (Z_SYSTEM);
2600 	}
2601 
2602 	free(aclp);
2603 	return (Z_OK);
2604 }
2605 
2606 /*
2607  * This function finds everything mounted under a zone's rootpath.
2608  * This returns the number of mounts under rootpath, or -1 on error.
2609  * callback is called once per mount found with the first argument
2610  * pointing to the  mount point.
2611  *
2612  * If the callback function returns non-zero zonecfg_find_mounts
2613  * aborts with an error.
2614  */
2615 int
2616 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *),
2617     void *priv) {
2618 	FILE *mnttab;
2619 	struct mnttab m;
2620 	size_t l;
2621 	int zfsl;
2622 	int rv = 0;
2623 	char zfs_path[MAXPATHLEN];
2624 
2625 	assert(rootpath != NULL);
2626 
2627 	if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath))
2628 	    >= sizeof (zfs_path))
2629 		return (-1);
2630 
2631 	l = strlen(rootpath);
2632 
2633 	mnttab = fopen("/etc/mnttab", "r");
2634 
2635 	if (mnttab == NULL)
2636 		return (-1);
2637 
2638 	if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0)  {
2639 		rv = -1;
2640 		goto out;
2641 	}
2642 
2643 	while (!getmntent(mnttab, &m)) {
2644 		if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
2645 		    (m.mnt_mountp[l] == '/') &&
2646 		    (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) {
2647 			rv++;
2648 			if (callback == NULL)
2649 				continue;
2650 			if (callback(m.mnt_mountp, priv)) {
2651 				rv = -1;
2652 				goto out;
2653 
2654 			}
2655 		}
2656 	}
2657 
2658 out:
2659 	(void) fclose(mnttab);
2660 	return (rv);
2661 }
2662 
2663 int
2664 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2665 {
2666 	xmlNodePtr cur, firstmatch;
2667 	int err;
2668 	char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
2669 
2670 	if (tabptr == NULL)
2671 		return (Z_INVAL);
2672 
2673 	if ((err = operation_prep(handle)) != Z_OK)
2674 		return (err);
2675 
2676 	cur = handle->zone_dh_cur;
2677 	firstmatch = NULL;
2678 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2679 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
2680 			continue;
2681 		if (strlen(tabptr->zone_attr_name) > 0) {
2682 			if ((fetchprop(cur, DTD_ATTR_NAME, name,
2683 			    sizeof (name)) == Z_OK) &&
2684 			    (strcmp(tabptr->zone_attr_name, name) == 0)) {
2685 				if (firstmatch == NULL)
2686 					firstmatch = cur;
2687 				else
2688 					return (Z_INSUFFICIENT_SPEC);
2689 			}
2690 		}
2691 		if (strlen(tabptr->zone_attr_type) > 0) {
2692 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
2693 			    sizeof (type)) == Z_OK)) {
2694 				if (strcmp(tabptr->zone_attr_type, type) == 0) {
2695 					if (firstmatch == NULL)
2696 						firstmatch = cur;
2697 					else if (firstmatch != cur)
2698 						return (Z_INSUFFICIENT_SPEC);
2699 				} else {
2700 					/*
2701 					 * If another property matched but this
2702 					 * one doesn't then reset firstmatch.
2703 					 */
2704 					if (firstmatch == cur)
2705 						firstmatch = NULL;
2706 				}
2707 			}
2708 		}
2709 		if (strlen(tabptr->zone_attr_value) > 0) {
2710 			if ((fetchprop(cur, DTD_ATTR_VALUE, value,
2711 			    sizeof (value)) == Z_OK)) {
2712 				if (strcmp(tabptr->zone_attr_value, value) ==
2713 				    0) {
2714 					if (firstmatch == NULL)
2715 						firstmatch = cur;
2716 					else if (firstmatch != cur)
2717 						return (Z_INSUFFICIENT_SPEC);
2718 				} else {
2719 					/*
2720 					 * If another property matched but this
2721 					 * one doesn't then reset firstmatch.
2722 					 */
2723 					if (firstmatch == cur)
2724 						firstmatch = NULL;
2725 				}
2726 			}
2727 		}
2728 	}
2729 	if (firstmatch == NULL)
2730 		return (Z_NO_RESOURCE_ID);
2731 
2732 	cur = firstmatch;
2733 
2734 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
2735 	    sizeof (tabptr->zone_attr_name))) != Z_OK)
2736 		return (err);
2737 
2738 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
2739 	    sizeof (tabptr->zone_attr_type))) != Z_OK)
2740 		return (err);
2741 
2742 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
2743 	    sizeof (tabptr->zone_attr_value))) != Z_OK)
2744 		return (err);
2745 
2746 	return (Z_OK);
2747 }
2748 
2749 static int
2750 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2751 {
2752 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2753 	int err;
2754 
2755 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
2756 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
2757 	if (err != Z_OK)
2758 		return (err);
2759 	err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
2760 	if (err != Z_OK)
2761 		return (err);
2762 	err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
2763 	if (err != Z_OK)
2764 		return (err);
2765 	return (Z_OK);
2766 }
2767 
2768 int
2769 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2770 {
2771 	int err;
2772 
2773 	if (tabptr == NULL)
2774 		return (Z_INVAL);
2775 
2776 	if ((err = operation_prep(handle)) != Z_OK)
2777 		return (err);
2778 
2779 	if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
2780 		return (err);
2781 
2782 	return (Z_OK);
2783 }
2784 
2785 static int
2786 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2787 {
2788 	xmlNodePtr cur = handle->zone_dh_cur;
2789 	int name_match, type_match, value_match;
2790 
2791 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2792 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
2793 			continue;
2794 
2795 		name_match = match_prop(cur, DTD_ATTR_NAME,
2796 		    tabptr->zone_attr_name);
2797 		type_match = match_prop(cur, DTD_ATTR_TYPE,
2798 		    tabptr->zone_attr_type);
2799 		value_match = match_prop(cur, DTD_ATTR_VALUE,
2800 		    tabptr->zone_attr_value);
2801 
2802 		if (name_match && type_match && value_match) {
2803 			xmlUnlinkNode(cur);
2804 			xmlFreeNode(cur);
2805 			return (Z_OK);
2806 		}
2807 	}
2808 	return (Z_NO_RESOURCE_ID);
2809 }
2810 
2811 int
2812 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2813 {
2814 	int err;
2815 
2816 	if (tabptr == NULL)
2817 		return (Z_INVAL);
2818 
2819 	if ((err = operation_prep(handle)) != Z_OK)
2820 		return (err);
2821 
2822 	if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
2823 		return (err);
2824 
2825 	return (Z_OK);
2826 }
2827 
2828 int
2829 zonecfg_modify_attr(
2830 	zone_dochandle_t handle,
2831 	struct zone_attrtab *oldtabptr,
2832 	struct zone_attrtab *newtabptr)
2833 {
2834 	int err;
2835 
2836 	if (oldtabptr == NULL || newtabptr == NULL)
2837 		return (Z_INVAL);
2838 
2839 	if ((err = operation_prep(handle)) != Z_OK)
2840 		return (err);
2841 
2842 	if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK)
2843 		return (err);
2844 
2845 	if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK)
2846 		return (err);
2847 
2848 	return (Z_OK);
2849 }
2850 
2851 int
2852 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value)
2853 {
2854 	if (attr == NULL)
2855 		return (Z_INVAL);
2856 
2857 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0)
2858 		return (Z_INVAL);
2859 
2860 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) {
2861 		*value = B_TRUE;
2862 		return (Z_OK);
2863 	}
2864 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) {
2865 		*value = B_FALSE;
2866 		return (Z_OK);
2867 	}
2868 	return (Z_INVAL);
2869 }
2870 
2871 int
2872 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value)
2873 {
2874 	long long result;
2875 	char *endptr;
2876 
2877 	if (attr == NULL)
2878 		return (Z_INVAL);
2879 
2880 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0)
2881 		return (Z_INVAL);
2882 
2883 	errno = 0;
2884 	result = strtoll(attr->zone_attr_value, &endptr, 10);
2885 	if (errno != 0 || *endptr != '\0')
2886 		return (Z_INVAL);
2887 	*value = result;
2888 	return (Z_OK);
2889 }
2890 
2891 int
2892 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value,
2893     size_t val_sz)
2894 {
2895 	if (attr == NULL)
2896 		return (Z_INVAL);
2897 
2898 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0)
2899 		return (Z_INVAL);
2900 
2901 	if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz)
2902 		return (Z_TOO_BIG);
2903 	return (Z_OK);
2904 }
2905 
2906 int
2907 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value)
2908 {
2909 	unsigned long long result;
2910 	long long neg_result;
2911 	char *endptr;
2912 
2913 	if (attr == NULL)
2914 		return (Z_INVAL);
2915 
2916 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0)
2917 		return (Z_INVAL);
2918 
2919 	errno = 0;
2920 	result = strtoull(attr->zone_attr_value, &endptr, 10);
2921 	if (errno != 0 || *endptr != '\0')
2922 		return (Z_INVAL);
2923 	errno = 0;
2924 	neg_result = strtoll(attr->zone_attr_value, &endptr, 10);
2925 	/*
2926 	 * Incredibly, strtoull("<negative number>", ...) will not fail but
2927 	 * return whatever (negative) number cast as a u_longlong_t, so we
2928 	 * need to look for this here.
2929 	 */
2930 	if (errno == 0 && neg_result < 0)
2931 		return (Z_INVAL);
2932 	*value = result;
2933 	return (Z_OK);
2934 }
2935 
2936 int
2937 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2938 {
2939 	xmlNodePtr cur, val;
2940 	char savedname[MAXNAMELEN];
2941 	struct zone_rctlvaltab *valptr;
2942 	int err;
2943 
2944 	if (tabptr->zone_rctl_name == NULL ||
2945 	    strlen(tabptr->zone_rctl_name) == 0)
2946 		return (Z_INVAL);
2947 
2948 	if ((err = operation_prep(handle)) != Z_OK)
2949 		return (err);
2950 
2951 	cur = handle->zone_dh_cur;
2952 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2953 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
2954 			continue;
2955 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
2956 		    sizeof (savedname)) == Z_OK) &&
2957 		    (strcmp(savedname, tabptr->zone_rctl_name) == 0)) {
2958 			tabptr->zone_rctl_valptr = NULL;
2959 			for (val = cur->xmlChildrenNode; val != NULL;
2960 			    val = val->next) {
2961 				valptr = (struct zone_rctlvaltab *)malloc(
2962 				    sizeof (struct zone_rctlvaltab));
2963 				if (valptr == NULL)
2964 					return (Z_NOMEM);
2965 				if ((fetchprop(val, DTD_ATTR_PRIV,
2966 				    valptr->zone_rctlval_priv,
2967 				    sizeof (valptr->zone_rctlval_priv)) !=
2968 				    Z_OK))
2969 					break;
2970 				if ((fetchprop(val, DTD_ATTR_LIMIT,
2971 				    valptr->zone_rctlval_limit,
2972 				    sizeof (valptr->zone_rctlval_limit)) !=
2973 				    Z_OK))
2974 					break;
2975 				if ((fetchprop(val, DTD_ATTR_ACTION,
2976 				    valptr->zone_rctlval_action,
2977 				    sizeof (valptr->zone_rctlval_action)) !=
2978 				    Z_OK))
2979 					break;
2980 				if (zonecfg_add_rctl_value(tabptr, valptr) !=
2981 				    Z_OK)
2982 					break;
2983 			}
2984 			return (Z_OK);
2985 		}
2986 	}
2987 	return (Z_NO_RESOURCE_ID);
2988 }
2989 
2990 static int
2991 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2992 {
2993 	xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
2994 	struct zone_rctlvaltab *valptr;
2995 	int err;
2996 
2997 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL);
2998 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name);
2999 	if (err != Z_OK)
3000 		return (err);
3001 	for (valptr = tabptr->zone_rctl_valptr; valptr != NULL;
3002 	    valptr = valptr->zone_rctlval_next) {
3003 		valnode = xmlNewTextChild(newnode, NULL,
3004 		    DTD_ELEM_RCTLVALUE, NULL);
3005 		err = newprop(valnode, DTD_ATTR_PRIV,
3006 		    valptr->zone_rctlval_priv);
3007 		if (err != Z_OK)
3008 			return (err);
3009 		err = newprop(valnode, DTD_ATTR_LIMIT,
3010 		    valptr->zone_rctlval_limit);
3011 		if (err != Z_OK)
3012 			return (err);
3013 		err = newprop(valnode, DTD_ATTR_ACTION,
3014 		    valptr->zone_rctlval_action);
3015 		if (err != Z_OK)
3016 			return (err);
3017 	}
3018 	return (Z_OK);
3019 }
3020 
3021 int
3022 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3023 {
3024 	int err;
3025 
3026 	if (tabptr == NULL || tabptr->zone_rctl_name == NULL)
3027 		return (Z_INVAL);
3028 
3029 	if ((err = operation_prep(handle)) != Z_OK)
3030 		return (err);
3031 
3032 	if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK)
3033 		return (err);
3034 
3035 	return (Z_OK);
3036 }
3037 
3038 static int
3039 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3040 {
3041 	xmlNodePtr cur = handle->zone_dh_cur;
3042 	xmlChar *savedname;
3043 	int name_result;
3044 
3045 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3046 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
3047 			continue;
3048 
3049 		savedname = xmlGetProp(cur, DTD_ATTR_NAME);
3050 		if (savedname == NULL)	/* shouldn't happen */
3051 			continue;
3052 		name_result = xmlStrcmp(savedname,
3053 		    (const xmlChar *) tabptr->zone_rctl_name);
3054 		xmlFree(savedname);
3055 
3056 		if (name_result == 0) {
3057 			xmlUnlinkNode(cur);
3058 			xmlFreeNode(cur);
3059 			return (Z_OK);
3060 		}
3061 	}
3062 	return (Z_NO_RESOURCE_ID);
3063 }
3064 
3065 int
3066 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3067 {
3068 	int err;
3069 
3070 	if (tabptr == NULL || tabptr->zone_rctl_name == NULL)
3071 		return (Z_INVAL);
3072 
3073 	if ((err = operation_prep(handle)) != Z_OK)
3074 		return (err);
3075 
3076 	if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK)
3077 		return (err);
3078 
3079 	return (Z_OK);
3080 }
3081 
3082 int
3083 zonecfg_modify_rctl(
3084 	zone_dochandle_t handle,
3085 	struct zone_rctltab *oldtabptr,
3086 	struct zone_rctltab *newtabptr)
3087 {
3088 	int err;
3089 
3090 	if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL ||
3091 	    newtabptr == NULL || newtabptr->zone_rctl_name == NULL)
3092 		return (Z_INVAL);
3093 
3094 	if ((err = operation_prep(handle)) != Z_OK)
3095 		return (err);
3096 
3097 	if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK)
3098 		return (err);
3099 
3100 	if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK)
3101 		return (err);
3102 
3103 	return (Z_OK);
3104 }
3105 
3106 int
3107 zonecfg_add_rctl_value(
3108 	struct zone_rctltab *tabptr,
3109 	struct zone_rctlvaltab *valtabptr)
3110 {
3111 	struct zone_rctlvaltab *last, *old, *new;
3112 	rctlblk_t *rctlblk = alloca(rctlblk_size());
3113 
3114 	last = tabptr->zone_rctl_valptr;
3115 	for (old = last; old != NULL; old = old->zone_rctlval_next)
3116 		last = old;	/* walk to the end of the list */
3117 	new = valtabptr;	/* alloc'd by caller */
3118 	new->zone_rctlval_next = NULL;
3119 	if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK)
3120 		return (Z_INVAL);
3121 	if (!zonecfg_valid_rctlblk(rctlblk))
3122 		return (Z_INVAL);
3123 	if (last == NULL)
3124 		tabptr->zone_rctl_valptr = new;
3125 	else
3126 		last->zone_rctlval_next = new;
3127 	return (Z_OK);
3128 }
3129 
3130 int
3131 zonecfg_remove_rctl_value(
3132 	struct zone_rctltab *tabptr,
3133 	struct zone_rctlvaltab *valtabptr)
3134 {
3135 	struct zone_rctlvaltab *last, *this, *next;
3136 
3137 	last = tabptr->zone_rctl_valptr;
3138 	for (this = last; this != NULL; this = this->zone_rctlval_next) {
3139 		if (strcmp(this->zone_rctlval_priv,
3140 		    valtabptr->zone_rctlval_priv) == 0 &&
3141 		    strcmp(this->zone_rctlval_limit,
3142 		    valtabptr->zone_rctlval_limit) == 0 &&
3143 		    strcmp(this->zone_rctlval_action,
3144 		    valtabptr->zone_rctlval_action) == 0) {
3145 			next = this->zone_rctlval_next;
3146 			if (this == tabptr->zone_rctl_valptr)
3147 				tabptr->zone_rctl_valptr = next;
3148 			else
3149 				last->zone_rctlval_next = next;
3150 			free(this);
3151 			return (Z_OK);
3152 		} else
3153 			last = this;
3154 	}
3155 	return (Z_NO_PROPERTY_ID);
3156 }
3157 
3158 char *
3159 zonecfg_strerror(int errnum)
3160 {
3161 	switch (errnum) {
3162 	case Z_OK:
3163 		return (dgettext(TEXT_DOMAIN, "OK"));
3164 	case Z_EMPTY_DOCUMENT:
3165 		return (dgettext(TEXT_DOMAIN, "Empty document"));
3166 	case Z_WRONG_DOC_TYPE:
3167 		return (dgettext(TEXT_DOMAIN, "Wrong document type"));
3168 	case Z_BAD_PROPERTY:
3169 		return (dgettext(TEXT_DOMAIN, "Bad document property"));
3170 	case Z_TEMP_FILE:
3171 		return (dgettext(TEXT_DOMAIN,
3172 		    "Problem creating temporary file"));
3173 	case Z_SAVING_FILE:
3174 		return (dgettext(TEXT_DOMAIN, "Problem saving file"));
3175 	case Z_NO_ENTRY:
3176 		return (dgettext(TEXT_DOMAIN, "No such entry"));
3177 	case Z_BOGUS_ZONE_NAME:
3178 		return (dgettext(TEXT_DOMAIN, "Bogus zone name"));
3179 	case Z_REQD_RESOURCE_MISSING:
3180 		return (dgettext(TEXT_DOMAIN, "Required resource missing"));
3181 	case Z_REQD_PROPERTY_MISSING:
3182 		return (dgettext(TEXT_DOMAIN, "Required property missing"));
3183 	case Z_BAD_HANDLE:
3184 		return (dgettext(TEXT_DOMAIN, "Bad handle"));
3185 	case Z_NOMEM:
3186 		return (dgettext(TEXT_DOMAIN, "Out of memory"));
3187 	case Z_INVAL:
3188 		return (dgettext(TEXT_DOMAIN, "Invalid argument"));
3189 	case Z_ACCES:
3190 		return (dgettext(TEXT_DOMAIN, "Permission denied"));
3191 	case Z_TOO_BIG:
3192 		return (dgettext(TEXT_DOMAIN, "Argument list too long"));
3193 	case Z_MISC_FS:
3194 		return (dgettext(TEXT_DOMAIN,
3195 		    "Miscellaneous file system error"));
3196 	case Z_NO_ZONE:
3197 		return (dgettext(TEXT_DOMAIN, "No such zone configured"));
3198 	case Z_NO_RESOURCE_TYPE:
3199 		return (dgettext(TEXT_DOMAIN, "No such resource type"));
3200 	case Z_NO_RESOURCE_ID:
3201 		return (dgettext(TEXT_DOMAIN, "No such resource with that id"));
3202 	case Z_NO_PROPERTY_TYPE:
3203 		return (dgettext(TEXT_DOMAIN, "No such property type"));
3204 	case Z_NO_PROPERTY_ID:
3205 		return (dgettext(TEXT_DOMAIN, "No such property with that id"));
3206 	case Z_BAD_ZONE_STATE:
3207 		return (dgettext(TEXT_DOMAIN,
3208 		    "Zone state is invalid for the requested operation"));
3209 	case Z_INVALID_DOCUMENT:
3210 		return (dgettext(TEXT_DOMAIN, "Invalid document"));
3211 	case Z_NAME_IN_USE:
3212 		return (dgettext(TEXT_DOMAIN, "Zone name already in use"));
3213 	case Z_NO_SUCH_ID:
3214 		return (dgettext(TEXT_DOMAIN, "No such zone ID"));
3215 	case Z_UPDATING_INDEX:
3216 		return (dgettext(TEXT_DOMAIN, "Problem updating index file"));
3217 	case Z_LOCKING_FILE:
3218 		return (dgettext(TEXT_DOMAIN, "Locking index file"));
3219 	case Z_UNLOCKING_FILE:
3220 		return (dgettext(TEXT_DOMAIN, "Unlocking index file"));
3221 	case Z_INSUFFICIENT_SPEC:
3222 		return (dgettext(TEXT_DOMAIN, "Insufficient specification"));
3223 	case Z_RESOLVED_PATH:
3224 		return (dgettext(TEXT_DOMAIN, "Resolved path mismatch"));
3225 	case Z_IPV6_ADDR_PREFIX_LEN:
3226 		return (dgettext(TEXT_DOMAIN,
3227 		    "IPv6 address missing required prefix length"));
3228 	case Z_BOGUS_ADDRESS:
3229 		return (dgettext(TEXT_DOMAIN,
3230 		    "Neither an IPv4 nor an IPv6 address nor a host name"));
3231 	case Z_PRIV_PROHIBITED:
3232 		return (dgettext(TEXT_DOMAIN,
3233 		    "Specified privilege is prohibited"));
3234 	case Z_PRIV_REQUIRED:
3235 		return (dgettext(TEXT_DOMAIN,
3236 		    "Required privilege is missing"));
3237 	case Z_PRIV_UNKNOWN:
3238 		return (dgettext(TEXT_DOMAIN,
3239 		    "Specified privilege is unknown"));
3240 	case Z_BRAND_ERROR:
3241 		return (dgettext(TEXT_DOMAIN,
3242 		    "Brand-specific error"));
3243 	case Z_INCOMPATIBLE:
3244 		return (dgettext(TEXT_DOMAIN, "Incompatible settings"));
3245 	case Z_ALIAS_DISALLOW:
3246 		return (dgettext(TEXT_DOMAIN,
3247 		    "An incompatible rctl already exists for this property"));
3248 	case Z_CLEAR_DISALLOW:
3249 		return (dgettext(TEXT_DOMAIN,
3250 		    "Clearing this property is not allowed"));
3251 	case Z_POOL:
3252 		return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error"));
3253 	case Z_POOLS_NOT_ACTIVE:
3254 		return (dgettext(TEXT_DOMAIN, "Pools facility not active; "
3255 		    "zone will not be bound to pool"));
3256 	case Z_POOL_ENABLE:
3257 		return (dgettext(TEXT_DOMAIN,
3258 		    "Could not enable pools facility"));
3259 	case Z_NO_POOL:
3260 		return (dgettext(TEXT_DOMAIN,
3261 		    "Pool not found; using default pool"));
3262 	case Z_POOL_CREATE:
3263 		return (dgettext(TEXT_DOMAIN,
3264 		    "Could not create a temporary pool"));
3265 	case Z_POOL_BIND:
3266 		return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool"));
3267 	default:
3268 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
3269 	}
3270 }
3271 
3272 /*
3273  * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
3274  * same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
3275  */
3276 
3277 static int
3278 zonecfg_setent(zone_dochandle_t handle)
3279 {
3280 	xmlNodePtr cur;
3281 	int err;
3282 
3283 	if (handle == NULL)
3284 		return (Z_INVAL);
3285 
3286 	if ((err = operation_prep(handle)) != Z_OK) {
3287 		handle->zone_dh_cur = NULL;
3288 		return (err);
3289 	}
3290 	cur = handle->zone_dh_cur;
3291 	cur = cur->xmlChildrenNode;
3292 	handle->zone_dh_cur = cur;
3293 	return (Z_OK);
3294 }
3295 
3296 static int
3297 zonecfg_endent(zone_dochandle_t handle)
3298 {
3299 	if (handle == NULL)
3300 		return (Z_INVAL);
3301 
3302 	handle->zone_dh_cur = handle->zone_dh_top;
3303 	return (Z_OK);
3304 }
3305 
3306 /*
3307  * Do the work required to manipulate a process through libproc.
3308  * If grab_process() returns no errors (0), then release_process()
3309  * must eventually be called.
3310  *
3311  * Return values:
3312  *      0 Successful creation of agent thread
3313  *      1 Error grabbing
3314  *      2 Error creating agent
3315  */
3316 static int
3317 grab_process(pr_info_handle_t *p)
3318 {
3319 	int ret;
3320 
3321 	if ((p->pr = Pgrab(p->pid, 0, &ret)) != NULL) {
3322 
3323 		if (Psetflags(p->pr, PR_RLC) != 0) {
3324 			Prelease(p->pr, 0);
3325 			return (1);
3326 		}
3327 		if (Pcreate_agent(p->pr) == 0) {
3328 			return (0);
3329 
3330 		} else {
3331 			Prelease(p->pr, 0);
3332 			return (2);
3333 		}
3334 	} else {
3335 		return (1);
3336 	}
3337 }
3338 
3339 /*
3340  * Release the specified process. This destroys the agent
3341  * and releases the process. If the process is NULL, nothing
3342  * is done. This function should only be called if grab_process()
3343  * has previously been called and returned success.
3344  *
3345  * This function is Pgrab-safe.
3346  */
3347 static void
3348 release_process(struct ps_prochandle *Pr)
3349 {
3350 	if (Pr == NULL)
3351 		return;
3352 
3353 	Pdestroy_agent(Pr);
3354 	Prelease(Pr, 0);
3355 }
3356 
3357 static boolean_t
3358 grab_zone_proc(char *zonename, pr_info_handle_t *p)
3359 {
3360 	DIR *dirp;
3361 	struct dirent *dentp;
3362 	zoneid_t zoneid;
3363 	int pid_self;
3364 	psinfo_t psinfo;
3365 
3366 	if (zone_get_id(zonename, &zoneid) != 0)
3367 		return (B_FALSE);
3368 
3369 	pid_self = getpid();
3370 
3371 	if ((dirp = opendir("/proc")) == NULL)
3372 		return (B_FALSE);
3373 
3374 	while (dentp = readdir(dirp)) {
3375 		p->pid = atoi(dentp->d_name);
3376 
3377 		/* Skip self */
3378 		if (p->pid == pid_self)
3379 			continue;
3380 
3381 		if (proc_get_psinfo(p->pid, &psinfo) != 0)
3382 			continue;
3383 
3384 		if (psinfo.pr_zoneid != zoneid)
3385 			continue;
3386 
3387 		/* attempt to grab process */
3388 		if (grab_process(p) != 0)
3389 			continue;
3390 
3391 		if (pr_getzoneid(p->pr) != zoneid) {
3392 			release_process(p->pr);
3393 			continue;
3394 		}
3395 
3396 		(void) closedir(dirp);
3397 		return (B_TRUE);
3398 	}
3399 
3400 	(void) closedir(dirp);
3401 	return (B_FALSE);
3402 }
3403 
3404 static boolean_t
3405 get_priv_rctl(struct ps_prochandle *pr, char *name, rctlblk_t *rblk)
3406 {
3407 	if (pr_getrctl(pr, name, NULL, rblk, RCTL_FIRST))
3408 		return (B_FALSE);
3409 
3410 	if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
3411 		return (B_TRUE);
3412 
3413 	while (pr_getrctl(pr, name, rblk, rblk, RCTL_NEXT) == 0) {
3414 		if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
3415 			return (B_TRUE);
3416 	}
3417 
3418 	return (B_FALSE);
3419 }
3420 
3421 /*
3422  * Apply the current rctl settings to the specified, running zone.
3423  */
3424 int
3425 zonecfg_apply_rctls(char *zone_name, zone_dochandle_t handle)
3426 {
3427 	int err;
3428 	int res = Z_OK;
3429 	rctlblk_t *rblk;
3430 	pr_info_handle_t p;
3431 	struct zone_rctltab rctl;
3432 
3433 	if ((err = zonecfg_setrctlent(handle)) != Z_OK)
3434 		return (err);
3435 
3436 	if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
3437 		(void) zonecfg_endrctlent(handle);
3438 		return (Z_NOMEM);
3439 	}
3440 
3441 	if (!grab_zone_proc(zone_name, &p)) {
3442 		(void) zonecfg_endrctlent(handle);
3443 		free(rblk);
3444 		return (Z_SYSTEM);
3445 	}
3446 
3447 	while (zonecfg_getrctlent(handle, &rctl) == Z_OK) {
3448 		char *rname;
3449 		struct zone_rctlvaltab *valptr;
3450 
3451 		rname = rctl.zone_rctl_name;
3452 
3453 		/* first delete all current privileged settings for this rctl */
3454 		while (get_priv_rctl(p.pr, rname, rblk)) {
3455 			if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_DELETE) !=
3456 			    0) {
3457 				res = Z_SYSTEM;
3458 				goto done;
3459 			}
3460 		}
3461 
3462 		/* now set each new value for the rctl */
3463 		for (valptr = rctl.zone_rctl_valptr; valptr != NULL;
3464 		    valptr = valptr->zone_rctlval_next) {
3465 			if ((err = zonecfg_construct_rctlblk(valptr, rblk))
3466 			    != Z_OK) {
3467 				res = errno = err;
3468 				goto done;
3469 			}
3470 
3471 			if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_INSERT)) {
3472 				res = Z_SYSTEM;
3473 				goto done;
3474 			}
3475 		}
3476 	}
3477 
3478 done:
3479 	release_process(p.pr);
3480 	free(rblk);
3481 	(void) zonecfg_endrctlent(handle);
3482 
3483 	return (res);
3484 }
3485 
3486 static const xmlChar *
3487 nm_to_dtd(char *nm)
3488 {
3489 	if (strcmp(nm, "device") == 0)
3490 		return (DTD_ELEM_DEVICE);
3491 	if (strcmp(nm, "fs") == 0)
3492 		return (DTD_ELEM_FS);
3493 	if (strcmp(nm, "inherit-pkg-dir") == 0)
3494 		return (DTD_ELEM_IPD);
3495 	if (strcmp(nm, "net") == 0)
3496 		return (DTD_ELEM_NET);
3497 	if (strcmp(nm, "attr") == 0)
3498 		return (DTD_ELEM_ATTR);
3499 	if (strcmp(nm, "rctl") == 0)
3500 		return (DTD_ELEM_RCTL);
3501 	if (strcmp(nm, "dataset") == 0)
3502 		return (DTD_ELEM_DATASET);
3503 
3504 	return (NULL);
3505 }
3506 
3507 int
3508 zonecfg_num_resources(zone_dochandle_t handle, char *rsrc)
3509 {
3510 	int num = 0;
3511 	const xmlChar *dtd;
3512 	xmlNodePtr cur;
3513 
3514 	if ((dtd = nm_to_dtd(rsrc)) == NULL)
3515 		return (num);
3516 
3517 	if (zonecfg_setent(handle) != Z_OK)
3518 		return (num);
3519 
3520 	for (cur = handle->zone_dh_cur; cur != NULL; cur = cur->next)
3521 		if (xmlStrcmp(cur->name, dtd) == 0)
3522 			num++;
3523 
3524 	(void) zonecfg_endent(handle);
3525 
3526 	return (num);
3527 }
3528 
3529 int
3530 zonecfg_del_all_resources(zone_dochandle_t handle, char *rsrc)
3531 {
3532 	int err;
3533 	const xmlChar *dtd;
3534 	xmlNodePtr cur;
3535 
3536 	if ((dtd = nm_to_dtd(rsrc)) == NULL)
3537 		return (Z_NO_RESOURCE_TYPE);
3538 
3539 	if ((err = zonecfg_setent(handle)) != Z_OK)
3540 		return (err);
3541 
3542 	cur = handle->zone_dh_cur;
3543 	while (cur != NULL) {
3544 		xmlNodePtr tmp;
3545 
3546 		if (xmlStrcmp(cur->name, dtd)) {
3547 			cur = cur->next;
3548 			continue;
3549 		}
3550 
3551 		tmp = cur->next;
3552 		xmlUnlinkNode(cur);
3553 		xmlFreeNode(cur);
3554 		cur = tmp;
3555 	}
3556 
3557 	(void) zonecfg_endent(handle);
3558 	return (Z_OK);
3559 }
3560 
3561 static boolean_t
3562 valid_uint(char *s, uint64_t *n)
3563 {
3564 	char *endp;
3565 
3566 	/* strtoull accepts '-'?! so we want to flag that as an error */
3567 	if (strchr(s, '-') != NULL)
3568 		return (B_FALSE);
3569 
3570 	errno = 0;
3571 	*n = strtoull(s, &endp, 10);
3572 
3573 	if (errno != 0 || *endp != '\0')
3574 		return (B_FALSE);
3575 	return (B_TRUE);
3576 }
3577 
3578 /*
3579  * Convert a string representing a number (possibly a fraction) into an integer.
3580  * The string can have a modifier (K, M, G or T).   The modifiers are treated
3581  * as powers of two (not 10).
3582  */
3583 int
3584 zonecfg_str_to_bytes(char *str, uint64_t *bytes)
3585 {
3586 	long double val;
3587 	char *unitp;
3588 	uint64_t scale;
3589 
3590 	if ((val = strtold(str, &unitp)) < 0)
3591 		return (-1);
3592 
3593 	/* remove any leading white space from units string */
3594 	while (isspace(*unitp) != 0)
3595 		++unitp;
3596 
3597 	/* if no units explicitly set, error */
3598 	if (unitp == NULL || *unitp == '\0') {
3599 		scale = 1;
3600 	} else {
3601 		int i;
3602 		char *units[] = {"K", "M", "G", "T", NULL};
3603 
3604 		scale = 1024;
3605 
3606 		/* update scale based on units */
3607 		for (i = 0; units[i] != NULL; i++) {
3608 			if (strcasecmp(unitp, units[i]) == 0)
3609 				break;
3610 			scale <<= 10;
3611 		}
3612 
3613 		if (units[i] == NULL)
3614 			return (-1);
3615 	}
3616 
3617 	*bytes = (uint64_t)(val * scale);
3618 	return (0);
3619 }
3620 
3621 boolean_t
3622 zonecfg_valid_ncpus(char *lowstr, char *highstr)
3623 {
3624 	uint64_t low, high;
3625 
3626 	if (!valid_uint(lowstr, &low) || !valid_uint(highstr, &high) ||
3627 	    low < 1 || low > high)
3628 		return (B_FALSE);
3629 
3630 	return (B_TRUE);
3631 }
3632 
3633 boolean_t
3634 zonecfg_valid_importance(char *impstr)
3635 {
3636 	uint64_t num;
3637 
3638 	if (!valid_uint(impstr, &num))
3639 		return (B_FALSE);
3640 
3641 	return (B_TRUE);
3642 }
3643 
3644 boolean_t
3645 zonecfg_valid_alias_limit(char *name, char *limitstr, uint64_t *limit)
3646 {
3647 	int i;
3648 
3649 	for (i = 0; aliases[i].shortname != NULL; i++)
3650 		if (strcmp(name, aliases[i].shortname) == 0)
3651 			break;
3652 
3653 	if (aliases[i].shortname == NULL)
3654 		return (B_FALSE);
3655 
3656 	if (!valid_uint(limitstr, limit) || *limit < aliases[i].low_limit)
3657 		return (B_FALSE);
3658 
3659 	return (B_TRUE);
3660 }
3661 
3662 boolean_t
3663 zonecfg_valid_memlimit(char *memstr, uint64_t *mem_val)
3664 {
3665 	if (zonecfg_str_to_bytes(memstr, mem_val) != 0)
3666 		return (B_FALSE);
3667 
3668 	return (B_TRUE);
3669 }
3670 
3671 static int
3672 zerr_pool(char *pool_err, int err_size, int res)
3673 {
3674 	(void) strlcpy(pool_err, pool_strerror(pool_error()), err_size);
3675 	return (res);
3676 }
3677 
3678 static int
3679 create_tmp_pset(char *pool_err, int err_size, pool_conf_t *pconf, pool_t *pool,
3680     char *name, int min, int max)
3681 {
3682 	pool_resource_t *res;
3683 	pool_elem_t *elem;
3684 	pool_value_t *val;
3685 
3686 	if ((res = pool_resource_create(pconf, "pset", name)) == NULL)
3687 		return (zerr_pool(pool_err, err_size, Z_POOL));
3688 
3689 	if (pool_associate(pconf, pool, res) != PO_SUCCESS)
3690 		return (zerr_pool(pool_err, err_size, Z_POOL));
3691 
3692 	if ((elem = pool_resource_to_elem(pconf, res)) == NULL)
3693 		return (zerr_pool(pool_err, err_size, Z_POOL));
3694 
3695 	if ((val = pool_value_alloc()) == NULL)
3696 		return (zerr_pool(pool_err, err_size, Z_POOL));
3697 
3698 	/* set the maximum number of cpus for the pset */
3699 	pool_value_set_uint64(val, (uint64_t)max);
3700 
3701 	if (pool_put_property(pconf, elem, "pset.max", val) != PO_SUCCESS) {
3702 		pool_value_free(val);
3703 		return (zerr_pool(pool_err, err_size, Z_POOL));
3704 	}
3705 
3706 	/* set the minimum number of cpus for the pset */
3707 	pool_value_set_uint64(val, (uint64_t)min);
3708 
3709 	if (pool_put_property(pconf, elem, "pset.min", val) != PO_SUCCESS) {
3710 		pool_value_free(val);
3711 		return (zerr_pool(pool_err, err_size, Z_POOL));
3712 	}
3713 
3714 	pool_value_free(val);
3715 
3716 	return (Z_OK);
3717 }
3718 
3719 static int
3720 create_tmp_pool(char *pool_err, int err_size, pool_conf_t *pconf, char *name,
3721     struct zone_psettab *pset_tab)
3722 {
3723 	pool_t *pool;
3724 	int res = Z_OK;
3725 
3726 	/* create a temporary pool configuration */
3727 	if (pool_conf_open(pconf, NULL, PO_TEMP) != PO_SUCCESS) {
3728 		res = zerr_pool(pool_err, err_size, Z_POOL);
3729 		return (res);
3730 	}
3731 
3732 	if ((pool = pool_create(pconf, name)) == NULL) {
3733 		res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
3734 		goto done;
3735 	}
3736 
3737 	/* set pool importance */
3738 	if (pset_tab->zone_importance[0] != '\0') {
3739 		pool_elem_t *elem;
3740 		pool_value_t *val;
3741 
3742 		if ((elem = pool_to_elem(pconf, pool)) == NULL) {
3743 			res = zerr_pool(pool_err, err_size, Z_POOL);
3744 			goto done;
3745 		}
3746 
3747 		if ((val = pool_value_alloc()) == NULL) {
3748 			res = zerr_pool(pool_err, err_size, Z_POOL);
3749 			goto done;
3750 		}
3751 
3752 		pool_value_set_int64(val,
3753 		    (int64_t)atoi(pset_tab->zone_importance));
3754 
3755 		if (pool_put_property(pconf, elem, "pool.importance", val)
3756 		    != PO_SUCCESS) {
3757 			res = zerr_pool(pool_err, err_size, Z_POOL);
3758 			pool_value_free(val);
3759 			goto done;
3760 		}
3761 
3762 		pool_value_free(val);
3763 	}
3764 
3765 	if ((res = create_tmp_pset(pool_err, err_size, pconf, pool, name,
3766 	    atoi(pset_tab->zone_ncpu_min),
3767 	    atoi(pset_tab->zone_ncpu_max))) != Z_OK)
3768 		goto done;
3769 
3770 	/* validation */
3771 	if (pool_conf_status(pconf) == POF_INVALID) {
3772 		res = zerr_pool(pool_err, err_size, Z_POOL);
3773 		goto done;
3774 	}
3775 
3776 	/*
3777 	 * This validation is the one we expect to fail if the user specified
3778 	 * an invalid configuration (too many cpus) for this system.
3779 	 */
3780 	if (pool_conf_validate(pconf, POV_RUNTIME) != PO_SUCCESS) {
3781 		res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
3782 		goto done;
3783 	}
3784 
3785 	/*
3786 	 * Commit the dynamic configuration but not the pool configuration
3787 	 * file.
3788 	 */
3789 	if (pool_conf_commit(pconf, 1) != PO_SUCCESS)
3790 		res = zerr_pool(pool_err, err_size, Z_POOL);
3791 
3792 done:
3793 	(void) pool_conf_close(pconf);
3794 	return (res);
3795 }
3796 
3797 static int
3798 get_running_tmp_pset(pool_conf_t *pconf, pool_t *pool, pool_resource_t *pset,
3799     struct zone_psettab *pset_tab)
3800 {
3801 	int nfound = 0;
3802 	pool_elem_t *pe;
3803 	pool_value_t *pv = pool_value_alloc();
3804 	uint64_t val_uint;
3805 
3806 	if (pool != NULL) {
3807 		pe = pool_to_elem(pconf, pool);
3808 		if (pool_get_property(pconf, pe, "pool.importance", pv)
3809 		    != POC_INVAL) {
3810 			int64_t val_int;
3811 
3812 			(void) pool_value_get_int64(pv, &val_int);
3813 			(void) snprintf(pset_tab->zone_importance,
3814 			    sizeof (pset_tab->zone_importance), "%d", val_int);
3815 			nfound++;
3816 		}
3817 	}
3818 
3819 	if (pset != NULL) {
3820 		pe = pool_resource_to_elem(pconf, pset);
3821 		if (pool_get_property(pconf, pe, "pset.min", pv) != POC_INVAL) {
3822 			(void) pool_value_get_uint64(pv, &val_uint);
3823 			(void) snprintf(pset_tab->zone_ncpu_min,
3824 			    sizeof (pset_tab->zone_ncpu_min), "%u", val_uint);
3825 			nfound++;
3826 		}
3827 
3828 		if (pool_get_property(pconf, pe, "pset.max", pv) != POC_INVAL) {
3829 			(void) pool_value_get_uint64(pv, &val_uint);
3830 			(void) snprintf(pset_tab->zone_ncpu_max,
3831 			    sizeof (pset_tab->zone_ncpu_max), "%u", val_uint);
3832 			nfound++;
3833 		}
3834 	}
3835 
3836 	pool_value_free(pv);
3837 
3838 	if (nfound == 3)
3839 		return (PO_SUCCESS);
3840 
3841 	return (PO_FAIL);
3842 }
3843 
3844 /*
3845  * Determine if a tmp pool is configured and if so, if the configuration is
3846  * still valid or if it has been changed since the tmp pool was created.
3847  * If the tmp pool configuration is no longer valid, delete the tmp pool.
3848  *
3849  * Set *valid=B_TRUE if there is an existing, valid tmp pool configuration.
3850  */
3851 static int
3852 verify_del_tmp_pool(pool_conf_t *pconf, char *tmp_name, char *pool_err,
3853     int err_size, struct zone_psettab *pset_tab, boolean_t *exists)
3854 {
3855 	int res = Z_OK;
3856 	pool_t *pool;
3857 	pool_resource_t *pset;
3858 	struct zone_psettab pset_current;
3859 
3860 	*exists = B_FALSE;
3861 
3862 	if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
3863 	    != PO_SUCCESS) {
3864 		res = zerr_pool(pool_err, err_size, Z_POOL);
3865 		return (res);
3866 	}
3867 
3868 	pool = pool_get_pool(pconf, tmp_name);
3869 	pset = pool_get_resource(pconf, "pset", tmp_name);
3870 
3871 	if (pool == NULL && pset == NULL) {
3872 		/* no tmp pool configured */
3873 		goto done;
3874 	}
3875 
3876 	/*
3877 	 * If an existing tmp pool for this zone is configured with the proper
3878 	 * settings, then the tmp pool is valid.
3879 	 */
3880 	if (get_running_tmp_pset(pconf, pool, pset, &pset_current)
3881 	    == PO_SUCCESS &&
3882 	    strcmp(pset_tab->zone_ncpu_min,
3883 	    pset_current.zone_ncpu_min) == 0 &&
3884 	    strcmp(pset_tab->zone_ncpu_max,
3885 	    pset_current.zone_ncpu_max) == 0 &&
3886 	    strcmp(pset_tab->zone_importance,
3887 	    pset_current.zone_importance) == 0) {
3888 		*exists = B_TRUE;
3889 
3890 	} else {
3891 		/*
3892 		 * An out-of-date tmp pool configuration exists.  Delete it
3893 		 * so that we can create the correct tmp pool config.
3894 		 */
3895 		if (pset != NULL &&
3896 		    pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
3897 			res = zerr_pool(pool_err, err_size, Z_POOL);
3898 			goto done;
3899 		}
3900 
3901 		if (pool != NULL &&
3902 		    pool_destroy(pconf, pool) != PO_SUCCESS) {
3903 			res = zerr_pool(pool_err, err_size, Z_POOL);
3904 			goto done;
3905 		}
3906 
3907 		/* commit dynamic config */
3908 		if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
3909 			res = zerr_pool(pool_err, err_size, Z_POOL);
3910 	}
3911 
3912 done:
3913 	(void) pool_conf_close(pconf);
3914 
3915 	return (res);
3916 }
3917 
3918 /*
3919  * Destroy any existing tmp pool.
3920  */
3921 int
3922 zonecfg_destroy_tmp_pool(char *zone_name, char *pool_err, int err_size)
3923 {
3924 	int status;
3925 	int res = Z_OK;
3926 	pool_conf_t *pconf;
3927 	pool_t *pool;
3928 	pool_resource_t *pset;
3929 	char tmp_name[MAX_TMP_POOL_NAME];
3930 
3931 	/* if pools not enabled then nothing to do */
3932 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
3933 		return (Z_OK);
3934 
3935 	if ((pconf = pool_conf_alloc()) == NULL)
3936 		return (zerr_pool(pool_err, err_size, Z_POOL));
3937 
3938 	(void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
3939 
3940 	if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
3941 	    != PO_SUCCESS) {
3942 		res = zerr_pool(pool_err, err_size, Z_POOL);
3943 		pool_conf_free(pconf);
3944 		return (res);
3945 	}
3946 
3947 	pool = pool_get_pool(pconf, tmp_name);
3948 	pset = pool_get_resource(pconf, "pset", tmp_name);
3949 
3950 	if (pool == NULL && pset == NULL) {
3951 		/* nothing to destroy, we're done */
3952 		goto done;
3953 	}
3954 
3955 	if (pset != NULL && pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
3956 		res = zerr_pool(pool_err, err_size, Z_POOL);
3957 		goto done;
3958 	}
3959 
3960 	if (pool != NULL && pool_destroy(pconf, pool) != PO_SUCCESS) {
3961 		res = zerr_pool(pool_err, err_size, Z_POOL);
3962 		goto done;
3963 	}
3964 
3965 	/* commit dynamic config */
3966 	if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
3967 		res = zerr_pool(pool_err, err_size, Z_POOL);
3968 
3969 done:
3970 	(void) pool_conf_close(pconf);
3971 	pool_conf_free(pconf);
3972 
3973 	return (res);
3974 }
3975 
3976 /*
3977  * Attempt to bind to a tmp pool for this zone.  If there is no tmp pool
3978  * configured, we just return Z_OK.
3979  *
3980  * We either attempt to create the tmp pool for this zone or rebind to an
3981  * existing tmp pool for this zone.
3982  *
3983  * Rebinding is used when a zone with a tmp pool reboots so that we don't have
3984  * to recreate the tmp pool.  To do this we need to be sure we work correctly
3985  * for the following cases:
3986  *
3987  *	- there is an existing, properly configured tmp pool.
3988  *	- zonecfg added tmp pool after zone was booted, must now create.
3989  *	- zonecfg updated tmp pool config after zone was booted, in this case
3990  *	  we destroy the old tmp pool and create a new one.
3991  */
3992 int
3993 zonecfg_bind_tmp_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
3994     int err_size)
3995 {
3996 	struct zone_psettab pset_tab;
3997 	int err;
3998 	int status;
3999 	pool_conf_t *pconf;
4000 	boolean_t exists;
4001 	char zone_name[ZONENAME_MAX];
4002 	char tmp_name[MAX_TMP_POOL_NAME];
4003 
4004 	(void) getzonenamebyid(zoneid, zone_name, sizeof (zone_name));
4005 
4006 	err = zonecfg_lookup_pset(handle, &pset_tab);
4007 
4008 	/* if no temporary pool configured, we're done */
4009 	if (err == Z_NO_ENTRY)
4010 		return (Z_OK);
4011 
4012 	/*
4013 	 * importance might not have a value but we need to validate it here,
4014 	 * so set the default.
4015 	 */
4016 	if (pset_tab.zone_importance[0] == '\0')
4017 		(void) strlcpy(pset_tab.zone_importance, "1",
4018 		    sizeof (pset_tab.zone_importance));
4019 
4020 	/* if pools not enabled, enable them now */
4021 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
4022 		if (pool_set_status(POOL_ENABLED) != PO_SUCCESS)
4023 			return (Z_POOL_ENABLE);
4024 	}
4025 
4026 	if ((pconf = pool_conf_alloc()) == NULL)
4027 		return (zerr_pool(pool_err, err_size, Z_POOL));
4028 
4029 	(void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
4030 
4031 	/*
4032 	 * Check if a valid tmp pool/pset already exists.  If so, we just
4033 	 * reuse it.
4034 	 */
4035 	if ((err = verify_del_tmp_pool(pconf, tmp_name, pool_err, err_size,
4036 	    &pset_tab, &exists)) != Z_OK) {
4037 		pool_conf_free(pconf);
4038 		return (err);
4039 	}
4040 
4041 	if (!exists)
4042 		err = create_tmp_pool(pool_err, err_size, pconf, tmp_name,
4043 		    &pset_tab);
4044 
4045 	pool_conf_free(pconf);
4046 
4047 	if (err != Z_OK)
4048 		return (err);
4049 
4050 	/* Bind the zone to the pool. */
4051 	if (pool_set_binding(tmp_name, P_ZONEID, zoneid) != PO_SUCCESS)
4052 		return (zerr_pool(pool_err, err_size, Z_POOL_BIND));
4053 
4054 	return (Z_OK);
4055 }
4056 
4057 /*
4058  * Attempt to bind to a permanent pool for this zone.  If there is no
4059  * permanent pool configured, we just return Z_OK.
4060  */
4061 int
4062 zonecfg_bind_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
4063     int err_size)
4064 {
4065 	pool_conf_t *poolconf;
4066 	pool_t *pool;
4067 	char poolname[MAXPATHLEN];
4068 	int status;
4069 	int error;
4070 
4071 	/*
4072 	 * Find the pool mentioned in the zone configuration, and bind to it.
4073 	 */
4074 	error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
4075 	if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
4076 		/*
4077 		 * The property is not set on the zone, so the pool
4078 		 * should be bound to the default pool.  But that's
4079 		 * already done by the kernel, so we can just return.
4080 		 */
4081 		return (Z_OK);
4082 	}
4083 	if (error != Z_OK) {
4084 		/*
4085 		 * Not an error, even though it shouldn't be happening.
4086 		 */
4087 		return (Z_OK);
4088 	}
4089 	/*
4090 	 * Don't do anything if pools aren't enabled.
4091 	 */
4092 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4093 		return (Z_POOLS_NOT_ACTIVE);
4094 
4095 	/*
4096 	 * Try to provide a sane error message if the requested pool doesn't
4097 	 * exist.
4098 	 */
4099 	if ((poolconf = pool_conf_alloc()) == NULL)
4100 		return (zerr_pool(pool_err, err_size, Z_POOL));
4101 
4102 	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
4103 	    PO_SUCCESS) {
4104 		pool_conf_free(poolconf);
4105 		return (zerr_pool(pool_err, err_size, Z_POOL));
4106 	}
4107 	pool = pool_get_pool(poolconf, poolname);
4108 	(void) pool_conf_close(poolconf);
4109 	pool_conf_free(poolconf);
4110 	if (pool == NULL)
4111 		return (Z_NO_POOL);
4112 
4113 	/*
4114 	 * Bind the zone to the pool.
4115 	 */
4116 	if (pool_set_binding(poolname, P_ZONEID, zoneid) != PO_SUCCESS) {
4117 		/* if bind fails, return poolname for the error msg */
4118 		(void) strlcpy(pool_err, poolname, err_size);
4119 		return (Z_POOL_BIND);
4120 	}
4121 
4122 	return (Z_OK);
4123 }
4124 
4125 
4126 static boolean_t
4127 svc_enabled(char *svc_name)
4128 {
4129 	scf_simple_prop_t	*prop;
4130 	boolean_t		found = B_FALSE;
4131 
4132 	prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL,
4133 	    SCF_PROPERTY_ENABLED);
4134 
4135 	if (scf_simple_prop_numvalues(prop) == 1 &&
4136 	    *scf_simple_prop_next_boolean(prop) != 0)
4137 		found = B_TRUE;
4138 
4139 	scf_simple_prop_free(prop);
4140 
4141 	return (found);
4142 }
4143 
4144 /*
4145  * If the zone has capped-memory, make sure the rcap service is enabled.
4146  */
4147 int
4148 zonecfg_enable_rcapd(char *err, int size)
4149 {
4150 	if (!svc_enabled(RCAP_SERVICE) &&
4151 	    smf_enable_instance(RCAP_SERVICE, 0) == -1) {
4152 		(void) strlcpy(err, scf_strerror(scf_error()), size);
4153 		return (Z_SYSTEM);
4154 	}
4155 
4156 	return (Z_OK);
4157 }
4158 
4159 /*
4160  * Return true if pset has cpu range specified and poold is not enabled.
4161  */
4162 boolean_t
4163 zonecfg_warn_poold(zone_dochandle_t handle)
4164 {
4165 	struct zone_psettab pset_tab;
4166 	int min, max;
4167 	int err;
4168 
4169 	err = zonecfg_lookup_pset(handle, &pset_tab);
4170 
4171 	/* if no temporary pool configured, we're done */
4172 	if (err == Z_NO_ENTRY)
4173 		return (B_FALSE);
4174 
4175 	min = atoi(pset_tab.zone_ncpu_min);
4176 	max = atoi(pset_tab.zone_ncpu_max);
4177 
4178 	/* range not specified, no need for poold */
4179 	if (min == max)
4180 		return (B_FALSE);
4181 
4182 	/* we have a range, check if poold service is enabled */
4183 	if (svc_enabled(POOLD_SERVICE))
4184 		return (B_FALSE);
4185 
4186 	return (B_TRUE);
4187 }
4188 
4189 static int
4190 get_pool_sched_class(char *poolname, char *class, int clsize)
4191 {
4192 	int status;
4193 	pool_conf_t *poolconf;
4194 	pool_t *pool;
4195 	pool_elem_t *pe;
4196 	pool_value_t *pv = pool_value_alloc();
4197 	const char *sched_str;
4198 
4199 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4200 		return (Z_NO_POOL);
4201 
4202 	if ((poolconf = pool_conf_alloc()) == NULL)
4203 		return (Z_NO_POOL);
4204 
4205 	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
4206 	    PO_SUCCESS) {
4207 		pool_conf_free(poolconf);
4208 		return (Z_NO_POOL);
4209 	}
4210 
4211 	if ((pool = pool_get_pool(poolconf, poolname)) == NULL) {
4212 		(void) pool_conf_close(poolconf);
4213 		pool_conf_free(poolconf);
4214 		return (Z_NO_POOL);
4215 	}
4216 
4217 	pe = pool_to_elem(poolconf, pool);
4218 	if (pool_get_property(poolconf, pe, "pool.scheduler", pv)
4219 	    != POC_INVAL) {
4220 		(void) pool_value_get_string(pv, &sched_str);
4221 		if (strlcpy(class, sched_str, clsize) >= clsize)
4222 			return (Z_TOO_BIG);
4223 	}
4224 
4225 	(void) pool_conf_close(poolconf);
4226 	pool_conf_free(poolconf);
4227 	return (Z_OK);
4228 }
4229 
4230 /*
4231  * Get the default scheduling class for the zone.  This will either be the
4232  * class set on the zone's pool or the system default scheduling class.
4233  */
4234 int
4235 zonecfg_get_dflt_sched_class(zone_dochandle_t handle, char *class, int clsize)
4236 {
4237 	char poolname[MAXPATHLEN];
4238 
4239 	if (zonecfg_get_pool(handle, poolname, sizeof (poolname)) == Z_OK) {
4240 		/* check if the zone's pool specified a sched class */
4241 		if (get_pool_sched_class(poolname, class, clsize) == Z_OK)
4242 			return (Z_OK);
4243 	}
4244 
4245 	if (priocntl(0, 0, PC_GETDFLCL, class, (uint64_t)clsize) == -1)
4246 		return (Z_TOO_BIG);
4247 
4248 	return (Z_OK);
4249 }
4250 
4251 int
4252 zonecfg_setfsent(zone_dochandle_t handle)
4253 {
4254 	return (zonecfg_setent(handle));
4255 }
4256 
4257 int
4258 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr)
4259 {
4260 	xmlNodePtr cur, options;
4261 	char options_str[MAX_MNTOPT_STR];
4262 	int err;
4263 
4264 	if (handle == NULL)
4265 		return (Z_INVAL);
4266 
4267 	if ((cur = handle->zone_dh_cur) == NULL)
4268 		return (Z_NO_ENTRY);
4269 
4270 	for (; cur != NULL; cur = cur->next)
4271 		if (!xmlStrcmp(cur->name, DTD_ELEM_FS))
4272 			break;
4273 	if (cur == NULL) {
4274 		handle->zone_dh_cur = handle->zone_dh_top;
4275 		return (Z_NO_ENTRY);
4276 	}
4277 
4278 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
4279 	    sizeof (tabptr->zone_fs_special))) != Z_OK) {
4280 		handle->zone_dh_cur = handle->zone_dh_top;
4281 		return (err);
4282 	}
4283 
4284 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
4285 	    sizeof (tabptr->zone_fs_raw))) != Z_OK) {
4286 		handle->zone_dh_cur = handle->zone_dh_top;
4287 		return (err);
4288 	}
4289 
4290 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
4291 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
4292 		handle->zone_dh_cur = handle->zone_dh_top;
4293 		return (err);
4294 	}
4295 
4296 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
4297 	    sizeof (tabptr->zone_fs_type))) != Z_OK) {
4298 		handle->zone_dh_cur = handle->zone_dh_top;
4299 		return (err);
4300 	}
4301 
4302 	/* OK for options to be NULL */
4303 	tabptr->zone_fs_options = NULL;
4304 	for (options = cur->xmlChildrenNode; options != NULL;
4305 	    options = options->next) {
4306 		if (fetchprop(options, DTD_ATTR_NAME, options_str,
4307 		    sizeof (options_str)) != Z_OK)
4308 			break;
4309 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
4310 			break;
4311 	}
4312 
4313 	handle->zone_dh_cur = cur->next;
4314 	return (Z_OK);
4315 }
4316 
4317 int
4318 zonecfg_endfsent(zone_dochandle_t handle)
4319 {
4320 	return (zonecfg_endent(handle));
4321 }
4322 
4323 int
4324 zonecfg_setipdent(zone_dochandle_t handle)
4325 {
4326 	return (zonecfg_setent(handle));
4327 }
4328 
4329 int
4330 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr)
4331 {
4332 	xmlNodePtr cur;
4333 	int err;
4334 
4335 	if (handle == NULL)
4336 		return (Z_INVAL);
4337 
4338 	if ((cur = handle->zone_dh_cur) == NULL)
4339 		return (Z_NO_ENTRY);
4340 
4341 	for (; cur != NULL; cur = cur->next)
4342 		if (!xmlStrcmp(cur->name, DTD_ELEM_IPD))
4343 			break;
4344 	if (cur == NULL) {
4345 		handle->zone_dh_cur = handle->zone_dh_top;
4346 		return (Z_NO_ENTRY);
4347 	}
4348 
4349 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
4350 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
4351 		handle->zone_dh_cur = handle->zone_dh_top;
4352 		return (err);
4353 	}
4354 
4355 	handle->zone_dh_cur = cur->next;
4356 	return (Z_OK);
4357 }
4358 
4359 int
4360 zonecfg_endipdent(zone_dochandle_t handle)
4361 {
4362 	return (zonecfg_endent(handle));
4363 }
4364 
4365 int
4366 zonecfg_setnwifent(zone_dochandle_t handle)
4367 {
4368 	return (zonecfg_setent(handle));
4369 }
4370 
4371 int
4372 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
4373 {
4374 	xmlNodePtr cur;
4375 	int err;
4376 
4377 	if (handle == NULL)
4378 		return (Z_INVAL);
4379 
4380 	if ((cur = handle->zone_dh_cur) == NULL)
4381 		return (Z_NO_ENTRY);
4382 
4383 	for (; cur != NULL; cur = cur->next)
4384 		if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
4385 			break;
4386 	if (cur == NULL) {
4387 		handle->zone_dh_cur = handle->zone_dh_top;
4388 		return (Z_NO_ENTRY);
4389 	}
4390 
4391 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
4392 	    sizeof (tabptr->zone_nwif_address))) != Z_OK) {
4393 		handle->zone_dh_cur = handle->zone_dh_top;
4394 		return (err);
4395 	}
4396 
4397 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
4398 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
4399 		handle->zone_dh_cur = handle->zone_dh_top;
4400 		return (err);
4401 	}
4402 
4403 	if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
4404 	    tabptr->zone_nwif_defrouter,
4405 	    sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
4406 		handle->zone_dh_cur = handle->zone_dh_top;
4407 		return (err);
4408 	}
4409 
4410 	handle->zone_dh_cur = cur->next;
4411 	return (Z_OK);
4412 }
4413 
4414 int
4415 zonecfg_endnwifent(zone_dochandle_t handle)
4416 {
4417 	return (zonecfg_endent(handle));
4418 }
4419 
4420 int
4421 zonecfg_setdevent(zone_dochandle_t handle)
4422 {
4423 	return (zonecfg_setent(handle));
4424 }
4425 
4426 int
4427 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
4428 {
4429 	xmlNodePtr cur;
4430 	int err;
4431 
4432 	if (handle == NULL)
4433 		return (Z_INVAL);
4434 
4435 	if ((cur = handle->zone_dh_cur) == NULL)
4436 		return (Z_NO_ENTRY);
4437 
4438 	for (; cur != NULL; cur = cur->next)
4439 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
4440 			break;
4441 	if (cur == NULL) {
4442 		handle->zone_dh_cur = handle->zone_dh_top;
4443 		return (Z_NO_ENTRY);
4444 	}
4445 
4446 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
4447 	    sizeof (tabptr->zone_dev_match))) != Z_OK) {
4448 		handle->zone_dh_cur = handle->zone_dh_top;
4449 		return (err);
4450 	}
4451 
4452 	handle->zone_dh_cur = cur->next;
4453 	return (Z_OK);
4454 }
4455 
4456 int
4457 zonecfg_enddevent(zone_dochandle_t handle)
4458 {
4459 	return (zonecfg_endent(handle));
4460 }
4461 
4462 int
4463 zonecfg_setrctlent(zone_dochandle_t handle)
4464 {
4465 	return (zonecfg_setent(handle));
4466 }
4467 
4468 int
4469 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
4470 {
4471 	xmlNodePtr cur, val;
4472 	struct zone_rctlvaltab *valptr;
4473 	int err;
4474 
4475 	if (handle == NULL)
4476 		return (Z_INVAL);
4477 
4478 	if ((cur = handle->zone_dh_cur) == NULL)
4479 		return (Z_NO_ENTRY);
4480 
4481 	for (; cur != NULL; cur = cur->next)
4482 		if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL))
4483 			break;
4484 	if (cur == NULL) {
4485 		handle->zone_dh_cur = handle->zone_dh_top;
4486 		return (Z_NO_ENTRY);
4487 	}
4488 
4489 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name,
4490 	    sizeof (tabptr->zone_rctl_name))) != Z_OK) {
4491 		handle->zone_dh_cur = handle->zone_dh_top;
4492 		return (err);
4493 	}
4494 
4495 	tabptr->zone_rctl_valptr = NULL;
4496 	for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
4497 		valptr = (struct zone_rctlvaltab *)malloc(
4498 		    sizeof (struct zone_rctlvaltab));
4499 		if (valptr == NULL)
4500 			return (Z_NOMEM);
4501 		if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv,
4502 		    sizeof (valptr->zone_rctlval_priv)) != Z_OK)
4503 			break;
4504 		if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit,
4505 		    sizeof (valptr->zone_rctlval_limit)) != Z_OK)
4506 			break;
4507 		if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action,
4508 		    sizeof (valptr->zone_rctlval_action)) != Z_OK)
4509 			break;
4510 		if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK)
4511 			break;
4512 	}
4513 
4514 	handle->zone_dh_cur = cur->next;
4515 	return (Z_OK);
4516 }
4517 
4518 int
4519 zonecfg_endrctlent(zone_dochandle_t handle)
4520 {
4521 	return (zonecfg_endent(handle));
4522 }
4523 
4524 int
4525 zonecfg_setattrent(zone_dochandle_t handle)
4526 {
4527 	return (zonecfg_setent(handle));
4528 }
4529 
4530 int
4531 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr)
4532 {
4533 	xmlNodePtr cur;
4534 	int err;
4535 
4536 	if (handle == NULL)
4537 		return (Z_INVAL);
4538 
4539 	if ((cur = handle->zone_dh_cur) == NULL)
4540 		return (Z_NO_ENTRY);
4541 
4542 	for (; cur != NULL; cur = cur->next)
4543 		if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR))
4544 			break;
4545 	if (cur == NULL) {
4546 		handle->zone_dh_cur = handle->zone_dh_top;
4547 		return (Z_NO_ENTRY);
4548 	}
4549 
4550 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
4551 	    sizeof (tabptr->zone_attr_name))) != Z_OK) {
4552 		handle->zone_dh_cur = handle->zone_dh_top;
4553 		return (err);
4554 	}
4555 
4556 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
4557 	    sizeof (tabptr->zone_attr_type))) != Z_OK) {
4558 		handle->zone_dh_cur = handle->zone_dh_top;
4559 		return (err);
4560 	}
4561 
4562 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
4563 	    sizeof (tabptr->zone_attr_value))) != Z_OK) {
4564 		handle->zone_dh_cur = handle->zone_dh_top;
4565 		return (err);
4566 	}
4567 
4568 	handle->zone_dh_cur = cur->next;
4569 	return (Z_OK);
4570 }
4571 
4572 int
4573 zonecfg_endattrent(zone_dochandle_t handle)
4574 {
4575 	return (zonecfg_endent(handle));
4576 }
4577 
4578 /*
4579  * The privileges available on the system and described in privileges(5)
4580  * fall into four categories with respect to non-global zones:
4581  *
4582  *      Default set of privileges considered safe for all non-global
4583  *      zones.  These privileges are "safe" in the sense that a
4584  *      privileged process in the zone cannot affect processes in any
4585  *      other zone on the system.
4586  *
4587  *      Set of privileges not currently permitted within a non-global
4588  *      zone.  These privileges are considered by default, "unsafe,"
4589  *      and include ones which affect global resources (such as the
4590  *      system clock or physical memory) or are overly broad and cover
4591  *      more than one mechanism in the system.  In other cases, there
4592  *      has not been sufficient virtualization in the parts of the
4593  *      system the privilege covers to allow its use within a
4594  *      non-global zone.
4595  *
4596  *      Set of privileges required in order to get a zone booted and
4597  *      init(1M) started.  These cannot be removed from the zone's
4598  *      privilege set.
4599  *
4600  * All other privileges are optional and are potentially useful for
4601  * processes executing inside a non-global zone.
4602  *
4603  * When privileges are added to the system, a determination needs to be
4604  * made as to which category the privilege belongs to.  Ideally,
4605  * privileges should be fine-grained enough and the mechanisms they cover
4606  * virtualized enough so that they can be made available to non-global
4607  * zones.
4608  */
4609 
4610 /*
4611  * Define some of the tokens that priv_str_to_set(3C) recognizes.  Since
4612  * the privilege string separator can be any character, although it is
4613  * usually a comma character, define these here as well in the event that
4614  * they change or are augmented in the future.
4615  */
4616 #define	BASIC_TOKEN		"basic"
4617 #define	DEFAULT_TOKEN		"default"
4618 #define	ZONE_TOKEN		"zone"
4619 #define	TOKEN_PRIV_CHAR		','
4620 #define	TOKEN_PRIV_STR		","
4621 
4622 typedef struct priv_node {
4623 	struct priv_node	*pn_next;	/* Next privilege */
4624 	char			*pn_priv;	/* Privileges name */
4625 } priv_node_t;
4626 
4627 /* Privileges lists can differ across brands */
4628 typedef struct priv_lists {
4629 	/* Privileges considered safe for all non-global zones of a brand */
4630 	struct priv_node	*pl_default;
4631 
4632 	/* Privileges not permitted for all non-global zones of a brand */
4633 	struct priv_node	*pl_prohibited;
4634 
4635 	/* Privileges required for all non-global zones of a brand */
4636 	struct priv_node	*pl_required;
4637 
4638 	/*
4639 	 * ip-type of the zone these privileges lists apply to.
4640 	 * It is used to pass ip-type to the callback function,
4641 	 * priv_lists_cb, which has no way of getting the ip-type.
4642 	 */
4643 	const char		*pl_iptype;
4644 } priv_lists_t;
4645 
4646 static int
4647 priv_lists_cb(void *data, priv_iter_t *priv_iter)
4648 {
4649 	priv_lists_t *plp = (priv_lists_t *)data;
4650 	priv_node_t *pnp;
4651 
4652 	/* Skip this privilege if ip-type does not match */
4653 	if ((strcmp(priv_iter->pi_iptype, "all") != 0) &&
4654 	    (strcmp(priv_iter->pi_iptype, plp->pl_iptype) != 0))
4655 		return (0);
4656 
4657 	/* Allocate a new priv list node. */
4658 	if ((pnp = malloc(sizeof (*pnp))) == NULL)
4659 		return (-1);
4660 	if ((pnp->pn_priv = strdup(priv_iter->pi_name)) == NULL) {
4661 		free(pnp);
4662 		return (-1);
4663 	}
4664 
4665 	/* Insert the new priv list node into the right list */
4666 	if (strcmp(priv_iter->pi_set, "default") == 0) {
4667 		pnp->pn_next = plp->pl_default;
4668 		plp->pl_default = pnp;
4669 	} else if (strcmp(priv_iter->pi_set, "prohibited") == 0) {
4670 		pnp->pn_next = plp->pl_prohibited;
4671 		plp->pl_prohibited = pnp;
4672 	} else if (strcmp(priv_iter->pi_set, "required") == 0) {
4673 		pnp->pn_next = plp->pl_required;
4674 		plp->pl_required = pnp;
4675 	} else {
4676 		free(pnp->pn_priv);
4677 		free(pnp);
4678 		return (-1);
4679 	}
4680 	return (0);
4681 }
4682 
4683 static void
4684 priv_lists_destroy(priv_lists_t *plp)
4685 {
4686 	priv_node_t *pnp;
4687 
4688 	assert(plp != NULL);
4689 
4690 	while ((pnp = plp->pl_default) != NULL) {
4691 		plp->pl_default = pnp->pn_next;
4692 		free(pnp->pn_priv);
4693 		free(pnp);
4694 	}
4695 	while ((pnp = plp->pl_prohibited) != NULL) {
4696 		plp->pl_prohibited = pnp->pn_next;
4697 		free(pnp->pn_priv);
4698 		free(pnp);
4699 	}
4700 	while ((pnp = plp->pl_required) != NULL) {
4701 		plp->pl_required = pnp->pn_next;
4702 		free(pnp->pn_priv);
4703 		free(pnp);
4704 	}
4705 	free(plp);
4706 }
4707 
4708 static int
4709 priv_lists_create(zone_dochandle_t handle, priv_lists_t **plpp,
4710     const char *curr_iptype)
4711 {
4712 	priv_lists_t *plp;
4713 	brand_handle_t bh;
4714 	char brand[MAXNAMELEN];
4715 
4716 	if (handle != NULL) {
4717 		if (zonecfg_get_brand(handle, brand, sizeof (brand)) != 0)
4718 			return (Z_BRAND_ERROR);
4719 	} else {
4720 		(void) strlcpy(brand, NATIVE_BRAND_NAME, MAXNAMELEN);
4721 	}
4722 
4723 	if ((bh = brand_open(brand)) == NULL)
4724 		return (Z_BRAND_ERROR);
4725 
4726 	if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) {
4727 		brand_close(bh);
4728 		return (Z_NOMEM);
4729 	}
4730 
4731 	plp->pl_iptype = curr_iptype;
4732 
4733 	/* construct the privilege lists */
4734 	if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) {
4735 		priv_lists_destroy(plp);
4736 		brand_close(bh);
4737 		return (Z_BRAND_ERROR);
4738 	}
4739 
4740 	brand_close(bh);
4741 	*plpp = plp;
4742 	return (Z_OK);
4743 }
4744 
4745 static int
4746 get_default_privset(priv_set_t *privs, priv_lists_t *plp)
4747 {
4748 	priv_node_t *pnp;
4749 	priv_set_t *basic;
4750 
4751 	basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL);
4752 	if (basic == NULL)
4753 		return (errno == ENOMEM ? Z_NOMEM : Z_INVAL);
4754 
4755 	priv_union(basic, privs);
4756 	priv_freeset(basic);
4757 
4758 	for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) {
4759 		if (priv_addset(privs, pnp->pn_priv) != 0)
4760 			return (Z_INVAL);
4761 	}
4762 
4763 	return (Z_OK);
4764 }
4765 
4766 int
4767 zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype)
4768 {
4769 	priv_lists_t *plp;
4770 	int ret;
4771 
4772 	if ((ret = priv_lists_create(NULL, &plp, curr_iptype)) != Z_OK)
4773 		return (ret);
4774 	ret = get_default_privset(privs, plp);
4775 	priv_lists_destroy(plp);
4776 	return (ret);
4777 }
4778 
4779 void
4780 append_priv_token(char *priv, char *str, size_t strlen)
4781 {
4782 	if (*str != '\0')
4783 		(void) strlcat(str, TOKEN_PRIV_STR, strlen);
4784 	(void) strlcat(str, priv, strlen);
4785 }
4786 
4787 /*
4788  * Verify that the supplied string is a valid privilege limit set for a
4789  * non-global zone.  This string must not only be acceptable to
4790  * priv_str_to_set(3C) which parses it, but it also must resolve to a
4791  * privilege set that includes certain required privileges and lacks
4792  * certain prohibited privileges.
4793  */
4794 static int
4795 verify_privset(char *privbuf, priv_set_t *privs, char **privname,
4796     boolean_t add_default, priv_lists_t *plp)
4797 {
4798 	priv_node_t *pnp;
4799 	char *tmp, *cp, *lasts;
4800 	size_t len;
4801 	priv_set_t *mergeset;
4802 	const char *token;
4803 
4804 	/*
4805 	 * The verification of the privilege string occurs in several
4806 	 * phases.  In the first phase, the supplied string is scanned for
4807 	 * the ZONE_TOKEN token which is not support as part of the
4808 	 * "limitpriv" property.
4809 	 *
4810 	 * Duplicate the supplied privilege string since strtok_r(3C)
4811 	 * tokenizes its input by null-terminating the tokens.
4812 	 */
4813 	if ((tmp = strdup(privbuf)) == NULL)
4814 		return (Z_NOMEM);
4815 	for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL;
4816 	    cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) {
4817 		if (strcmp(cp, ZONE_TOKEN) == 0) {
4818 			free(tmp);
4819 			if ((*privname = strdup(ZONE_TOKEN)) == NULL)
4820 				return (Z_NOMEM);
4821 			else
4822 				return (Z_PRIV_UNKNOWN);
4823 		}
4824 	}
4825 	free(tmp);
4826 
4827 	if (add_default) {
4828 		/*
4829 		 * If DEFAULT_TOKEN was specified, a string needs to be
4830 		 * built containing the privileges from the default, safe
4831 		 * set along with those of the "limitpriv" property.
4832 		 */
4833 		len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2;
4834 
4835 		for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
4836 			len += strlen(pnp->pn_priv) + 1;
4837 		tmp = alloca(len);
4838 		*tmp = '\0';
4839 
4840 		append_priv_token(BASIC_TOKEN, tmp, len);
4841 		for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
4842 			append_priv_token(pnp->pn_priv, tmp, len);
4843 		(void) strlcat(tmp, TOKEN_PRIV_STR, len);
4844 		(void) strlcat(tmp, privbuf, len);
4845 	} else {
4846 		tmp = privbuf;
4847 	}
4848 
4849 
4850 	/*
4851 	 * In the next phase, attempt to convert the merged privilege
4852 	 * string into a privilege set.  In the case of an error, either
4853 	 * there was a memory allocation failure or there was an invalid
4854 	 * privilege token in the string.  In either case, return an
4855 	 * appropriate error code but in the event of an invalid token,
4856 	 * allocate a string containing its name and return that back to
4857 	 * the caller.
4858 	 */
4859 	mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token);
4860 	if (mergeset == NULL) {
4861 		if (token == NULL)
4862 			return (Z_NOMEM);
4863 		if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL)
4864 			*cp = '\0';
4865 		if ((*privname = strdup(token)) == NULL)
4866 			return (Z_NOMEM);
4867 		else
4868 			return (Z_PRIV_UNKNOWN);
4869 	}
4870 
4871 	/*
4872 	 * Next, verify that none of the prohibited zone privileges are
4873 	 * present in the merged privilege set.
4874 	 */
4875 	for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) {
4876 		if (priv_ismember(mergeset, pnp->pn_priv)) {
4877 			priv_freeset(mergeset);
4878 			if ((*privname = strdup(pnp->pn_priv)) == NULL)
4879 				return (Z_NOMEM);
4880 			else
4881 				return (Z_PRIV_PROHIBITED);
4882 		}
4883 	}
4884 
4885 	/*
4886 	 * Finally, verify that all of the required zone privileges are
4887 	 * present in the merged privilege set.
4888 	 */
4889 	for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) {
4890 		if (!priv_ismember(mergeset, pnp->pn_priv)) {
4891 			priv_freeset(mergeset);
4892 			if ((*privname = strdup(pnp->pn_priv)) == NULL)
4893 				return (Z_NOMEM);
4894 			else
4895 				return (Z_PRIV_REQUIRED);
4896 		}
4897 	}
4898 
4899 	priv_copyset(mergeset, privs);
4900 	priv_freeset(mergeset);
4901 	return (Z_OK);
4902 }
4903 
4904 /*
4905  * Fill in the supplied privilege set with either the default, safe set of
4906  * privileges suitable for a non-global zone, or one based on the
4907  * "limitpriv" property in the zone's configuration.
4908  *
4909  * In the event of an invalid privilege specification in the
4910  * configuration, a string is allocated and returned containing the
4911  * "privilege" causing the issue.  It is the caller's responsibility to
4912  * free this memory when it is done with it.
4913  */
4914 int
4915 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs,
4916     char **privname)
4917 {
4918 	priv_lists_t *plp;
4919 	char *cp, *limitpriv = NULL;
4920 	int err, limitlen;
4921 	zone_iptype_t iptype;
4922 	const char *curr_iptype;
4923 
4924 	/*
4925 	 * Attempt to lookup the "limitpriv" property.  If it does not
4926 	 * exist or matches the string DEFAULT_TOKEN exactly, then the
4927 	 * default, safe privilege set is returned.
4928 	 */
4929 	if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK)
4930 		return (err);
4931 
4932 	if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
4933 		return (err);
4934 
4935 	switch (iptype) {
4936 	case ZS_SHARED:
4937 		curr_iptype = "shared";
4938 		break;
4939 	case ZS_EXCLUSIVE:
4940 		curr_iptype = "exclusive";
4941 		break;
4942 	}
4943 
4944 	if ((err = priv_lists_create(handle, &plp, curr_iptype)) != Z_OK)
4945 		return (err);
4946 
4947 	limitlen = strlen(limitpriv);
4948 	if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) {
4949 		free(limitpriv);
4950 		err = get_default_privset(privs, plp);
4951 		priv_lists_destroy(plp);
4952 		return (err);
4953 	}
4954 
4955 	/*
4956 	 * Check if the string DEFAULT_TOKEN is the first token in a list
4957 	 * of privileges.
4958 	 */
4959 	cp = strchr(limitpriv, TOKEN_PRIV_CHAR);
4960 	if (cp != NULL &&
4961 	    strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0)
4962 		err = verify_privset(cp + 1, privs, privname, B_TRUE, plp);
4963 	else
4964 		err = verify_privset(limitpriv, privs, privname, B_FALSE, plp);
4965 
4966 	free(limitpriv);
4967 	priv_lists_destroy(plp);
4968 	return (err);
4969 }
4970 
4971 int
4972 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
4973 {
4974 	zone_dochandle_t handle;
4975 	boolean_t found = B_FALSE;
4976 	struct zoneent *ze;
4977 	FILE *cookie;
4978 	int err;
4979 	char *cp;
4980 
4981 	if (zone_name == NULL)
4982 		return (Z_INVAL);
4983 
4984 	(void) strlcpy(zonepath, zonecfg_root, rp_sz);
4985 	cp = zonepath + strlen(zonepath);
4986 	while (cp > zonepath && cp[-1] == '/')
4987 		*--cp = '\0';
4988 
4989 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
4990 		if (zonepath[0] == '\0')
4991 			(void) strlcpy(zonepath, "/", rp_sz);
4992 		return (Z_OK);
4993 	}
4994 
4995 	/*
4996 	 * First check the index file.  Because older versions did not have
4997 	 * a copy of the zone path, allow for it to be zero length, in which
4998 	 * case we ignore this result and fall back to the XML files.
4999 	 */
5000 	cookie = setzoneent();
5001 	while ((ze = getzoneent_private(cookie)) != NULL) {
5002 		if (strcmp(ze->zone_name, zone_name) == 0) {
5003 			found = B_TRUE;
5004 			if (ze->zone_path[0] != '\0')
5005 				(void) strlcpy(cp, ze->zone_path,
5006 				    rp_sz - (cp - zonepath));
5007 		}
5008 		free(ze);
5009 		if (found)
5010 			break;
5011 	}
5012 	endzoneent(cookie);
5013 	if (found && *cp != '\0')
5014 		return (Z_OK);
5015 
5016 	/* Fall back to the XML files. */
5017 	if ((handle = zonecfg_init_handle()) == NULL)
5018 		return (Z_NOMEM);
5019 
5020 	/*
5021 	 * Check the snapshot first: if a zone is running, its zonepath
5022 	 * may have changed.
5023 	 */
5024 	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
5025 		if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) {
5026 			zonecfg_fini_handle(handle);
5027 			return (err);
5028 		}
5029 	}
5030 	err = zonecfg_get_zonepath(handle, zonepath, rp_sz);
5031 	zonecfg_fini_handle(handle);
5032 	return (err);
5033 }
5034 
5035 int
5036 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz)
5037 {
5038 	int err;
5039 
5040 	/* This function makes sense for non-global zones only. */
5041 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5042 		return (Z_BOGUS_ZONE_NAME);
5043 	if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK)
5044 		return (err);
5045 	if (strlcat(rootpath, "/root", rp_sz) >= rp_sz)
5046 		return (Z_TOO_BIG);
5047 	return (Z_OK);
5048 }
5049 
5050 int
5051 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz)
5052 {
5053 	int err;
5054 	zone_dochandle_t handle;
5055 	char myzone[MAXNAMELEN];
5056 	int myzoneid = getzoneid();
5057 
5058 	/*
5059 	 * If we are not in the global zone, then we don't have the zone
5060 	 * .xml files with the brand name available.  Thus, we are going to
5061 	 * have to ask the kernel for the information.
5062 	 */
5063 	if (myzoneid != GLOBAL_ZONEID) {
5064 		if (is_system_labeled()) {
5065 			(void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz);
5066 			return (Z_OK);
5067 		}
5068 		if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone,
5069 		    sizeof (myzone)) < 0)
5070 			return (Z_NO_ZONE);
5071 		if (strncmp(zone_name, myzone, MAXNAMELEN) != NULL)
5072 			return (Z_NO_ZONE);
5073 		err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz);
5074 		if (err < 0)
5075 			return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5076 		return (Z_OK);
5077 	}
5078 
5079 	if (strcmp(zone_name, "global") == NULL) {
5080 		(void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz);
5081 		return (Z_OK);
5082 	}
5083 	if ((handle = zonecfg_init_handle()) == NULL)
5084 		return (Z_NOMEM);
5085 
5086 	err = zonecfg_get_handle((char *)zone_name, handle);
5087 	if (err == Z_OK)
5088 		err = zonecfg_get_brand(handle, brandname, rp_sz);
5089 
5090 	zonecfg_fini_handle(handle);
5091 	return (err);
5092 }
5093 
5094 /*
5095  * Return the appropriate root for the active /dev.
5096  * For normal zone, the path is $ZONEPATH/root;
5097  * for scratch zone, the dev path is $ZONEPATH/lu.
5098  */
5099 int
5100 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5101 {
5102 	int err;
5103 	char *suffix;
5104 	zone_state_t state;
5105 
5106 	/* This function makes sense for non-global zones only. */
5107 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5108 		return (Z_BOGUS_ZONE_NAME);
5109 	if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5110 		return (err);
5111 
5112 	if (zone_get_state(zone_name, &state) == Z_OK &&
5113 	    state == ZONE_STATE_MOUNTED)
5114 		suffix = "/lu";
5115 	else
5116 		suffix = "/root";
5117 	if (strlcat(devroot, suffix, rp_sz) >= rp_sz)
5118 		return (Z_TOO_BIG);
5119 	return (Z_OK);
5120 }
5121 
5122 static zone_state_t
5123 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state)
5124 {
5125 	char zoneroot[MAXPATHLEN];
5126 	size_t zlen;
5127 
5128 	assert(kernel_state <= ZONE_MAX_STATE);
5129 	switch (kernel_state) {
5130 		case ZONE_IS_UNINITIALIZED:
5131 		case ZONE_IS_INITIALIZED:
5132 			/* The kernel will not return these two states */
5133 			return (ZONE_STATE_READY);
5134 		case ZONE_IS_READY:
5135 			/*
5136 			 * If the zone's root is mounted on $ZONEPATH/lu, then
5137 			 * it's a mounted scratch zone.
5138 			 */
5139 			if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
5140 			    sizeof (zoneroot)) >= 0) {
5141 				zlen = strlen(zoneroot);
5142 				if (zlen > 3 &&
5143 				    strcmp(zoneroot + zlen - 3, "/lu") == 0)
5144 					return (ZONE_STATE_MOUNTED);
5145 			}
5146 			return (ZONE_STATE_READY);
5147 		case ZONE_IS_BOOTING:
5148 		case ZONE_IS_RUNNING:
5149 			return (ZONE_STATE_RUNNING);
5150 		case ZONE_IS_SHUTTING_DOWN:
5151 		case ZONE_IS_EMPTY:
5152 			return (ZONE_STATE_SHUTTING_DOWN);
5153 		case ZONE_IS_DOWN:
5154 		case ZONE_IS_DYING:
5155 		case ZONE_IS_DEAD:
5156 		default:
5157 			return (ZONE_STATE_DOWN);
5158 	}
5159 	/* NOTREACHED */
5160 }
5161 
5162 int
5163 zone_get_state(char *zone_name, zone_state_t *state_num)
5164 {
5165 	zone_status_t status;
5166 	zoneid_t zone_id;
5167 	struct zoneent *ze;
5168 	boolean_t found = B_FALSE;
5169 	FILE *cookie;
5170 	char kernzone[ZONENAME_MAX];
5171 	FILE *fp;
5172 
5173 	if (zone_name == NULL)
5174 		return (Z_INVAL);
5175 
5176 	/*
5177 	 * If we're looking at an alternate root, then we need to query the
5178 	 * kernel using the scratch zone name.
5179 	 */
5180 	zone_id = -1;
5181 	if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
5182 		if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
5183 			if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
5184 			    kernzone, sizeof (kernzone)) == 0)
5185 				zone_id = getzoneidbyname(kernzone);
5186 			zonecfg_close_scratch(fp);
5187 		}
5188 	} else {
5189 		zone_id = getzoneidbyname(zone_name);
5190 	}
5191 
5192 	/* check to see if zone is running */
5193 	if (zone_id != -1 &&
5194 	    zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
5195 	    sizeof (status)) >= 0) {
5196 		*state_num = kernel_state_to_user_state(zone_id, status);
5197 		return (Z_OK);
5198 	}
5199 
5200 	cookie = setzoneent();
5201 	while ((ze = getzoneent_private(cookie)) != NULL) {
5202 		if (strcmp(ze->zone_name, zone_name) == 0) {
5203 			found = B_TRUE;
5204 			*state_num = ze->zone_state;
5205 		}
5206 		free(ze);
5207 		if (found)
5208 			break;
5209 	}
5210 	endzoneent(cookie);
5211 	return ((found) ? Z_OK : Z_NO_ZONE);
5212 }
5213 
5214 int
5215 zone_set_state(char *zone, zone_state_t state)
5216 {
5217 	struct zoneent ze;
5218 
5219 	if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
5220 	    state != ZONE_STATE_INCOMPLETE)
5221 		return (Z_INVAL);
5222 
5223 	bzero(&ze, sizeof (ze));
5224 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
5225 	ze.zone_state = state;
5226 	(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
5227 	return (putzoneent(&ze, PZE_MODIFY));
5228 }
5229 
5230 /*
5231  * Get id (if any) for specified zone.  There are four possible outcomes:
5232  * - If the string corresponds to the numeric id of an active (booted)
5233  *   zone, sets *zip to the zone id and returns 0.
5234  * - If the string corresponds to the name of an active (booted) zone,
5235  *   sets *zip to the zone id and returns 0.
5236  * - If the string is a name in the configuration but is not booted,
5237  *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
5238  * - Otherwise, leaves *zip unchanged and returns -1.
5239  *
5240  * This function acts as an auxiliary filter on the function of the same
5241  * name in libc; the linker binds to this version if libzonecfg exists,
5242  * and the libc version if it doesn't.  Any changes to this version of
5243  * the function should probably be reflected in the libc version as well.
5244  */
5245 int
5246 zone_get_id(const char *str, zoneid_t *zip)
5247 {
5248 	zone_dochandle_t hdl;
5249 	zoneid_t zoneid;
5250 	char *cp;
5251 	int err;
5252 
5253 	/* first try looking for active zone by id */
5254 	errno = 0;
5255 	zoneid = (zoneid_t)strtol(str, &cp, 0);
5256 	if (errno == 0 && cp != str && *cp == '\0' &&
5257 	    getzonenamebyid(zoneid, NULL, 0) != -1) {
5258 		*zip = zoneid;
5259 		return (0);
5260 	}
5261 
5262 	/* then look for active zone by name */
5263 	if ((zoneid = getzoneidbyname(str)) != -1) {
5264 		*zip = zoneid;
5265 		return (0);
5266 	}
5267 
5268 	/* if in global zone, try looking up name in configuration database */
5269 	if (getzoneid() != GLOBAL_ZONEID ||
5270 	    (hdl = zonecfg_init_handle()) == NULL)
5271 		return (-1);
5272 
5273 	if (zonecfg_get_handle(str, hdl) == Z_OK) {
5274 		/* zone exists but isn't active */
5275 		*zip = ZONE_ID_UNDEFINED;
5276 		err = 0;
5277 	} else {
5278 		err = -1;
5279 	}
5280 
5281 	zonecfg_fini_handle(hdl);
5282 	return (err);
5283 }
5284 
5285 char *
5286 zone_state_str(zone_state_t state_num)
5287 {
5288 	switch (state_num) {
5289 	case ZONE_STATE_CONFIGURED:
5290 		return (ZONE_STATE_STR_CONFIGURED);
5291 	case ZONE_STATE_INCOMPLETE:
5292 		return (ZONE_STATE_STR_INCOMPLETE);
5293 	case ZONE_STATE_INSTALLED:
5294 		return (ZONE_STATE_STR_INSTALLED);
5295 	case ZONE_STATE_READY:
5296 		return (ZONE_STATE_STR_READY);
5297 	case ZONE_STATE_MOUNTED:
5298 		return (ZONE_STATE_STR_MOUNTED);
5299 	case ZONE_STATE_RUNNING:
5300 		return (ZONE_STATE_STR_RUNNING);
5301 	case ZONE_STATE_SHUTTING_DOWN:
5302 		return (ZONE_STATE_STR_SHUTTING_DOWN);
5303 	case ZONE_STATE_DOWN:
5304 		return (ZONE_STATE_STR_DOWN);
5305 	default:
5306 		return ("unknown");
5307 	}
5308 }
5309 
5310 /*
5311  * Given a UUID value, find an associated zone name.  This is intended to be
5312  * used by callers who set up some 'default' name (corresponding to the
5313  * expected name for the zone) in the zonename buffer, and thus the function
5314  * doesn't touch this buffer on failure.
5315  */
5316 int
5317 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen)
5318 {
5319 	FILE *fp;
5320 	struct zoneent *ze;
5321 	uchar_t *uuid;
5322 
5323 	/*
5324 	 * A small amount of subterfuge via casts is necessary here because
5325 	 * libuuid doesn't use const correctly, but we don't want to export
5326 	 * this brokenness to our clients.
5327 	 */
5328 	uuid = (uchar_t *)uuidin;
5329 	if (uuid_is_null(uuid))
5330 		return (Z_NO_ZONE);
5331 	if ((fp = setzoneent()) == NULL)
5332 		return (Z_NO_ZONE);
5333 	while ((ze = getzoneent_private(fp)) != NULL) {
5334 		if (uuid_compare(uuid, ze->zone_uuid) == 0)
5335 			break;
5336 		free(ze);
5337 	}
5338 	endzoneent(fp);
5339 	if (ze != NULL) {
5340 		(void) strlcpy(zonename, ze->zone_name, namelen);
5341 		free(ze);
5342 		return (Z_OK);
5343 	} else {
5344 		return (Z_NO_ZONE);
5345 	}
5346 }
5347 
5348 /*
5349  * Given a zone name, get its UUID.  Returns a "NULL" UUID value if the zone
5350  * exists but the file doesn't have a value set yet.  Returns an error if the
5351  * zone cannot be located.
5352  */
5353 int
5354 zonecfg_get_uuid(const char *zonename, uuid_t uuid)
5355 {
5356 	FILE *fp;
5357 	struct zoneent *ze;
5358 
5359 	if ((fp = setzoneent()) == NULL)
5360 		return (Z_NO_ZONE);
5361 	while ((ze = getzoneent_private(fp)) != NULL) {
5362 		if (strcmp(ze->zone_name, zonename) == 0)
5363 			break;
5364 		free(ze);
5365 	}
5366 	endzoneent(fp);
5367 	if (ze != NULL) {
5368 		uuid_copy(uuid, ze->zone_uuid);
5369 		free(ze);
5370 		return (Z_OK);
5371 	} else {
5372 		return (Z_NO_ZONE);
5373 	}
5374 }
5375 
5376 /*
5377  * File-system convenience functions.
5378  */
5379 boolean_t
5380 zonecfg_valid_fs_type(const char *type)
5381 {
5382 	/*
5383 	 * We already know which FS types don't work.
5384 	 */
5385 	if (strcmp(type, "proc") == 0 ||
5386 	    strcmp(type, "mntfs") == 0 ||
5387 	    strcmp(type, "autofs") == 0 ||
5388 	    strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 ||
5389 	    strcmp(type, "cachefs") == 0)
5390 		return (B_FALSE);
5391 	/*
5392 	 * The caller may do more detailed verification to make sure other
5393 	 * aspects of this filesystem type make sense.
5394 	 */
5395 	return (B_TRUE);
5396 }
5397 
5398 /*
5399  * Generally uninteresting rctl convenience functions.
5400  */
5401 
5402 int
5403 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
5404     rctlblk_t *rctlblk)
5405 {
5406 	unsigned long long ull;
5407 	char *endp;
5408 	rctl_priv_t priv;
5409 	rctl_qty_t limit;
5410 	uint_t action;
5411 
5412 	/* Get the privilege */
5413 	if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
5414 		priv = RCPRIV_BASIC;
5415 	} else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
5416 		priv = RCPRIV_PRIVILEGED;
5417 	} else {
5418 		/* Invalid privilege */
5419 		return (Z_INVAL);
5420 	}
5421 
5422 	/* deal with negative input; strtoull(3c) doesn't do what we want */
5423 	if (rctlval->zone_rctlval_limit[0] == '-')
5424 		return (Z_INVAL);
5425 	/* Get the limit */
5426 	errno = 0;
5427 	ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
5428 	if (errno != 0 || *endp != '\0') {
5429 		/* parse failed */
5430 		return (Z_INVAL);
5431 	}
5432 	limit = (rctl_qty_t)ull;
5433 
5434 	/* Get the action */
5435 	if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
5436 		action = RCTL_LOCAL_NOACTION;
5437 	} else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
5438 		action = RCTL_LOCAL_SIGNAL;
5439 	} else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
5440 		action = RCTL_LOCAL_DENY;
5441 	} else {
5442 		/* Invalid Action */
5443 		return (Z_INVAL);
5444 	}
5445 	rctlblk_set_local_action(rctlblk, action, 0);
5446 	rctlblk_set_privilege(rctlblk, priv);
5447 	rctlblk_set_value(rctlblk, limit);
5448 	return (Z_OK);
5449 }
5450 
5451 static int
5452 rctl_check(const char *rctlname, void *arg)
5453 {
5454 	const char *attrname = arg;
5455 
5456 	/*
5457 	 * Returning 1 here is our signal to zonecfg_is_rctl() that it is
5458 	 * indeed an rctl name recognized by the system.
5459 	 */
5460 	return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
5461 }
5462 
5463 boolean_t
5464 zonecfg_is_rctl(const char *name)
5465 {
5466 	return (rctl_walk(rctl_check, (void *)name) == 1);
5467 }
5468 
5469 boolean_t
5470 zonecfg_valid_rctlname(const char *name)
5471 {
5472 	const char *c;
5473 
5474 	if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
5475 		return (B_FALSE);
5476 	if (strlen(name) == sizeof ("zone.") - 1)
5477 		return (B_FALSE);
5478 	for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
5479 		if (!isalpha(*c) && *c != '-')
5480 			return (B_FALSE);
5481 	}
5482 	return (B_TRUE);
5483 }
5484 
5485 boolean_t
5486 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
5487 {
5488 	rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
5489 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
5490 
5491 	if (priv != RCPRIV_PRIVILEGED)
5492 		return (B_FALSE);
5493 	if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
5494 		return (B_FALSE);
5495 	return (B_TRUE);
5496 }
5497 
5498 boolean_t
5499 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
5500 {
5501 	rctlblk_t *current, *next;
5502 	rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
5503 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
5504 	uint_t global_flags;
5505 
5506 	if (!zonecfg_valid_rctlblk(rctlblk))
5507 		return (B_FALSE);
5508 	if (!zonecfg_valid_rctlname(name))
5509 		return (B_FALSE);
5510 
5511 	current = alloca(rctlblk_size());
5512 	if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
5513 		return (B_TRUE);	/* not an rctl on this system */
5514 	/*
5515 	 * Make sure the proposed value isn't greater than the current system
5516 	 * value.
5517 	 */
5518 	next = alloca(rctlblk_size());
5519 	while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
5520 		rctlblk_t *tmp;
5521 
5522 		if (getrctl(name, current, next, RCTL_NEXT) != 0)
5523 			return (B_FALSE);	/* shouldn't happen */
5524 		tmp = current;
5525 		current = next;
5526 		next = tmp;
5527 	}
5528 	if (limit > rctlblk_get_value(current))
5529 		return (B_FALSE);
5530 
5531 	/*
5532 	 * Make sure the proposed action is allowed.
5533 	 */
5534 	global_flags = rctlblk_get_global_flags(current);
5535 	if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
5536 	    action == RCTL_LOCAL_DENY)
5537 		return (B_FALSE);
5538 	if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
5539 	    action == RCTL_LOCAL_NOACTION)
5540 		return (B_FALSE);
5541 
5542 	return (B_TRUE);
5543 }
5544 
5545 /*
5546  * There is always a race condition between reading the initial copy of
5547  * a zones state and its state changing.  We address this by providing
5548  * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
5549  * When zonecfg_critical_enter is called, sets the state field to LOCKED
5550  * and aquires biglock. Biglock protects against other threads executing
5551  * critical_enter and the state field protects against state changes during
5552  * the critical period.
5553  *
5554  * If any state changes occur, zn_cb will set the failed field of the znotify
5555  * structure.  This will cause the critical_exit function to re-lock the
5556  * channel and return an error. Since evsnts may be delayed, the critical_exit
5557  * function "flushes" the queue by putting an event on the queue and waiting for
5558  * zn_cb to notify critical_exit that it received the ping event.
5559  */
5560 static const char *
5561 string_get_tok(const char *in, char delim, int num)
5562 {
5563 	int i = 0;
5564 
5565 	for (; i < num; in++) {
5566 		if (*in == delim)
5567 			i++;
5568 		if (*in == 0)
5569 			return (NULL);
5570 	}
5571 	return (in);
5572 }
5573 
5574 static boolean_t
5575 is_ping(sysevent_t *ev)
5576 {
5577 	if (strcmp(sysevent_get_subclass_name(ev),
5578 	    ZONE_EVENT_PING_SUBCLASS) == 0) {
5579 		return (B_TRUE);
5580 	} else {
5581 		return (B_FALSE);
5582 	}
5583 }
5584 
5585 static boolean_t
5586 is_my_ping(sysevent_t *ev)
5587 {
5588 	const char *sender;
5589 	char mypid[sizeof (pid_t) * 3 + 1];
5590 
5591 	(void) snprintf(mypid, sizeof (mypid), "%i", getpid());
5592 	sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
5593 	if (sender == NULL)
5594 		return (B_FALSE);
5595 	if (strcmp(sender, mypid) != 0)
5596 		return (B_FALSE);
5597 	return (B_TRUE);
5598 }
5599 
5600 static int
5601 do_callback(struct znotify *zevtchan, sysevent_t *ev)
5602 {
5603 	nvlist_t *l;
5604 	int zid;
5605 	char *zonename;
5606 	char *newstate;
5607 	char *oldstate;
5608 	int ret;
5609 	hrtime_t when;
5610 
5611 	if (strcmp(sysevent_get_subclass_name(ev),
5612 	    ZONE_EVENT_STATUS_SUBCLASS) == 0) {
5613 
5614 		if (sysevent_get_attr_list(ev, &l) != 0) {
5615 			if (errno == ENOMEM) {
5616 				zevtchan->zn_failure_count++;
5617 				return (EAGAIN);
5618 			}
5619 			return (0);
5620 		}
5621 		ret = 0;
5622 
5623 		if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
5624 		    (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
5625 		    == 0) &&
5626 		    (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
5627 		    == 0) &&
5628 		    (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
5629 		    (uint64_t *)&when) == 0) &&
5630 		    (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
5631 			ret = zevtchan->zn_callback(zonename, zid, newstate,
5632 			    oldstate, when, zevtchan->zn_private);
5633 		}
5634 
5635 		zevtchan->zn_failure_count = 0;
5636 		nvlist_free(l);
5637 		return (ret);
5638 	} else {
5639 		/*
5640 		 * We have received an event in an unknown subclass. Ignore.
5641 		 */
5642 		zevtchan->zn_failure_count = 0;
5643 		return (0);
5644 	}
5645 }
5646 
5647 static int
5648 zn_cb(sysevent_t *ev, void *p)
5649 {
5650 	struct znotify *zevtchan = p;
5651 	int error;
5652 
5653 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
5654 
5655 	if (is_ping(ev) && !is_my_ping(ev)) {
5656 		(void) pthread_mutex_unlock((&zevtchan->zn_mutex));
5657 		return (0);
5658 	}
5659 
5660 	if (zevtchan->zn_state == ZN_LOCKED) {
5661 		assert(!is_ping(ev));
5662 		zevtchan->zn_failed = B_TRUE;
5663 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5664 		return (0);
5665 	}
5666 
5667 	if (zevtchan->zn_state == ZN_PING_INFLIGHT) {
5668 		if (is_ping(ev)) {
5669 			zevtchan->zn_state = ZN_PING_RECEIVED;
5670 			(void) pthread_cond_signal(&(zevtchan->zn_cond));
5671 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5672 			return (0);
5673 		} else {
5674 			zevtchan->zn_failed = B_TRUE;
5675 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5676 			return (0);
5677 		}
5678 	}
5679 
5680 	if (zevtchan->zn_state == ZN_UNLOCKED) {
5681 
5682 		error = do_callback(zevtchan, ev);
5683 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5684 		/*
5685 		 * Every ENOMEM failure causes do_callback to increment
5686 		 * zn_failure_count and every success causes it to
5687 		 * set zn_failure_count to zero.  If we got EAGAIN,
5688 		 * we will sleep for zn_failure_count seconds and return
5689 		 * EAGAIN to gpec to try again.
5690 		 *
5691 		 * After 55 seconds, or 10 try's we give up and drop the
5692 		 * event.
5693 		 */
5694 		if (error == EAGAIN) {
5695 			if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) {
5696 				return (0);
5697 			}
5698 			(void) sleep(zevtchan->zn_failure_count);
5699 		}
5700 		return (error);
5701 	}
5702 
5703 	if (zevtchan->zn_state == ZN_PING_RECEIVED) {
5704 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5705 		return (0);
5706 	}
5707 
5708 	abort();
5709 	return (0);
5710 }
5711 
5712 void
5713 zonecfg_notify_critical_enter(void *h)
5714 {
5715 	struct znotify *zevtchan = h;
5716 
5717 	(void) pthread_mutex_lock(&(zevtchan->zn_bigmutex));
5718 	zevtchan->zn_state = ZN_LOCKED;
5719 }
5720 
5721 int
5722 zonecfg_notify_critical_exit(void * h)
5723 {
5724 
5725 	struct znotify *zevtchan = h;
5726 
5727 	if (zevtchan->zn_state == ZN_UNLOCKED)
5728 		return (0);
5729 
5730 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
5731 	zevtchan->zn_state = ZN_PING_INFLIGHT;
5732 
5733 	(void) sysevent_evc_publish(zevtchan->zn_eventchan,
5734 	    ZONE_EVENT_STATUS_CLASS,
5735 	    ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER,
5736 	    zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP);
5737 
5738 	while (zevtchan->zn_state != ZN_PING_RECEIVED) {
5739 		(void) pthread_cond_wait(&(zevtchan->zn_cond),
5740 		    &(zevtchan->zn_mutex));
5741 	}
5742 
5743 	if (zevtchan->zn_failed == B_TRUE) {
5744 		zevtchan->zn_state = ZN_LOCKED;
5745 		zevtchan->zn_failed = B_FALSE;
5746 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5747 		return (1);
5748 	}
5749 
5750 	zevtchan->zn_state = ZN_UNLOCKED;
5751 	(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5752 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
5753 	return (0);
5754 }
5755 
5756 void
5757 zonecfg_notify_critical_abort(void *h)
5758 {
5759 	struct znotify *zevtchan = h;
5760 
5761 	zevtchan->zn_state = ZN_UNLOCKED;
5762 	zevtchan->zn_failed = B_FALSE;
5763 	/*
5764 	 * Don't do anything about zn_lock. If it is held, it could only be
5765 	 * held by zn_cb and it will be unlocked soon.
5766 	 */
5767 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
5768 }
5769 
5770 void *
5771 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
5772     const char *newstate, const char *oldstate, hrtime_t when, void *p),
5773     void *p)
5774 {
5775 	struct znotify *zevtchan;
5776 	int i = 1;
5777 	int r;
5778 
5779 	zevtchan = malloc(sizeof (struct znotify));
5780 
5781 	if (zevtchan == NULL)
5782 		return (NULL);
5783 
5784 	zevtchan->zn_private = p;
5785 	zevtchan->zn_callback = func;
5786 	zevtchan->zn_state = ZN_UNLOCKED;
5787 	zevtchan->zn_failed = B_FALSE;
5788 
5789 	if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL))
5790 		goto out3;
5791 	if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) {
5792 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
5793 		goto out3;
5794 	}
5795 	if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) {
5796 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
5797 		(void) pthread_cond_destroy(&(zevtchan->zn_cond));
5798 		goto out3;
5799 	}
5800 
5801 	if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan),
5802 	    0) != 0)
5803 		goto out2;
5804 
5805 	do {
5806 		/*
5807 		 * At 4 digits the subscriber ID gets too long and we have
5808 		 * no chance of successfully registering.
5809 		 */
5810 		if (i > 999)
5811 			goto out1;
5812 
5813 		(void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i",
5814 		    getpid() % 999999l, i);
5815 
5816 		r = sysevent_evc_subscribe(zevtchan->zn_eventchan,
5817 		    zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb,
5818 		    zevtchan, 0);
5819 
5820 		i++;
5821 
5822 	} while (r);
5823 
5824 	return (zevtchan);
5825 out1:
5826 	sysevent_evc_unbind(zevtchan->zn_eventchan);
5827 out2:
5828 	(void) pthread_mutex_destroy(&zevtchan->zn_mutex);
5829 	(void) pthread_cond_destroy(&zevtchan->zn_cond);
5830 	(void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex));
5831 out3:
5832 	free(zevtchan);
5833 
5834 	return (NULL);
5835 }
5836 
5837 void
5838 zonecfg_notify_unbind(void *handle)
5839 {
5840 
5841 	int ret;
5842 
5843 	sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan);
5844 	/*
5845 	 * Check that all evc threads have gone away. This should be
5846 	 * enforced by sysevent_evc_unbind.
5847 	 */
5848 	ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex);
5849 
5850 	if (ret)
5851 		abort();
5852 
5853 	(void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex);
5854 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex);
5855 	(void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond);
5856 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex);
5857 
5858 	free(handle);
5859 }
5860 
5861 static int
5862 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
5863 {
5864 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
5865 	int err;
5866 
5867 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL);
5868 	if ((err = newprop(newnode, DTD_ATTR_NAME,
5869 	    tabptr->zone_dataset_name)) != Z_OK)
5870 		return (err);
5871 	return (Z_OK);
5872 }
5873 
5874 int
5875 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5876 {
5877 	int err;
5878 
5879 	if (tabptr == NULL)
5880 		return (Z_INVAL);
5881 
5882 	if ((err = operation_prep(handle)) != Z_OK)
5883 		return (err);
5884 
5885 	if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK)
5886 		return (err);
5887 
5888 	return (Z_OK);
5889 }
5890 
5891 static int
5892 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
5893 {
5894 	xmlNodePtr cur = handle->zone_dh_cur;
5895 
5896 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
5897 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5898 			continue;
5899 
5900 		if (match_prop(cur, DTD_ATTR_NAME,
5901 		    tabptr->zone_dataset_name)) {
5902 			xmlUnlinkNode(cur);
5903 			xmlFreeNode(cur);
5904 			return (Z_OK);
5905 		}
5906 	}
5907 	return (Z_NO_RESOURCE_ID);
5908 }
5909 
5910 int
5911 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5912 {
5913 	int err;
5914 
5915 	if (tabptr == NULL)
5916 		return (Z_INVAL);
5917 
5918 	if ((err = operation_prep(handle)) != Z_OK)
5919 		return (err);
5920 
5921 	if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK)
5922 		return (err);
5923 
5924 	return (Z_OK);
5925 }
5926 
5927 int
5928 zonecfg_modify_ds(
5929 	zone_dochandle_t handle,
5930 	struct zone_dstab *oldtabptr,
5931 	struct zone_dstab *newtabptr)
5932 {
5933 	int err;
5934 
5935 	if (oldtabptr == NULL || newtabptr == NULL)
5936 		return (Z_INVAL);
5937 
5938 	if ((err = operation_prep(handle)) != Z_OK)
5939 		return (err);
5940 
5941 	if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK)
5942 		return (err);
5943 
5944 	if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK)
5945 		return (err);
5946 
5947 	return (Z_OK);
5948 }
5949 
5950 int
5951 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5952 {
5953 	xmlNodePtr cur, firstmatch;
5954 	int err;
5955 	char dataset[MAXNAMELEN];
5956 
5957 	if (tabptr == NULL)
5958 		return (Z_INVAL);
5959 
5960 	if ((err = operation_prep(handle)) != Z_OK)
5961 		return (err);
5962 
5963 	cur = handle->zone_dh_cur;
5964 	firstmatch = NULL;
5965 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
5966 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5967 			continue;
5968 		if (strlen(tabptr->zone_dataset_name) > 0) {
5969 			if ((fetchprop(cur, DTD_ATTR_NAME, dataset,
5970 			    sizeof (dataset)) == Z_OK) &&
5971 			    (strcmp(tabptr->zone_dataset_name,
5972 			    dataset) == 0)) {
5973 				if (firstmatch == NULL)
5974 					firstmatch = cur;
5975 				else
5976 					return (Z_INSUFFICIENT_SPEC);
5977 			}
5978 		}
5979 	}
5980 	if (firstmatch == NULL)
5981 		return (Z_NO_RESOURCE_ID);
5982 
5983 	cur = firstmatch;
5984 
5985 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
5986 	    sizeof (tabptr->zone_dataset_name))) != Z_OK)
5987 		return (err);
5988 
5989 	return (Z_OK);
5990 }
5991 
5992 int
5993 zonecfg_setdsent(zone_dochandle_t handle)
5994 {
5995 	return (zonecfg_setent(handle));
5996 }
5997 
5998 int
5999 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
6000 {
6001 	xmlNodePtr cur;
6002 	int err;
6003 
6004 	if (handle == NULL)
6005 		return (Z_INVAL);
6006 
6007 	if ((cur = handle->zone_dh_cur) == NULL)
6008 		return (Z_NO_ENTRY);
6009 
6010 	for (; cur != NULL; cur = cur->next)
6011 		if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6012 			break;
6013 	if (cur == NULL) {
6014 		handle->zone_dh_cur = handle->zone_dh_top;
6015 		return (Z_NO_ENTRY);
6016 	}
6017 
6018 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
6019 	    sizeof (tabptr->zone_dataset_name))) != Z_OK) {
6020 		handle->zone_dh_cur = handle->zone_dh_top;
6021 		return (err);
6022 	}
6023 
6024 	handle->zone_dh_cur = cur->next;
6025 	return (Z_OK);
6026 }
6027 
6028 int
6029 zonecfg_enddsent(zone_dochandle_t handle)
6030 {
6031 	return (zonecfg_endent(handle));
6032 }
6033 
6034 /*
6035  * Support for aliased rctls; that is, rctls that have simplified names in
6036  * zonecfg.  For example, max-lwps is an alias for a well defined zone.max-lwps
6037  * rctl.  If there are multiple existing values for one of these rctls or if
6038  * there is a single value that does not match the well defined template (i.e.
6039  * it has a different action) then we cannot treat the rctl as having an alias
6040  * so we return Z_ALIAS_DISALLOW.  That means that the rctl cannot be
6041  * managed in zonecfg via an alias and that the standard rctl syntax must be
6042  * used.
6043  *
6044  * The possible return values are:
6045  *	Z_NO_PROPERTY_ID - invalid alias name
6046  *	Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition
6047  *	Z_NO_ENTRY - no rctl is configured for this alias
6048  *	Z_OK - we got a valid rctl for the specified alias
6049  */
6050 int
6051 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval)
6052 {
6053 	boolean_t found = B_FALSE;
6054 	boolean_t found_val = B_FALSE;
6055 	xmlNodePtr cur, val;
6056 	char savedname[MAXNAMELEN];
6057 	struct zone_rctlvaltab rctl;
6058 	int i;
6059 	int err;
6060 
6061 	for (i = 0; aliases[i].shortname != NULL; i++)
6062 		if (strcmp(name, aliases[i].shortname) == 0)
6063 			break;
6064 
6065 	if (aliases[i].shortname == NULL)
6066 		return (Z_NO_PROPERTY_ID);
6067 
6068 	if ((err = operation_prep(handle)) != Z_OK)
6069 		return (err);
6070 
6071 	cur = handle->zone_dh_cur;
6072 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6073 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0)
6074 			continue;
6075 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
6076 		    sizeof (savedname)) == Z_OK) &&
6077 		    (strcmp(savedname, aliases[i].realname) == 0)) {
6078 
6079 			/*
6080 			 * If we already saw one of these, we can't have an
6081 			 * alias since we just found another.
6082 			 */
6083 			if (found)
6084 				return (Z_ALIAS_DISALLOW);
6085 			found = B_TRUE;
6086 
6087 			for (val = cur->xmlChildrenNode; val != NULL;
6088 			    val = val->next) {
6089 				/*
6090 				 * If we already have one value, we can't have
6091 				 * an alias since we just found another.
6092 				 */
6093 				if (found_val)
6094 					return (Z_ALIAS_DISALLOW);
6095 				found_val = B_TRUE;
6096 
6097 				if ((fetchprop(val, DTD_ATTR_PRIV,
6098 				    rctl.zone_rctlval_priv,
6099 				    sizeof (rctl.zone_rctlval_priv)) != Z_OK))
6100 					break;
6101 				if ((fetchprop(val, DTD_ATTR_LIMIT,
6102 				    rctl.zone_rctlval_limit,
6103 				    sizeof (rctl.zone_rctlval_limit)) != Z_OK))
6104 					break;
6105 				if ((fetchprop(val, DTD_ATTR_ACTION,
6106 				    rctl.zone_rctlval_action,
6107 				    sizeof (rctl.zone_rctlval_action)) != Z_OK))
6108 					break;
6109 			}
6110 
6111 			/* check priv and action match the expected vals */
6112 			if (strcmp(rctl.zone_rctlval_priv,
6113 			    aliases[i].priv) != 0 ||
6114 			    strcmp(rctl.zone_rctlval_action,
6115 			    aliases[i].action) != 0)
6116 				return (Z_ALIAS_DISALLOW);
6117 		}
6118 	}
6119 
6120 	if (found) {
6121 		*rval = strtoull(rctl.zone_rctlval_limit, NULL, 10);
6122 		return (Z_OK);
6123 	}
6124 
6125 	return (Z_NO_ENTRY);
6126 }
6127 
6128 int
6129 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name)
6130 {
6131 	int i;
6132 	uint64_t val;
6133 	struct zone_rctltab rctltab;
6134 
6135 	/*
6136 	 * First check that we have a valid aliased rctl to remove.
6137 	 * This will catch an rctl entry with non-standard values or
6138 	 * multiple rctl values for this name.  We need to ignore those
6139 	 * rctl entries.
6140 	 */
6141 	if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK)
6142 		return (Z_OK);
6143 
6144 	for (i = 0; aliases[i].shortname != NULL; i++)
6145 		if (strcmp(name, aliases[i].shortname) == 0)
6146 			break;
6147 
6148 	if (aliases[i].shortname == NULL)
6149 		return (Z_NO_RESOURCE_ID);
6150 
6151 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6152 	    sizeof (rctltab.zone_rctl_name));
6153 
6154 	return (zonecfg_delete_rctl(handle, &rctltab));
6155 }
6156 
6157 boolean_t
6158 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name)
6159 {
6160 	uint64_t tmp_val;
6161 
6162 	switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) {
6163 	case Z_OK:
6164 		/*FALLTHRU*/
6165 	case Z_NO_ENTRY:
6166 		return (B_TRUE);
6167 	default:
6168 		return (B_FALSE);
6169 	}
6170 }
6171 
6172 int
6173 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val)
6174 {
6175 	int i;
6176 	int err;
6177 	struct zone_rctltab rctltab;
6178 	struct zone_rctlvaltab *rctlvaltab;
6179 	char buf[128];
6180 
6181 	if (!zonecfg_aliased_rctl_ok(handle, name))
6182 		return (Z_ALIAS_DISALLOW);
6183 
6184 	for (i = 0; aliases[i].shortname != NULL; i++)
6185 		if (strcmp(name, aliases[i].shortname) == 0)
6186 			break;
6187 
6188 	if (aliases[i].shortname == NULL)
6189 		return (Z_NO_RESOURCE_ID);
6190 
6191 	/* remove any pre-existing definition for this rctl */
6192 	(void) zonecfg_rm_aliased_rctl(handle, name);
6193 
6194 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6195 	    sizeof (rctltab.zone_rctl_name));
6196 
6197 	rctltab.zone_rctl_valptr = NULL;
6198 
6199 	if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL)
6200 		return (Z_NOMEM);
6201 
6202 	(void) snprintf(buf, sizeof (buf), "%llu", (long long)val);
6203 
6204 	(void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv,
6205 	    sizeof (rctlvaltab->zone_rctlval_priv));
6206 	(void) strlcpy(rctlvaltab->zone_rctlval_limit, buf,
6207 	    sizeof (rctlvaltab->zone_rctlval_limit));
6208 	(void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action,
6209 	    sizeof (rctlvaltab->zone_rctlval_action));
6210 
6211 	rctlvaltab->zone_rctlval_next = NULL;
6212 
6213 	if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK)
6214 		return (err);
6215 
6216 	return (zonecfg_add_rctl(handle, &rctltab));
6217 }
6218 
6219 static int
6220 delete_tmp_pool(zone_dochandle_t handle)
6221 {
6222 	int err;
6223 	xmlNodePtr cur = handle->zone_dh_cur;
6224 
6225 	if ((err = operation_prep(handle)) != Z_OK)
6226 		return (err);
6227 
6228 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6229 		if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6230 			xmlUnlinkNode(cur);
6231 			xmlFreeNode(cur);
6232 			return (Z_OK);
6233 		}
6234 	}
6235 
6236 	return (Z_NO_RESOURCE_ID);
6237 }
6238 
6239 static int
6240 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance)
6241 {
6242 	int err;
6243 	xmlNodePtr cur = handle->zone_dh_cur;
6244 	xmlNodePtr newnode;
6245 
6246 	err = delete_tmp_pool(handle);
6247 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6248 		return (err);
6249 
6250 	if (*pool_importance != '\0') {
6251 		if ((err = operation_prep(handle)) != Z_OK)
6252 			return (err);
6253 
6254 		newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL);
6255 		if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE,
6256 		    pool_importance)) != Z_OK)
6257 			return (err);
6258 	}
6259 
6260 	return (Z_OK);
6261 }
6262 
6263 static int
6264 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr)
6265 {
6266 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6267 	int err;
6268 
6269 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL);
6270 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN,
6271 	    tabptr->zone_ncpu_min)) != Z_OK)
6272 		return (err);
6273 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX,
6274 	    tabptr->zone_ncpu_max)) != Z_OK)
6275 		return (err);
6276 
6277 	if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK)
6278 		return (err);
6279 
6280 	return (Z_OK);
6281 }
6282 
6283 int
6284 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6285 {
6286 	int err;
6287 
6288 	if (tabptr == NULL)
6289 		return (Z_INVAL);
6290 
6291 	if ((err = operation_prep(handle)) != Z_OK)
6292 		return (err);
6293 
6294 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
6295 		return (err);
6296 
6297 	return (Z_OK);
6298 }
6299 
6300 int
6301 zonecfg_delete_pset(zone_dochandle_t handle)
6302 {
6303 	int err;
6304 	int res = Z_NO_RESOURCE_ID;
6305 	xmlNodePtr cur = handle->zone_dh_cur;
6306 
6307 	if ((err = operation_prep(handle)) != Z_OK)
6308 		return (err);
6309 
6310 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6311 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
6312 			xmlUnlinkNode(cur);
6313 			xmlFreeNode(cur);
6314 			res = Z_OK;
6315 			break;
6316 		}
6317 	}
6318 
6319 	/*
6320 	 * Once we have msets, we should check that a mset
6321 	 * do not exist before we delete the tmp_pool data.
6322 	 */
6323 	err = delete_tmp_pool(handle);
6324 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6325 		return (err);
6326 
6327 	return (res);
6328 }
6329 
6330 int
6331 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6332 {
6333 	int err;
6334 
6335 	if (tabptr == NULL)
6336 		return (Z_INVAL);
6337 
6338 	if ((err = zonecfg_delete_pset(handle)) != Z_OK)
6339 		return (err);
6340 
6341 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
6342 		return (err);
6343 
6344 	return (Z_OK);
6345 }
6346 
6347 int
6348 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6349 {
6350 	xmlNodePtr cur;
6351 	int err;
6352 	int res = Z_NO_ENTRY;
6353 
6354 	if (tabptr == NULL)
6355 		return (Z_INVAL);
6356 
6357 	if ((err = operation_prep(handle)) != Z_OK)
6358 		return (err);
6359 
6360 	/* this is an optional component */
6361 	tabptr->zone_importance[0] = '\0';
6362 
6363 	cur = handle->zone_dh_cur;
6364 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6365 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
6366 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN,
6367 			    tabptr->zone_ncpu_min,
6368 			    sizeof (tabptr->zone_ncpu_min))) != Z_OK) {
6369 				handle->zone_dh_cur = handle->zone_dh_top;
6370 				return (err);
6371 			}
6372 
6373 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX,
6374 			    tabptr->zone_ncpu_max,
6375 			    sizeof (tabptr->zone_ncpu_max))) != Z_OK) {
6376 				handle->zone_dh_cur = handle->zone_dh_top;
6377 				return (err);
6378 			}
6379 
6380 			res = Z_OK;
6381 
6382 		} else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6383 			if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE,
6384 			    tabptr->zone_importance,
6385 			    sizeof (tabptr->zone_importance))) != Z_OK) {
6386 				handle->zone_dh_cur = handle->zone_dh_top;
6387 				return (err);
6388 			}
6389 		}
6390 	}
6391 
6392 	return (res);
6393 }
6394 
6395 int
6396 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
6397 {
6398 	int err;
6399 
6400 	if ((err = zonecfg_setent(handle)) != Z_OK)
6401 		return (err);
6402 
6403 	err = zonecfg_lookup_pset(handle, tabptr);
6404 
6405 	(void) zonecfg_endent(handle);
6406 
6407 	return (err);
6408 }
6409 
6410 static int
6411 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6412 {
6413 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6414 	int err;
6415 
6416 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
6417 	if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
6418 	    != Z_OK)
6419 		return (err);
6420 
6421 	return (Z_OK);
6422 }
6423 
6424 int
6425 zonecfg_delete_mcap(zone_dochandle_t handle)
6426 {
6427 	int err;
6428 	xmlNodePtr cur = handle->zone_dh_cur;
6429 
6430 	if ((err = operation_prep(handle)) != Z_OK)
6431 		return (err);
6432 
6433 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6434 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6435 			continue;
6436 
6437 		xmlUnlinkNode(cur);
6438 		xmlFreeNode(cur);
6439 		return (Z_OK);
6440 	}
6441 	return (Z_NO_RESOURCE_ID);
6442 }
6443 
6444 int
6445 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6446 {
6447 	int err;
6448 
6449 	if (tabptr == NULL)
6450 		return (Z_INVAL);
6451 
6452 	err = zonecfg_delete_mcap(handle);
6453 	/* it is ok if there is no mcap entry */
6454 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6455 		return (err);
6456 
6457 	if ((err = add_mcap(handle, tabptr)) != Z_OK)
6458 		return (err);
6459 
6460 	return (Z_OK);
6461 }
6462 
6463 int
6464 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6465 {
6466 	xmlNodePtr cur;
6467 	int err;
6468 
6469 	if (tabptr == NULL)
6470 		return (Z_INVAL);
6471 
6472 	if ((err = operation_prep(handle)) != Z_OK)
6473 		return (err);
6474 
6475 	cur = handle->zone_dh_cur;
6476 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6477 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6478 			continue;
6479 		if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
6480 		    tabptr->zone_physmem_cap,
6481 		    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6482 			handle->zone_dh_cur = handle->zone_dh_top;
6483 			return (err);
6484 		}
6485 
6486 		return (Z_OK);
6487 	}
6488 
6489 	return (Z_NO_ENTRY);
6490 }
6491 
6492 static int
6493 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6494 {
6495 	xmlNodePtr cur;
6496 	int err;
6497 
6498 	if (handle == NULL)
6499 		return (Z_INVAL);
6500 
6501 	if ((cur = handle->zone_dh_cur) == NULL)
6502 		return (Z_NO_ENTRY);
6503 
6504 	for (; cur != NULL; cur = cur->next)
6505 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
6506 			break;
6507 	if (cur == NULL) {
6508 		handle->zone_dh_cur = handle->zone_dh_top;
6509 		return (Z_NO_ENTRY);
6510 	}
6511 
6512 	if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
6513 	    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6514 		handle->zone_dh_cur = handle->zone_dh_top;
6515 		return (err);
6516 	}
6517 
6518 	handle->zone_dh_cur = cur->next;
6519 	return (Z_OK);
6520 }
6521 
6522 int
6523 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6524 {
6525 	int err;
6526 
6527 	if ((err = zonecfg_setent(handle)) != Z_OK)
6528 		return (err);
6529 
6530 	err = getmcapent_core(handle, tabptr);
6531 
6532 	(void) zonecfg_endent(handle);
6533 
6534 	return (err);
6535 }
6536 
6537 /*
6538  * Get the full tree of pkg/patch metadata in a set of nested AVL trees.
6539  * pkgs_avl is an AVL tree of pkgs.  Each pkg element contains a
6540  * zpe_patches_avl member which holds an AVL tree of patches for that pkg.
6541  * The patch elements have the same zpe_patches_avl member, each of which can
6542  * hold an AVL tree of patches that are obsoleted by the patch.
6543  *
6544  * The zone xml data contains DTD_ELEM_PACKAGE elements, followed by
6545  * DTD_ELEM_PATCH elements.  The DTD_ELEM_PATCH patch element applies to the
6546  * DTD_ELEM_PACKAGE that precedes it.  The DTD_ELEM_PATCH element may have
6547  * child DTD_ELEM_OBSOLETES nodes associated with it.  The DTD_ELEM_PACKAGE
6548  * really should have had the DTD_ELEM_PATCH elements as children but it
6549  * was not defined that way initially so we are stuck with the DTD definition
6550  * now.  However, we can safely assume the ordering for compatibility.
6551  */
6552 int
6553 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
6554     uu_avl_t *pkgs_avl)
6555 {
6556 	xmlNodePtr cur;
6557 	int res;
6558 	zone_pkg_entry_t *pkg;
6559 	char name[MAXNAMELEN];
6560 	char version[ZONE_PKG_VERSMAX];
6561 
6562 	if (handle == NULL)
6563 		return (Z_INVAL);
6564 
6565 	if ((res = zonecfg_setent(handle)) != Z_OK)
6566 		return (res);
6567 
6568 	if ((cur = handle->zone_dh_cur) == NULL) {
6569 		res = Z_NO_ENTRY;
6570 		goto done;
6571 	}
6572 
6573 	for (; cur != NULL; cur = cur->next) {
6574 		if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) {
6575 			uu_avl_index_t where;
6576 
6577 			if ((res = fetchprop(cur, DTD_ATTR_NAME, name,
6578 			    sizeof (name))) != Z_OK)
6579 				goto done;
6580 
6581 			if ((res = fetchprop(cur, DTD_ATTR_VERSION, version,
6582 			    sizeof (version))) != Z_OK)
6583 				goto done;
6584 
6585 			if ((pkg = (zone_pkg_entry_t *)
6586 			    malloc(sizeof (zone_pkg_entry_t))) == NULL) {
6587 				res = Z_NOMEM;
6588 				goto done;
6589 			}
6590 
6591 			if ((pkg->zpe_name = strdup(name)) == NULL) {
6592 				free(pkg);
6593 				res = Z_NOMEM;
6594 				goto done;
6595 			}
6596 
6597 			if ((pkg->zpe_vers = strdup(version)) == NULL) {
6598 				free(pkg->zpe_name);
6599 				free(pkg);
6600 				res = Z_NOMEM;
6601 				goto done;
6602 			}
6603 
6604 			pkg->zpe_patches_avl = NULL;
6605 
6606 			uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool);
6607 			if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) {
6608 				free(pkg->zpe_name);
6609 				free(pkg->zpe_vers);
6610 				free(pkg);
6611 			} else {
6612 				uu_avl_insert(pkgs_avl, pkg, where);
6613 			}
6614 
6615 		} else if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) {
6616 			zone_pkg_entry_t *patch;
6617 			uu_avl_index_t where;
6618 			char *p;
6619 			char *dashp = NULL;
6620 			xmlNodePtr child;
6621 
6622 			if ((res = fetchprop(cur, DTD_ATTR_ID, name,
6623 			    sizeof (name))) != Z_OK)
6624 				goto done;
6625 
6626 			if ((patch = (zone_pkg_entry_t *)
6627 			    malloc(sizeof (zone_pkg_entry_t))) == NULL) {
6628 				res = Z_NOMEM;
6629 				goto done;
6630 			}
6631 
6632 			if ((p = strchr(name, '-')) != NULL) {
6633 				dashp = p;
6634 				*p++ = '\0';
6635 			} else {
6636 				p = "";
6637 			}
6638 
6639 			if ((patch->zpe_name = strdup(name)) == NULL) {
6640 				free(patch);
6641 				res = Z_NOMEM;
6642 				goto done;
6643 			}
6644 
6645 			if ((patch->zpe_vers = strdup(p)) == NULL) {
6646 				free(patch->zpe_name);
6647 				free(patch);
6648 				res = Z_NOMEM;
6649 				goto done;
6650 			}
6651 
6652 			if (dashp != NULL)
6653 				*dashp = '-';
6654 
6655 			patch->zpe_patches_avl = NULL;
6656 
6657 			if (pkg->zpe_patches_avl == NULL) {
6658 				pkg->zpe_patches_avl = uu_avl_create(pkg_pool,
6659 				    NULL, UU_DEFAULT);
6660 				if (pkg->zpe_patches_avl == NULL) {
6661 					free(patch->zpe_name);
6662 					free(patch->zpe_vers);
6663 					free(patch);
6664 					res = Z_NOMEM;
6665 					goto done;
6666 				}
6667 			}
6668 
6669 			uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool);
6670 			if (uu_avl_find(pkg->zpe_patches_avl, patch, NULL,
6671 			    &where) != NULL) {
6672 				free(patch->zpe_name);
6673 				free(patch->zpe_vers);
6674 				free(patch);
6675 			} else {
6676 				uu_avl_insert(pkg->zpe_patches_avl, patch,
6677 				    where);
6678 			}
6679 
6680 			/* Add any patches this patch obsoletes. */
6681 			for (child = cur->xmlChildrenNode; child != NULL;
6682 			    child = child->next) {
6683 				zone_pkg_entry_t *obs;
6684 
6685 				if (xmlStrcmp(child->name, DTD_ELEM_OBSOLETES)
6686 				    != 0)
6687 					continue;
6688 
6689 				if ((res = fetchprop(child, DTD_ATTR_ID,
6690 				    name, sizeof (name))) != Z_OK)
6691 					goto done;
6692 
6693 				if ((obs = (zone_pkg_entry_t *)malloc(
6694 				    sizeof (zone_pkg_entry_t))) == NULL) {
6695 					res = Z_NOMEM;
6696 					goto done;
6697 				}
6698 
6699 				if ((obs->zpe_name = strdup(name)) == NULL) {
6700 					free(obs);
6701 					res = Z_NOMEM;
6702 					goto done;
6703 				}
6704 				/*
6705 				 * The version doesn't matter for obsoleted
6706 				 * patches.
6707 				 */
6708 				obs->zpe_vers = NULL;
6709 				obs->zpe_patches_avl = NULL;
6710 
6711 				/*
6712 				 * If this is the first obsolete patch, add an
6713 				 * AVL tree to the parent patch element.
6714 				 */
6715 				if (patch->zpe_patches_avl == NULL) {
6716 					patch->zpe_patches_avl =
6717 					    uu_avl_create(pkg_pool, NULL,
6718 					    UU_DEFAULT);
6719 					if (patch->zpe_patches_avl == NULL) {
6720 						free(obs->zpe_name);
6721 						free(obs);
6722 						res = Z_NOMEM;
6723 						goto done;
6724 					}
6725 				}
6726 
6727 				/* Insert obsolete patch into the AVL tree. */
6728 				uu_avl_node_init(obs, &obs->zpe_entry,
6729 				    pkg_pool);
6730 				if (uu_avl_find(patch->zpe_patches_avl, obs,
6731 				    NULL, &where) != NULL) {
6732 					free(obs->zpe_name);
6733 					free(obs);
6734 				} else {
6735 					uu_avl_insert(patch->zpe_patches_avl,
6736 					    obs, where);
6737 				}
6738 			}
6739 		}
6740 	}
6741 
6742 done:
6743 	(void) zonecfg_endent(handle);
6744 	return (res);
6745 }
6746 
6747 int
6748 zonecfg_setdevperment(zone_dochandle_t handle)
6749 {
6750 	return (zonecfg_setent(handle));
6751 }
6752 
6753 int
6754 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr)
6755 {
6756 	xmlNodePtr cur;
6757 	int err;
6758 	char buf[128];
6759 
6760 	tabptr->zone_devperm_acl = NULL;
6761 
6762 	if (handle == NULL)
6763 		return (Z_INVAL);
6764 
6765 	if ((cur = handle->zone_dh_cur) == NULL)
6766 		return (Z_NO_ENTRY);
6767 
6768 	for (; cur != NULL; cur = cur->next)
6769 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM))
6770 			break;
6771 	if (cur == NULL) {
6772 		handle->zone_dh_cur = handle->zone_dh_top;
6773 		return (Z_NO_ENTRY);
6774 	}
6775 
6776 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name,
6777 	    sizeof (tabptr->zone_devperm_name))) != Z_OK) {
6778 		handle->zone_dh_cur = handle->zone_dh_top;
6779 		return (err);
6780 	}
6781 
6782 	if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) {
6783 		handle->zone_dh_cur = handle->zone_dh_top;
6784 		return (err);
6785 	}
6786 	tabptr->zone_devperm_uid = (uid_t)atol(buf);
6787 
6788 	if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) {
6789 		handle->zone_dh_cur = handle->zone_dh_top;
6790 		return (err);
6791 	}
6792 	tabptr->zone_devperm_gid = (gid_t)atol(buf);
6793 
6794 	if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) {
6795 		handle->zone_dh_cur = handle->zone_dh_top;
6796 		return (err);
6797 	}
6798 	tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8);
6799 
6800 	if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL,
6801 	    &(tabptr->zone_devperm_acl))) != Z_OK) {
6802 		handle->zone_dh_cur = handle->zone_dh_top;
6803 		return (err);
6804 	}
6805 
6806 	handle->zone_dh_cur = cur->next;
6807 	return (Z_OK);
6808 }
6809 
6810 int
6811 zonecfg_enddevperment(zone_dochandle_t handle)
6812 {
6813 	return (zonecfg_endent(handle));
6814 }
6815 
6816 /*
6817  * Maintain a space separated list of unique pkg names.  PATH_MAX is used in
6818  * the pkg code as the maximum size for a pkg name.
6819  */
6820 static int
6821 add_pkg_to_str(char **str, char *pkg)
6822 {
6823 	int len, newlen;
6824 	char tstr[PATH_MAX + 3];
6825 	char *tmp;
6826 
6827 	len = strlen(pkg);
6828 	if (*str == NULL) {
6829 		/* space for str + 2 spaces + NULL */
6830 		if ((*str = (char *)malloc(len + 3)) == NULL)
6831 			return (Z_NOMEM);
6832 		(void) snprintf(*str, len + 3, " %s ", pkg);
6833 		return (Z_OK);
6834 	}
6835 
6836 	(void) snprintf(tstr, sizeof (tstr), " %s ", pkg);
6837 	if (strstr(*str, tstr) != NULL)
6838 		return (Z_OK);
6839 
6840 	/* space for str + 1 space + NULL */
6841 	newlen = strlen(*str) + len + 2;
6842 	if ((tmp = (char *)realloc(*str, newlen)) == NULL)
6843 		return (Z_NOMEM);
6844 	*str = tmp;
6845 	(void) strlcat(*str, pkg, newlen);
6846 	(void) strlcat(*str, " ", newlen);
6847 	return (Z_OK);
6848 }
6849 
6850 /*
6851  * Process a list of pkgs from an entry in the contents file, adding each pkg
6852  * name to the list of pkgs.
6853  *
6854  * It is possible for the pkg name to be preceeded by a special character
6855  * which indicates some bookkeeping information for pkging.  Check if the
6856  * first char is not an Alpha char.  If so, skip over it.
6857  */
6858 static int
6859 add_pkg_list(char *lastp, char ***plist, int *pcnt, char **pkg_warn)
6860 {
6861 	char	*p;
6862 	int	pkg_cnt = *pcnt;
6863 	char	**pkgs = *plist;
6864 	int	res = Z_OK;
6865 
6866 	while ((p = strtok_r(NULL, " ", &lastp)) != NULL) {
6867 		char	**tmpp;
6868 		int	i;
6869 
6870 		/* skip over any special pkg bookkeeping char */
6871 		if (!isalpha(*p)) {
6872 			p++;
6873 			if ((res = add_pkg_to_str(pkg_warn, p)) != Z_OK)
6874 				break;
6875 		}
6876 
6877 		/* Check if the pkg is already in the list */
6878 		for (i = 0; i < pkg_cnt; i++) {
6879 			if (strcmp(p, pkgs[i]) == 0)
6880 				break;
6881 		}
6882 
6883 		if (i < pkg_cnt)
6884 			continue;
6885 
6886 		/* The pkg is not in the list; add it. */
6887 		if ((tmpp = (char **)realloc(pkgs,
6888 		    sizeof (char *) * (pkg_cnt + 1))) == NULL) {
6889 			res = Z_NOMEM;
6890 			break;
6891 		}
6892 		pkgs = tmpp;
6893 
6894 		if ((pkgs[pkg_cnt] = strdup(p)) == NULL) {
6895 			res = Z_NOMEM;
6896 			break;
6897 		}
6898 		pkg_cnt++;
6899 	}
6900 
6901 	*plist = pkgs;
6902 	*pcnt = pkg_cnt;
6903 
6904 	return (res);
6905 }
6906 
6907 /*
6908  * Process an entry from the contents file (type "directory").  If the
6909  * directory path is in the list of ipds and is not under a lofs mount within
6910  * the ipd then add the associated list of pkgs to the pkg list.  The input
6911  * parameter "entry" will be broken up by the parser within this function so
6912  * its value will be modified when this function exits.
6913  *
6914  * The entries we are looking for will look something like:
6915  *	/usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf ....
6916  */
6917 static int
6918 get_path_pkgs(char *entry, char **ipds, char **fss, char ***pkgs, int *pkg_cnt,
6919     char **pkg_warn)
6920 {
6921 	char	*f1;
6922 	char	*f2;
6923 	char	*lastp;
6924 	int	i;
6925 	char	*nlp;
6926 
6927 	if ((f1 = strtok_r(entry, " ", &lastp)) == NULL ||
6928 	    (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0)
6929 		return (Z_OK);
6930 
6931 	/* Check if this directory entry is in the list of ipds. */
6932 	for (i = 0; ipds[i] != NULL; i++) {
6933 		char wildcard[MAXPATHLEN];
6934 
6935 		/*
6936 		 * We want to match on the path and any other directory
6937 		 * entries under this path.  When we use FNM_PATHNAME then
6938 		 * that means '/' will not be matched by a wildcard (*) so
6939 		 * we omit FNM_PATHNAME on the call with the wildcard matching.
6940 		 */
6941 		(void) snprintf(wildcard, sizeof (wildcard), "%s/*", ipds[i]);
6942 		if (fnmatch(ipds[i], f1, FNM_PATHNAME) == 0 ||
6943 		    fnmatch(wildcard, f1, 0) == 0) {
6944 			/* It looks like we do want the pkgs for this path. */
6945 			break;
6946 		}
6947 	}
6948 
6949 	/* This entry did not match any of the ipds. */
6950 	if (ipds[i] == NULL)
6951 		return (Z_OK);
6952 
6953 	/*
6954 	 * Check if there is a fs mounted under the ipd.  If so, ignore this
6955 	 * entry.
6956 	 */
6957 	for (i = 0; fss[i] != NULL; i++) {
6958 		char wildcard[MAXPATHLEN];
6959 
6960 		(void) snprintf(wildcard, sizeof (wildcard), "%s/*", fss[i]);
6961 		if (fnmatch(fss[i], f1, FNM_PATHNAME) == 0 ||
6962 		    fnmatch(wildcard, f1, 0) == 0) {
6963 			/* We should ignore this path. */
6964 			break;
6965 		}
6966 	}
6967 
6968 	/* If not null, then we matched an fs mount point so ignore entry. */
6969 	if (fss[i] != NULL)
6970 		return (Z_OK);
6971 
6972 	/*
6973 	 * We do want the pkgs for this entry.  First, skip over the next 4
6974 	 * fields in the entry so that we call add_pkg_list starting with the
6975 	 * pkg names.
6976 	 */
6977 	for (i = 0; i < 4 && strtok_r(NULL, " ", &lastp) != NULL; i++)
6978 		;
6979 	/* If there are < 4 fields this entry is corrupt, just skip it. */
6980 	if (i < 4)
6981 		return (Z_OK);
6982 
6983 	/* strip newline from the line */
6984 	nlp = (lastp + strlen(lastp) - 1);
6985 	if (*nlp == '\n')
6986 		*nlp = '\0';
6987 
6988 	return (add_pkg_list(lastp, pkgs, pkg_cnt, pkg_warn));
6989 }
6990 
6991 /*
6992  * Read an entry from a pkginfo or contents file.  Some of these lines can
6993  * either be arbitrarily long or be continued by a backslash at the end of
6994  * the line.  This function coalesces lines that are longer than the read
6995  * buffer, and lines that are continued, into one buffer which is returned.
6996  * The caller must free this memory.  NULL is returned when we hit EOF or
6997  * if we run out of memory (errno is set to ENOMEM).
6998  */
6999 static char *
7000 read_pkg_data(FILE *fp)
7001 {
7002 	char *start;
7003 	char *inp;
7004 	char *p;
7005 	int char_cnt = 0;
7006 
7007 	errno = 0;
7008 	if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) {
7009 		errno = ENOMEM;
7010 		return (NULL);
7011 	}
7012 
7013 	inp = start;
7014 	while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) {
7015 		int len;
7016 
7017 		len = strlen(inp);
7018 		if (inp[len - 1] == '\n' &&
7019 		    (len == 1 || inp[len - 2] != '\\')) {
7020 			char_cnt = len;
7021 			break;
7022 		}
7023 
7024 		if (inp[len - 2] == '\\')
7025 			char_cnt += len - 2;
7026 		else
7027 			char_cnt += PKGINFO_RD_LEN - 1;
7028 
7029 		if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) {
7030 			errno = ENOMEM;
7031 			break;
7032 		}
7033 
7034 		start = p;
7035 		inp = start + char_cnt;
7036 	}
7037 
7038 	if (errno == ENOMEM || (p == NULL && char_cnt == 0)) {
7039 		free(start);
7040 		start = NULL;
7041 	}
7042 
7043 	return (start);
7044 }
7045 
7046 static void
7047 free_ipd_pkgs(char **pkgs, int cnt)
7048 {
7049 	int i;
7050 
7051 	for (i = 0; i < cnt; i++)
7052 		free(pkgs[i]);
7053 	free(pkgs);
7054 }
7055 
7056 /*
7057  * Get a list of the inherited pkg dirs or fs entries configured for the
7058  * zone.  The type parameter will be either ZONE_IPD or ZONE_FS.
7059  */
7060 static int
7061 get_ipd_fs_list(zone_dochandle_t handle, enum zn_ipd_fs type, char ***list)
7062 {
7063 	int	res;
7064 	struct zone_fstab fstab;
7065 	int	cnt = 0;
7066 	char	**entries = NULL;
7067 	int	i;
7068 	int	(*fp)(zone_dochandle_t, struct zone_fstab *);
7069 
7070 	if (type == ZONE_IPD) {
7071 		fp = zonecfg_getipdent;
7072 		res = zonecfg_setipdent(handle);
7073 	} else {
7074 		fp = zonecfg_getfsent;
7075 		res = zonecfg_setfsent(handle);
7076 	}
7077 
7078 	if (res != Z_OK)
7079 		return (res);
7080 
7081 	while (fp(handle, &fstab) == Z_OK) {
7082 		char	**p;
7083 
7084 		if ((p = (char **)realloc(entries,
7085 		    sizeof (char *) * (cnt + 1))) == NULL) {
7086 			res = Z_NOMEM;
7087 			break;
7088 		}
7089 		entries = p;
7090 
7091 		if ((entries[cnt] = strdup(fstab.zone_fs_dir)) == NULL) {
7092 			res = Z_NOMEM;
7093 			break;
7094 		}
7095 
7096 		cnt++;
7097 	}
7098 
7099 	if (type == ZONE_IPD)
7100 		(void) zonecfg_endipdent(handle);
7101 	else
7102 		(void) zonecfg_endfsent(handle);
7103 
7104 	/* Add a NULL terminating element. */
7105 	if (res == Z_OK) {
7106 		char	**p;
7107 
7108 		if ((p = (char **)realloc(entries,
7109 		    sizeof (char *) * (cnt + 1))) == NULL) {
7110 			res = Z_NOMEM;
7111 		} else {
7112 			entries = p;
7113 			entries[cnt] = NULL;
7114 		}
7115 	}
7116 
7117 	if (res != Z_OK) {
7118 		if (entries != NULL) {
7119 			for (i = 0; i < cnt; i++)
7120 				free(entries[i]);
7121 			free(entries);
7122 		}
7123 		return (res);
7124 	}
7125 
7126 	*list = entries;
7127 	return (Z_OK);
7128 }
7129 
7130 /*
7131  * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the
7132  * list of pkgs that deliver into those dirs.
7133  */
7134 static int
7135 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt)
7136 {
7137 	int	res;
7138 	char	**ipds;
7139 	char	**fss;
7140 	int	pkg_cnt = 0;
7141 	char	**pkgs = NULL;
7142 	int	i;
7143 
7144 	if ((res = get_ipd_fs_list(handle, ZONE_IPD, &ipds)) != Z_OK)
7145 		return (res);
7146 
7147 	if ((res = get_ipd_fs_list(handle, ZONE_FS, &fss)) != Z_OK) {
7148 		for (i = 0; ipds[i] != NULL; i++)
7149 			free(ipds[i]);
7150 		free(ipds);
7151 		return (res);
7152 	}
7153 
7154 	/* We only have to process the contents file if we have ipds. */
7155 	if (ipds != NULL) {
7156 		FILE	*fp;
7157 
7158 		if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) {
7159 			char	*buf;
7160 			char	*pkg_warn = NULL;
7161 
7162 			while ((buf = read_pkg_data(fp)) != NULL) {
7163 				res = get_path_pkgs(buf, ipds, fss, &pkgs,
7164 				    &pkg_cnt, &pkg_warn);
7165 				free(buf);
7166 				if (res != Z_OK)
7167 					break;
7168 			}
7169 
7170 			(void) fclose(fp);
7171 
7172 			if (pkg_warn != NULL) {
7173 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
7174 				    "WARNING: package operation in progress "
7175 				    "on the following packages:\n   %s\n"),
7176 				    pkg_warn);
7177 				free(pkg_warn);
7178 			}
7179 		}
7180 	}
7181 
7182 	for (i = 0; ipds[i] != NULL; i++)
7183 		free(ipds[i]);
7184 	free(ipds);
7185 
7186 	for (i = 0; fss[i] != NULL; i++)
7187 		free(fss[i]);
7188 	free(fss);
7189 
7190 	if (res != Z_OK) {
7191 		free_ipd_pkgs(pkgs, pkg_cnt);
7192 	} else {
7193 		*pkg_list = pkgs;
7194 		*cnt = pkg_cnt;
7195 	}
7196 
7197 	return (res);
7198 }
7199 
7200 /*
7201  * Return true if pkg_name is in the list of pkgs that deliver into an
7202  * inherited pkg directory for the zone.
7203  */
7204 static boolean_t
7205 dir_pkg(char *pkg_name, char **pkg_list, int cnt)
7206 {
7207 	int i;
7208 
7209 	for (i = 0; i < cnt; i++) {
7210 		if (strcmp(pkg_name, pkg_list[i]) == 0)
7211 			return (B_TRUE);
7212 	}
7213 
7214 	return (B_FALSE);
7215 }
7216 
7217 /*
7218  * Keep track of obsoleted patches for this specific patch.  We don't need to
7219  * keep track of the patch version since once a patch is obsoleted, all prior
7220  * versions are also obsolete and there won't be any new versions.
7221  */
7222 static int
7223 add_obs_patch(patch_node_t *patch, char *num, uu_list_pool_t *patches_pool)
7224 {
7225 	obs_patch_node_t *obs;
7226 
7227 	if (patch->obs_patches == NULL) {
7228 		if ((patch->obs_patches = uu_list_create(patches_pool, NULL,
7229 		    0)) == NULL)
7230 			return (Z_NOMEM);
7231 	}
7232 
7233 	if ((obs = (obs_patch_node_t *)malloc(sizeof (obs_patch_node_t)))
7234 	    == NULL)
7235 		return (Z_NOMEM);
7236 
7237 	if ((obs->patch_num = strdup(num)) == NULL) {
7238 		free(obs);
7239 		return (Z_NOMEM);
7240 	}
7241 
7242 	uu_list_node_init(obs, &obs->link, patches_pool);
7243 	(void) uu_list_insert_before(patch->obs_patches, NULL, obs);
7244 
7245 	return (Z_OK);
7246 }
7247 
7248 /*
7249  * Keep track of obsoleted patches.  We don't need to keep track of the patch
7250  * version since once a patch is obsoleted, all prior versions are also
7251  * obsolete and there won't be any new versions.
7252  */
7253 static int
7254 save_obs_patch(char *num, uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches)
7255 {
7256 	patch_node_t	*patch;
7257 	uu_avl_index_t where;
7258 
7259 	if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL)
7260 		return (Z_NOMEM);
7261 
7262 	if ((patch->patch_num = strdup(num)) == NULL) {
7263 		free(patch);
7264 		return (Z_NOMEM);
7265 	}
7266 
7267 	patch->patch_vers = NULL;
7268 	patch->obs_patches = NULL;
7269 
7270 	uu_avl_node_init(patch, &patch->patch_node, patches_pool);
7271 
7272 	if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL) {
7273 		free(patch->patch_num);
7274 		free(patch);
7275 		return (Z_OK);
7276 	}
7277 
7278 	uu_avl_insert(obs_patches, patch, where);
7279 	return (Z_OK);
7280 }
7281 
7282 /*
7283  * Keep a list of patches for a pkg.  If we see a newer version of a patch,
7284  * we only keep track of the newer version.
7285  */
7286 static void
7287 save_patch(patch_node_t *patch, uu_avl_t *patches_avl)
7288 {
7289 	patch_node_t *existing;
7290 	uu_avl_index_t where;
7291 
7292 	/*
7293 	 * Check if this is a newer version of a patch we already have.
7294 	 * If it is an older version of a patch we already have, ignore it.
7295 	 */
7296 	if ((existing = (patch_node_t *)uu_avl_find(patches_avl, patch, NULL,
7297 	    &where)) != NULL) {
7298 		char *endptr;
7299 		ulong_t pvers, evers;
7300 
7301 		pvers = strtoul(patch->patch_vers, &endptr, 10);
7302 		evers = strtoul(existing->patch_vers, &endptr, 10);
7303 
7304 		if (pvers > evers) {
7305 			free(existing->patch_vers);
7306 			existing->patch_vers = patch->patch_vers;
7307 		} else {
7308 			free(patch->patch_vers);
7309 		}
7310 		free(patch->patch_num);
7311 		free(patch);
7312 		return;
7313 	}
7314 
7315 	uu_avl_insert(patches_avl, patch, where);
7316 }
7317 
7318 /*
7319  * Check if a patch is on the list of obsoleted patches.  We don't need to
7320  * check the patch version since once a patch is obsoleted, all prior versions
7321  * are also obsolete and there won't be any new versions.
7322  */
7323 static boolean_t
7324 obsolete_patch(patch_node_t *patch, uu_avl_t *obs_patches)
7325 {
7326 	uu_avl_index_t	where;
7327 
7328 	if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL)
7329 		return (B_TRUE);
7330 
7331 	return (B_FALSE);
7332 }
7333 
7334 /* ARGSUSED */
7335 static int
7336 patch_node_compare(const void *l_arg, const void *r_arg, void *private)
7337 {
7338 	patch_node_t *l = (patch_node_t *)l_arg;
7339 	patch_node_t *r = (patch_node_t *)r_arg;
7340 	char *endptr;
7341 	ulong_t lnum, rnum;
7342 
7343 	lnum = strtoul(l->patch_num, &endptr, 10);
7344 	rnum = strtoul(r->patch_num, &endptr, 10);
7345 
7346 	if (lnum > rnum)
7347 		return (1);
7348 	if (lnum < rnum)
7349 		return (-1);
7350 	return (0);
7351 }
7352 
7353 /*
7354  * Parse the patchinfo string for the patch.
7355  *
7356  * We are parsing entries of the form:
7357  * PATCH_INFO_121454-02=Installed: Wed Dec  7 07:13:51 PST 2005 From: mum \
7358  *	Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \
7359  *	119255-06 Incompatibles:
7360  *
7361  * A backed out patch will have "backed out\n" as the status.  We should
7362  * skip these patches.  We also ignore any entries that seem to be
7363  * corrupted.  Obsolete patches are saved in the obs_patches parameter
7364  * AVL list.
7365  */
7366 static int
7367 parse_info(char *patchinfo, uu_avl_pool_t *patches_pool, uu_avl_t *patches_avl,
7368     uu_avl_t *obs_patches, uu_list_pool_t *list_pool)
7369 {
7370 	char		*p;
7371 	char		*lastp;
7372 	char		*ep;
7373 	char		*pvers;
7374 	boolean_t	add_info = B_FALSE;
7375 	patch_node_t	*patch;
7376 
7377 	if (strlen(patchinfo) < (sizeof (PATCHINFO) - 1))
7378 		return (Z_OK);
7379 
7380 	/* Skip over "PATCH_INFO_" to get the patch id. */
7381 	p = patchinfo + sizeof (PATCHINFO) - 1;
7382 	if ((ep = strchr(p, '=')) == NULL)
7383 		return (Z_OK);
7384 
7385 	*ep++ = '\0';
7386 
7387 	/* Ignore all but installed patches. */
7388 	if (strncmp(ep, "Installed:", 10) != 0)
7389 		return (Z_OK);
7390 
7391 	/* remove newline */
7392 	lastp = (ep + strlen(ep) - 1);
7393 	if (*lastp == '\n')
7394 		*lastp = '\0';
7395 
7396 	if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL)
7397 		return (Z_NOMEM);
7398 
7399 	if ((pvers = strchr(p, '-')) != NULL)
7400 		*pvers++ = '\0';
7401 	else
7402 		pvers = "";
7403 
7404 	if ((patch->patch_num = strdup(p)) == NULL) {
7405 		free(patch);
7406 		return (Z_NOMEM);
7407 	}
7408 	if ((patch->patch_vers = strdup(pvers)) == NULL) {
7409 		free(patch->patch_num);
7410 		free(patch);
7411 		return (Z_NOMEM);
7412 	}
7413 	patch->obs_patches = NULL;
7414 
7415 	uu_avl_node_init(patch, &patch->patch_node, patches_pool);
7416 	save_patch(patch, patches_avl);
7417 
7418 	/*
7419 	 * Start with the first token.  This will probably be "Installed:".
7420 	 * If we can't tokenize this entry, just return.
7421 	 */
7422 	if ((p = strtok_r(ep, " ", &lastp)) == NULL)
7423 		return (Z_OK);
7424 
7425 	do {
7426 		if (strcmp(p, "Installed:") == 0 ||
7427 		    strcmp(p, "Requires:") == 0 ||
7428 		    strcmp(p, "From:") == 0 ||
7429 		    strcmp(p, "Incompatibles:") == 0) {
7430 			add_info = B_FALSE;
7431 			continue;
7432 		} else if (strcmp(p, "Obsoletes:") == 0) {
7433 			add_info = B_TRUE;
7434 			continue;
7435 		}
7436 
7437 		if (!add_info)
7438 			continue;
7439 
7440 		if ((pvers = strchr(p, '-')) != NULL)
7441 			*pvers = '\0';
7442 
7443 		/*
7444 		 * We save all of the obsolete patches in one big list in the
7445 		 * obs_patches AVL tree so that we know not to output those as
7446 		 * part of the sw dependencies.  However, we also need to save
7447 		 * the obsolete patch information for this sepcific patch so
7448 		 * so that we can do the cross manifest patch checking
7449 		 * correctly.
7450 		 */
7451 		if (save_obs_patch(p, patches_pool, obs_patches) != Z_OK)
7452 			return (Z_NOMEM);
7453 		if (add_obs_patch(patch, p, list_pool) != Z_OK)
7454 			return (Z_NOMEM);
7455 	} while ((p = strtok_r(NULL, " ", &lastp)) != NULL);
7456 
7457 	return (Z_OK);
7458 }
7459 
7460 /*
7461  * AVL walker callback used to add patch to XML manifest.
7462  *
7463  * PATH_MAX is used in the pkg/patch code as the maximum size for the patch
7464  * number/version string.
7465  */
7466 static int
7467 add_patch(void *e, void *p)
7468 {
7469 	xmlNodePtr	node;
7470 	xmlNodePtr	cur;
7471 	char		id[PATH_MAX];
7472 	patch_node_t	*patch;
7473 	patch_parms_t	*args;
7474 
7475 	patch = e;
7476 	args = p;
7477 
7478 	/* skip this patch if it has been obsoleted */
7479 	if (obsolete_patch(patch, args->obs_patches_avl))
7480 		return (UU_WALK_NEXT);
7481 
7482 	if (patch->patch_vers[0] == '\0')
7483 		(void) snprintf(id, sizeof (id), "%s", patch->patch_num);
7484 	else
7485 		(void) snprintf(id, sizeof (id), "%s-%s", patch->patch_num,
7486 		    patch->patch_vers);
7487 
7488 	if ((args->res = operation_prep(args->handle)) != Z_OK)
7489 		return (UU_WALK_DONE);
7490 
7491 	cur = args->handle->zone_dh_cur;
7492 	node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL);
7493 	if ((args->res = newprop(node, DTD_ATTR_ID, id)) != Z_OK)
7494 		return (UU_WALK_DONE);
7495 
7496 	if (patch->obs_patches != NULL) {
7497 		obs_patch_node_t *op;
7498 		xmlNodePtr	node2;
7499 
7500 		for (op = uu_list_first(patch->obs_patches); op != NULL;
7501 		    op = uu_list_next(patch->obs_patches, op)) {
7502 			(void) snprintf(id, sizeof (id), "%s", op->patch_num);
7503 			node2 = xmlNewTextChild(node, NULL, DTD_ELEM_OBSOLETES,
7504 			    NULL);
7505 			if ((args->res = newprop(node2, DTD_ATTR_ID, id))
7506 			    != Z_OK)
7507 				return (UU_WALK_DONE);
7508 		}
7509 	}
7510 
7511 	return (UU_WALK_NEXT);
7512 }
7513 
7514 static void
7515 patch_avl_delete(uu_avl_t *patches_avl)
7516 {
7517 	if (patches_avl != NULL) {
7518 		patch_node_t *p;
7519 		void *cookie = NULL;
7520 
7521 		while ((p = (patch_node_t *)uu_avl_teardown(patches_avl,
7522 		    &cookie)) != NULL) {
7523 			free(p->patch_num);
7524 			free(p->patch_vers);
7525 
7526 			if (p->obs_patches != NULL) {
7527 				obs_patch_node_t *op;
7528 				void *cookie2 = NULL;
7529 
7530 				while ((op = uu_list_teardown(p->obs_patches,
7531 				    &cookie2)) != NULL) {
7532 					free(op->patch_num);
7533 					free(op);
7534 				}
7535 				uu_list_destroy(p->obs_patches);
7536 			}
7537 
7538 			free(p);
7539 		}
7540 
7541 		uu_avl_destroy(patches_avl);
7542 	}
7543 }
7544 
7545 /*
7546  * Add the unique, highest version patches that are associated with this pkg
7547  * to the sw inventory on the handle.
7548  */
7549 static int
7550 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop,
7551     uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches,
7552     uu_list_pool_t *list_pool)
7553 {
7554 	int		i;
7555 	int		res;
7556 	uu_avl_t 	*patches_avl;
7557 	patch_parms_t	args;
7558 
7559 	if ((patches_avl = uu_avl_create(patches_pool, NULL, UU_DEFAULT))
7560 	    == NULL)
7561 		return (Z_NOMEM);
7562 
7563 	for (i = 0; i < infop->zpi_patch_cnt; i++) {
7564 		if ((res = parse_info(infop->zpi_patchinfo[i], patches_pool,
7565 		    patches_avl, obs_patches, list_pool)) != Z_OK) {
7566 			patch_avl_delete(patches_avl);
7567 			return (res);
7568 		}
7569 	}
7570 
7571 	args.obs_patches_avl = obs_patches;
7572 	args.handle = handle;
7573 	args.res = Z_OK;
7574 
7575 	(void) uu_avl_walk(patches_avl, add_patch, &args, 0);
7576 
7577 	patch_avl_delete(patches_avl);
7578 	return (args.res);
7579 }
7580 
7581 /*
7582  * Keep track of the pkgs we have already processed so that we can quickly
7583  * skip those pkgs while recursively doing dependents.
7584  */
7585 static boolean_t
7586 pkg_in_manifest(uu_avl_t *saw_pkgs, char *pname, uu_avl_pool_t *pkgs_pool)
7587 {
7588 	uu_avl_index_t where;
7589 
7590 	if (uu_avl_find(saw_pkgs, pname, NULL, &where) == NULL) {
7591 		zone_pkg_entry_t *pkg;
7592 
7593 		/*
7594 		 * We need to add it.  If we don't have memory we just skip
7595 		 * this pkg since this routine improves performance but the
7596 		 * algorithm is still correct without it.
7597 		 */
7598 		if ((pkg = (zone_pkg_entry_t *)
7599 		    malloc(sizeof (zone_pkg_entry_t))) == NULL)
7600 			return (B_FALSE);
7601 
7602 		if ((pkg->zpe_name = strdup(pname)) == NULL) {
7603 			free(pkg);
7604 			return (B_FALSE);
7605 		}
7606 
7607 		pkg->zpe_vers = NULL;
7608 		pkg->zpe_patches_avl = NULL;
7609 
7610 		/* Insert pkg into the AVL tree. */
7611 		uu_avl_node_init(pkg, &pkg->zpe_entry, pkgs_pool);
7612 		uu_avl_insert(saw_pkgs, pkg, where);
7613 		return (B_FALSE);
7614 	}
7615 
7616 	return (B_TRUE);
7617 }
7618 
7619 /*
7620  * Add the pkg to the sw inventory on the handle.
7621  */
7622 static int
7623 add_pkg(zone_dochandle_t handle, char *name, char *version)
7624 {
7625 	xmlNodePtr newnode;
7626 	xmlNodePtr cur;
7627 	int err;
7628 
7629 	if ((err = operation_prep(handle)) != Z_OK)
7630 		return (err);
7631 
7632 	cur = handle->zone_dh_cur;
7633 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL);
7634 	if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK)
7635 		return (err);
7636 	if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK)
7637 		return (err);
7638 	return (Z_OK);
7639 }
7640 
7641 static void
7642 free_pkginfo(struct zone_pkginfo *infop)
7643 {
7644 	free(infop->zpi_version);
7645 	if (infop->zpi_patch_cnt > 0) {
7646 		int i;
7647 
7648 		for (i = 0; i < infop->zpi_patch_cnt; i++)
7649 			free(infop->zpi_patchinfo[i]);
7650 		free(infop->zpi_patchinfo);
7651 	}
7652 }
7653 
7654 /*
7655  * Read the pkginfo file and populate the structure with the data we need
7656  * from this pkg for a sw inventory.
7657  */
7658 static int
7659 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop)
7660 {
7661 	FILE	*fp;
7662 	char	*buf;
7663 	int	err = 0;
7664 
7665 	infop->zpi_all_zones = B_FALSE;
7666 	infop->zpi_this_zone = B_FALSE;
7667 	infop->zpi_version = NULL;
7668 	infop->zpi_patch_cnt = 0;
7669 	infop->zpi_patchinfo = NULL;
7670 
7671 	if ((fp = fopen(pkginfo, "r")) == NULL)
7672 		return (errno);
7673 
7674 	while ((buf = read_pkg_data(fp)) != NULL) {
7675 		if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) {
7676 			int len;
7677 
7678 			if ((infop->zpi_version =
7679 			    strdup(buf + sizeof (VERSION) - 1)) == NULL) {
7680 				err = ENOMEM;
7681 				break;
7682 			}
7683 
7684 			/* remove trailing newline */
7685 			len = strlen(infop->zpi_version);
7686 			*(infop->zpi_version + len - 1) = 0;
7687 
7688 		} else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) {
7689 			infop->zpi_all_zones = B_TRUE;
7690 
7691 		} else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) {
7692 			infop->zpi_this_zone = B_TRUE;
7693 
7694 		} else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1)
7695 		    == 0) {
7696 			char **p;
7697 
7698 			if ((p = (char **)realloc(infop->zpi_patchinfo,
7699 			    sizeof (char *) * (infop->zpi_patch_cnt + 1)))
7700 			    == NULL) {
7701 				err = ENOMEM;
7702 				break;
7703 			}
7704 			infop->zpi_patchinfo = p;
7705 
7706 			if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] =
7707 			    strdup(buf)) == NULL) {
7708 				err = ENOMEM;
7709 				break;
7710 			}
7711 			infop->zpi_patch_cnt++;
7712 		}
7713 
7714 		free(buf);
7715 	}
7716 
7717 	free(buf);
7718 
7719 	if (errno == ENOMEM) {
7720 		err = ENOMEM;
7721 		/* Clean up anything we did manage to allocate. */
7722 		free_pkginfo(infop);
7723 	}
7724 
7725 	(void) fclose(fp);
7726 
7727 	return (err);
7728 }
7729 
7730 /*
7731  * Add any dependent pkgs to the list.  The pkg depend file lists pkg
7732  * dependencies, one per line with an entry that looks like:
7733  *	P SUNWcar       Core Architecture, (Root)
7734  * See the depend(4) man page.
7735  */
7736 static int
7737 add_dependents(zone_dochandle_t handle, char *pname,
7738     uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches,
7739     uu_list_pool_t *list_pool, uu_avl_t *saw_pkgs, uu_avl_pool_t *pkgs_pool)
7740 {
7741 	int		res = Z_OK;
7742 	FILE		*fp;
7743 	char		depend[MAXPATHLEN];
7744 	char		*buf;
7745 	struct stat	sbuf;
7746 
7747 	(void) snprintf(depend, sizeof (depend), "%s/%s/install/depend",
7748 	    PKG_PATH, pname);
7749 
7750 	if (stat(depend, &sbuf) == -1 || !S_ISREG(sbuf.st_mode))
7751 		return (Z_OK);
7752 
7753 	if ((fp = fopen(depend, "r")) == NULL)
7754 		return (Z_OK);
7755 
7756 	while ((buf = read_pkg_data(fp)) != NULL) {
7757 		char *deppkg;
7758 		char *delims = " \t";
7759 		char pkginfo[MAXPATHLEN];
7760 		struct zone_pkginfo info;
7761 
7762 		if (*buf != 'P') {
7763 			free(buf);
7764 			continue;
7765 		}
7766 
7767 		/* Skip past the leading 'P '. */
7768 		if ((deppkg = strtok(buf + 2, delims)) == NULL) {
7769 			free(buf);
7770 			continue;
7771 		}
7772 
7773 		/* If the pkg is already in the manifest don't add it again. */
7774 		if (pkg_in_manifest(saw_pkgs, deppkg, pkgs_pool)) {
7775 			free(buf);
7776 			continue;
7777 		}
7778 
7779 		(void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo",
7780 		    PKG_PATH, deppkg);
7781 
7782 		if (stat(pkginfo, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) {
7783 			free(buf);
7784 			continue;
7785 		}
7786 
7787 		if (get_pkginfo(pkginfo, &info) != 0) {
7788 			res = Z_NOMEM;
7789 			free(buf);
7790 			break;
7791 		}
7792 
7793 		if ((res = add_dependents(handle, deppkg, patches_pool,
7794 		    obs_patches, list_pool, saw_pkgs, pkgs_pool)) == Z_OK &&
7795 		    (res = add_pkg(handle, deppkg, info.zpi_version)) == Z_OK) {
7796 			if (info.zpi_patch_cnt > 0)
7797 				res = add_patches(handle, &info, patches_pool,
7798 				    obs_patches, list_pool);
7799 		}
7800 
7801 		free(buf);
7802 		free_pkginfo(&info);
7803 
7804 		if (res != Z_OK)
7805 			break;
7806 	}
7807 
7808 	(void) fclose(fp);
7809 	return (res);
7810 }
7811 
7812 /* ARGSUSED */
7813 static int
7814 pkg_entry_compare(const void *l_arg, const void *r_arg, void *private)
7815 {
7816 	zone_pkg_entry_t *pkg = (zone_pkg_entry_t *)l_arg;
7817 	char *name = (char *)r_arg;
7818 
7819 	return (strcmp(pkg->zpe_name, name));
7820 }
7821 
7822 static void
7823 pkg_avl_delete(uu_avl_t *pavl)
7824 {
7825 	if (pavl != NULL) {
7826 		zone_pkg_entry_t *p;
7827 		void *cookie = NULL;
7828 
7829 		while ((p = uu_avl_teardown(pavl, &cookie)) != NULL) {
7830 			free(p->zpe_name);
7831 			free(p);
7832 		}
7833 
7834 		uu_avl_destroy(pavl);
7835 	}
7836 }
7837 
7838 /*
7839  * Take a software inventory of the global zone.  We need to get the set of
7840  * packages and patches that are on the global zone that the specified
7841  * non-global zone depends on.  The packages we need in the inventory are:
7842  *
7843  * - skip the package if SUNW_PKG_THISZONE is 'true'
7844  * otherwise,
7845  * - add the package if
7846  * a) SUNW_PKG_ALLZONES is 'true',
7847  * or
7848  * b) any file delivered by the package is in a file system that is inherited
7849  * from the global zone.
7850  * If the zone does not inherit any file systems (whole root)
7851  * then (b) will be skipped.
7852  *
7853  * For each of the packages that is being added to the inventory, we will also
7854  * add its dependent packages to the inventory.
7855  *
7856  * For each of the packages that is being added to the inventory, we will also
7857  * add all of the associated, unique patches to the inventory.
7858  *
7859  * See the comment for zonecfg_getpkgdata() for compatability restrictions on
7860  * how we must save the XML representation of the software inventory.
7861  */
7862 static int
7863 zonecfg_sw_inventory(zone_dochandle_t handle)
7864 {
7865 	char		pkginfo[MAXPATHLEN];
7866 	int		res;
7867 	struct dirent	*dp;
7868 	DIR		*dirp;
7869 	struct stat	buf;
7870 	struct zone_pkginfo	info;
7871 	int		pkg_cnt = 0;
7872 	char		**pkgs = NULL;
7873 	uu_avl_pool_t 	*pkgs_pool = NULL;
7874 	uu_avl_pool_t 	*patches_pool = NULL;
7875 	uu_list_pool_t 	*list_pool = NULL;
7876 	uu_avl_t	*saw_pkgs = NULL;
7877 	uu_avl_t 	*obs_patches = NULL;
7878 
7879 	if ((pkgs_pool = uu_avl_pool_create("pkgs_pool",
7880 	    sizeof (zone_pkg_entry_t), offsetof(zone_pkg_entry_t, zpe_entry),
7881 	    pkg_entry_compare, UU_DEFAULT)) == NULL) {
7882 		res = Z_NOMEM;
7883 		goto done;
7884 	}
7885 
7886 	if ((saw_pkgs = uu_avl_create(pkgs_pool, NULL, UU_DEFAULT)) == NULL) {
7887 		res = Z_NOMEM;
7888 		goto done;
7889 	}
7890 
7891 	if ((patches_pool = uu_avl_pool_create("patches_pool",
7892 	    sizeof (patch_node_t), offsetof(patch_node_t, patch_node),
7893 	    patch_node_compare, UU_DEFAULT)) == NULL) {
7894 		res = Z_NOMEM;
7895 		goto done;
7896 	}
7897 
7898 	if ((list_pool = uu_list_pool_create("list_pool",
7899 	    sizeof (obs_patch_node_t), offsetof(obs_patch_node_t, link), NULL,
7900 	    UU_DEFAULT)) == NULL) {
7901 		res = Z_NOMEM;
7902 		goto done;
7903 	}
7904 
7905 	/*
7906 	 * The obs_patches AVL tree saves all of the obsolete patches so
7907 	 * that we know not to output those as part of the sw dependencies.
7908 	 */
7909 	if ((obs_patches = uu_avl_create(patches_pool, NULL, UU_DEFAULT))
7910 	    == NULL) {
7911 		res = Z_NOMEM;
7912 		goto done;
7913 	}
7914 
7915 	if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) {
7916 		res = Z_NOMEM;
7917 		goto done;
7918 	}
7919 
7920 	if ((dirp = opendir(PKG_PATH)) == NULL) {
7921 		res = Z_NOMEM;
7922 		goto done;
7923 	}
7924 
7925 	while ((dp = readdir(dirp)) != (struct dirent *)0) {
7926 		if (strcmp(dp->d_name, ".") == 0 ||
7927 		    strcmp(dp->d_name, "..") == 0)
7928 			continue;
7929 
7930 		(void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo",
7931 		    PKG_PATH, dp->d_name);
7932 
7933 		if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode))
7934 			continue;
7935 
7936 		if (get_pkginfo(pkginfo, &info) != 0) {
7937 			res = Z_NOMEM;
7938 			break;
7939 		}
7940 
7941 		if (!info.zpi_this_zone &&
7942 		    (info.zpi_all_zones ||
7943 		    dir_pkg(dp->d_name, pkgs, pkg_cnt)) &&
7944 		    !pkg_in_manifest(saw_pkgs, dp->d_name, pkgs_pool)) {
7945 			/*
7946 			 * Add dependents first so any patches will get
7947 			 * associated with the right pkg in the xml file.
7948 			 */
7949 			if ((res = add_dependents(handle, dp->d_name,
7950 			    patches_pool, obs_patches, list_pool, saw_pkgs,
7951 			    pkgs_pool)) == Z_OK &&
7952 			    (res = add_pkg(handle, dp->d_name,
7953 			    info.zpi_version)) == Z_OK) {
7954 				if (info.zpi_patch_cnt > 0)
7955 					res = add_patches(handle, &info,
7956 					    patches_pool, obs_patches,
7957 					    list_pool);
7958 			}
7959 		}
7960 
7961 		free_pkginfo(&info);
7962 
7963 		if (res != Z_OK)
7964 			break;
7965 	}
7966 
7967 	(void) closedir(dirp);
7968 
7969 done:
7970 	pkg_avl_delete(saw_pkgs);
7971 	patch_avl_delete(obs_patches);
7972 	if (pkgs_pool != NULL)
7973 		uu_avl_pool_destroy(pkgs_pool);
7974 	if (patches_pool != NULL)
7975 		uu_avl_pool_destroy(patches_pool);
7976 	if (list_pool != NULL)
7977 		uu_list_pool_destroy(list_pool);
7978 	free_ipd_pkgs(pkgs, pkg_cnt);
7979 
7980 	if (res == Z_OK)
7981 		handle->zone_dh_sw_inv = B_TRUE;
7982 
7983 	return (res);
7984 }
7985 
7986 /*
7987  * zonecfg_devwalk call-back function used during detach to generate the
7988  * dev info in the manifest.
7989  */
7990 static int
7991 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
7992     const char *acl, void *hdl)
7993 {
7994 	zone_dochandle_t handle = (zone_dochandle_t)hdl;
7995 	xmlNodePtr newnode;
7996 	xmlNodePtr cur;
7997 	int err;
7998 	char buf[128];
7999 
8000 	if ((err = operation_prep(handle)) != Z_OK)
8001 		return (err);
8002 
8003 	cur = handle->zone_dh_cur;
8004 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
8005 	if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
8006 		return (err);
8007 	(void) snprintf(buf, sizeof (buf), "%lu", uid);
8008 	if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
8009 		return (err);
8010 	(void) snprintf(buf, sizeof (buf), "%lu", gid);
8011 	if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
8012 		return (err);
8013 	(void) snprintf(buf, sizeof (buf), "%o", mode);
8014 	if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
8015 		return (err);
8016 	if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
8017 		return (err);
8018 	return (Z_OK);
8019 }
8020 
8021 /*
8022  * Get the information required to support detaching a zone.  This is
8023  * called on the source system when detaching (the detaching parameter should
8024  * be set to true) and on the destination system before attaching (the
8025  * detaching parameter should be false).
8026  *
8027  * For native Solaris zones, the detach/attach process involves validating
8028  * that the software on the global zone can support the zone when we attach.
8029  * To do this we take a software inventory of the global zone.  We also
8030  * have to keep track of the device configuration so that we can properly
8031  * recreate it on the destination.
8032  */
8033 int
8034 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching)
8035 {
8036 	int		res;
8037 
8038 	if ((res = zonecfg_sw_inventory(handle)) != Z_OK)
8039 		return (res);
8040 
8041 	if (detaching)
8042 		res = zonecfg_devwalk(handle, get_detach_dev_entry, handle);
8043 
8044 	return (res);
8045 }
8046