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