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