xref: /titanic_41/usr/src/lib/libzonecfg/common/libzonecfg.c (revision 9113a79cf228b8f7bd509b1328adf88659dfe218)
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 (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone,
5024 		    sizeof (myzone)) < 0)
5025 			return (Z_NO_ZONE);
5026 		if (strncmp(zone_name, myzone, MAXNAMELEN) != NULL)
5027 			return (Z_NO_ZONE);
5028 		err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz);
5029 		if (err < 0)
5030 			return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5031 		return (Z_OK);
5032 	}
5033 
5034 	if (strcmp(zone_name, "global") == NULL) {
5035 		(void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz);
5036 		return (0);
5037 	}
5038 	if ((handle = zonecfg_init_handle()) == NULL)
5039 		return (Z_NOMEM);
5040 
5041 	err = zonecfg_get_handle((char *)zone_name, handle);
5042 	if (err == Z_OK)
5043 		err = zonecfg_get_brand(handle, brandname, rp_sz);
5044 
5045 	zonecfg_fini_handle(handle);
5046 	return (err);
5047 }
5048 
5049 /*
5050  * Return the appropriate root for the active /dev.
5051  * For normal zone, the path is $ZONEPATH/root;
5052  * for scratch zone, the dev path is $ZONEPATH/lu.
5053  */
5054 int
5055 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5056 {
5057 	int err;
5058 	char *suffix;
5059 	zone_state_t state;
5060 
5061 	/* This function makes sense for non-global zones only. */
5062 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5063 		return (Z_BOGUS_ZONE_NAME);
5064 	if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5065 		return (err);
5066 
5067 	if (zone_get_state(zone_name, &state) == Z_OK &&
5068 	    state == ZONE_STATE_MOUNTED)
5069 		suffix = "/lu";
5070 	else
5071 		suffix = "/root";
5072 	if (strlcat(devroot, suffix, rp_sz) >= rp_sz)
5073 		return (Z_TOO_BIG);
5074 	return (Z_OK);
5075 }
5076 
5077 static zone_state_t
5078 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state)
5079 {
5080 	char zoneroot[MAXPATHLEN];
5081 	size_t zlen;
5082 
5083 	assert(kernel_state <= ZONE_MAX_STATE);
5084 	switch (kernel_state) {
5085 		case ZONE_IS_UNINITIALIZED:
5086 			return (ZONE_STATE_READY);
5087 		case ZONE_IS_READY:
5088 			/*
5089 			 * If the zone's root is mounted on $ZONEPATH/lu, then
5090 			 * it's a mounted scratch zone.
5091 			 */
5092 			if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
5093 			    sizeof (zoneroot)) >= 0) {
5094 				zlen = strlen(zoneroot);
5095 				if (zlen > 3 &&
5096 				    strcmp(zoneroot + zlen - 3, "/lu") == 0)
5097 					return (ZONE_STATE_MOUNTED);
5098 			}
5099 			return (ZONE_STATE_READY);
5100 		case ZONE_IS_BOOTING:
5101 		case ZONE_IS_RUNNING:
5102 			return (ZONE_STATE_RUNNING);
5103 		case ZONE_IS_SHUTTING_DOWN:
5104 		case ZONE_IS_EMPTY:
5105 			return (ZONE_STATE_SHUTTING_DOWN);
5106 		case ZONE_IS_DOWN:
5107 		case ZONE_IS_DYING:
5108 		case ZONE_IS_DEAD:
5109 		default:
5110 			return (ZONE_STATE_DOWN);
5111 	}
5112 	/* NOTREACHED */
5113 }
5114 
5115 int
5116 zone_get_state(char *zone_name, zone_state_t *state_num)
5117 {
5118 	zone_status_t status;
5119 	zoneid_t zone_id;
5120 	struct zoneent *ze;
5121 	boolean_t found = B_FALSE;
5122 	FILE *cookie;
5123 	char kernzone[ZONENAME_MAX];
5124 	FILE *fp;
5125 
5126 	if (zone_name == NULL)
5127 		return (Z_INVAL);
5128 
5129 	/*
5130 	 * If we're looking at an alternate root, then we need to query the
5131 	 * kernel using the scratch zone name.
5132 	 */
5133 	zone_id = -1;
5134 	if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
5135 		if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
5136 			if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
5137 			    kernzone, sizeof (kernzone)) == 0)
5138 				zone_id = getzoneidbyname(kernzone);
5139 			zonecfg_close_scratch(fp);
5140 		}
5141 	} else {
5142 		zone_id = getzoneidbyname(zone_name);
5143 	}
5144 
5145 	/* check to see if zone is running */
5146 	if (zone_id != -1 &&
5147 	    zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
5148 	    sizeof (status)) >= 0) {
5149 		*state_num = kernel_state_to_user_state(zone_id, status);
5150 		return (Z_OK);
5151 	}
5152 
5153 	cookie = setzoneent();
5154 	while ((ze = getzoneent_private(cookie)) != NULL) {
5155 		if (strcmp(ze->zone_name, zone_name) == 0) {
5156 			found = B_TRUE;
5157 			*state_num = ze->zone_state;
5158 		}
5159 		free(ze);
5160 		if (found)
5161 			break;
5162 	}
5163 	endzoneent(cookie);
5164 	return ((found) ? Z_OK : Z_NO_ZONE);
5165 }
5166 
5167 int
5168 zone_set_state(char *zone, zone_state_t state)
5169 {
5170 	struct zoneent ze;
5171 
5172 	if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
5173 	    state != ZONE_STATE_INCOMPLETE)
5174 		return (Z_INVAL);
5175 
5176 	bzero(&ze, sizeof (ze));
5177 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
5178 	ze.zone_state = state;
5179 	(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
5180 	return (putzoneent(&ze, PZE_MODIFY));
5181 }
5182 
5183 /*
5184  * Get id (if any) for specified zone.  There are four possible outcomes:
5185  * - If the string corresponds to the numeric id of an active (booted)
5186  *   zone, sets *zip to the zone id and returns 0.
5187  * - If the string corresponds to the name of an active (booted) zone,
5188  *   sets *zip to the zone id and returns 0.
5189  * - If the string is a name in the configuration but is not booted,
5190  *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
5191  * - Otherwise, leaves *zip unchanged and returns -1.
5192  *
5193  * This function acts as an auxiliary filter on the function of the same
5194  * name in libc; the linker binds to this version if libzonecfg exists,
5195  * and the libc version if it doesn't.  Any changes to this version of
5196  * the function should probably be reflected in the libc version as well.
5197  */
5198 int
5199 zone_get_id(const char *str, zoneid_t *zip)
5200 {
5201 	zone_dochandle_t hdl;
5202 	zoneid_t zoneid;
5203 	char *cp;
5204 	int err;
5205 
5206 	/* first try looking for active zone by id */
5207 	errno = 0;
5208 	zoneid = (zoneid_t)strtol(str, &cp, 0);
5209 	if (errno == 0 && cp != str && *cp == '\0' &&
5210 	    getzonenamebyid(zoneid, NULL, 0) != -1) {
5211 		*zip = zoneid;
5212 		return (0);
5213 	}
5214 
5215 	/* then look for active zone by name */
5216 	if ((zoneid = getzoneidbyname(str)) != -1) {
5217 		*zip = zoneid;
5218 		return (0);
5219 	}
5220 
5221 	/* if in global zone, try looking up name in configuration database */
5222 	if (getzoneid() != GLOBAL_ZONEID ||
5223 	    (hdl = zonecfg_init_handle()) == NULL)
5224 		return (-1);
5225 
5226 	if (zonecfg_get_handle(str, hdl) == Z_OK) {
5227 		/* zone exists but isn't active */
5228 		*zip = ZONE_ID_UNDEFINED;
5229 		err = 0;
5230 	} else {
5231 		err = -1;
5232 	}
5233 
5234 	zonecfg_fini_handle(hdl);
5235 	return (err);
5236 }
5237 
5238 char *
5239 zone_state_str(zone_state_t state_num)
5240 {
5241 	switch (state_num) {
5242 	case ZONE_STATE_CONFIGURED:
5243 		return (ZONE_STATE_STR_CONFIGURED);
5244 	case ZONE_STATE_INCOMPLETE:
5245 		return (ZONE_STATE_STR_INCOMPLETE);
5246 	case ZONE_STATE_INSTALLED:
5247 		return (ZONE_STATE_STR_INSTALLED);
5248 	case ZONE_STATE_READY:
5249 		return (ZONE_STATE_STR_READY);
5250 	case ZONE_STATE_MOUNTED:
5251 		return (ZONE_STATE_STR_MOUNTED);
5252 	case ZONE_STATE_RUNNING:
5253 		return (ZONE_STATE_STR_RUNNING);
5254 	case ZONE_STATE_SHUTTING_DOWN:
5255 		return (ZONE_STATE_STR_SHUTTING_DOWN);
5256 	case ZONE_STATE_DOWN:
5257 		return (ZONE_STATE_STR_DOWN);
5258 	default:
5259 		return ("unknown");
5260 	}
5261 }
5262 
5263 /*
5264  * Given a UUID value, find an associated zone name.  This is intended to be
5265  * used by callers who set up some 'default' name (corresponding to the
5266  * expected name for the zone) in the zonename buffer, and thus the function
5267  * doesn't touch this buffer on failure.
5268  */
5269 int
5270 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen)
5271 {
5272 	FILE *fp;
5273 	struct zoneent *ze;
5274 	uchar_t *uuid;
5275 
5276 	/*
5277 	 * A small amount of subterfuge via casts is necessary here because
5278 	 * libuuid doesn't use const correctly, but we don't want to export
5279 	 * this brokenness to our clients.
5280 	 */
5281 	uuid = (uchar_t *)uuidin;
5282 	if (uuid_is_null(uuid))
5283 		return (Z_NO_ZONE);
5284 	if ((fp = setzoneent()) == NULL)
5285 		return (Z_NO_ZONE);
5286 	while ((ze = getzoneent_private(fp)) != NULL) {
5287 		if (uuid_compare(uuid, ze->zone_uuid) == 0)
5288 			break;
5289 		free(ze);
5290 	}
5291 	endzoneent(fp);
5292 	if (ze != NULL) {
5293 		(void) strlcpy(zonename, ze->zone_name, namelen);
5294 		free(ze);
5295 		return (Z_OK);
5296 	} else {
5297 		return (Z_NO_ZONE);
5298 	}
5299 }
5300 
5301 /*
5302  * Given a zone name, get its UUID.  Returns a "NULL" UUID value if the zone
5303  * exists but the file doesn't have a value set yet.  Returns an error if the
5304  * zone cannot be located.
5305  */
5306 int
5307 zonecfg_get_uuid(const char *zonename, uuid_t uuid)
5308 {
5309 	FILE *fp;
5310 	struct zoneent *ze;
5311 
5312 	if ((fp = setzoneent()) == NULL)
5313 		return (Z_NO_ZONE);
5314 	while ((ze = getzoneent_private(fp)) != NULL) {
5315 		if (strcmp(ze->zone_name, zonename) == 0)
5316 			break;
5317 		free(ze);
5318 	}
5319 	endzoneent(fp);
5320 	if (ze != NULL) {
5321 		uuid_copy(uuid, ze->zone_uuid);
5322 		free(ze);
5323 		return (Z_OK);
5324 	} else {
5325 		return (Z_NO_ZONE);
5326 	}
5327 }
5328 
5329 /*
5330  * File-system convenience functions.
5331  */
5332 boolean_t
5333 zonecfg_valid_fs_type(const char *type)
5334 {
5335 	/*
5336 	 * We already know which FS types don't work.
5337 	 */
5338 	if (strcmp(type, "proc") == 0 ||
5339 	    strcmp(type, "mntfs") == 0 ||
5340 	    strcmp(type, "autofs") == 0 ||
5341 	    strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 ||
5342 	    strcmp(type, "cachefs") == 0)
5343 		return (B_FALSE);
5344 	/*
5345 	 * The caller may do more detailed verification to make sure other
5346 	 * aspects of this filesystem type make sense.
5347 	 */
5348 	return (B_TRUE);
5349 }
5350 
5351 /*
5352  * Generally uninteresting rctl convenience functions.
5353  */
5354 
5355 int
5356 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
5357     rctlblk_t *rctlblk)
5358 {
5359 	unsigned long long ull;
5360 	char *endp;
5361 	rctl_priv_t priv;
5362 	rctl_qty_t limit;
5363 	uint_t action;
5364 
5365 	/* Get the privilege */
5366 	if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
5367 		priv = RCPRIV_BASIC;
5368 	} else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
5369 		priv = RCPRIV_PRIVILEGED;
5370 	} else {
5371 		/* Invalid privilege */
5372 		return (Z_INVAL);
5373 	}
5374 
5375 	/* deal with negative input; strtoull(3c) doesn't do what we want */
5376 	if (rctlval->zone_rctlval_limit[0] == '-')
5377 		return (Z_INVAL);
5378 	/* Get the limit */
5379 	errno = 0;
5380 	ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
5381 	if (errno != 0 || *endp != '\0') {
5382 		/* parse failed */
5383 		return (Z_INVAL);
5384 	}
5385 	limit = (rctl_qty_t)ull;
5386 
5387 	/* Get the action */
5388 	if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
5389 		action = RCTL_LOCAL_NOACTION;
5390 	} else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
5391 		action = RCTL_LOCAL_SIGNAL;
5392 	} else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
5393 		action = RCTL_LOCAL_DENY;
5394 	} else {
5395 		/* Invalid Action */
5396 		return (Z_INVAL);
5397 	}
5398 	rctlblk_set_local_action(rctlblk, action, 0);
5399 	rctlblk_set_privilege(rctlblk, priv);
5400 	rctlblk_set_value(rctlblk, limit);
5401 	return (Z_OK);
5402 }
5403 
5404 static int
5405 rctl_check(const char *rctlname, void *arg)
5406 {
5407 	const char *attrname = arg;
5408 
5409 	/*
5410 	 * Returning 1 here is our signal to zonecfg_is_rctl() that it is
5411 	 * indeed an rctl name recognized by the system.
5412 	 */
5413 	return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
5414 }
5415 
5416 boolean_t
5417 zonecfg_is_rctl(const char *name)
5418 {
5419 	return (rctl_walk(rctl_check, (void *)name) == 1);
5420 }
5421 
5422 boolean_t
5423 zonecfg_valid_rctlname(const char *name)
5424 {
5425 	const char *c;
5426 
5427 	if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
5428 		return (B_FALSE);
5429 	if (strlen(name) == sizeof ("zone.") - 1)
5430 		return (B_FALSE);
5431 	for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
5432 		if (!isalpha(*c) && *c != '-')
5433 			return (B_FALSE);
5434 	}
5435 	return (B_TRUE);
5436 }
5437 
5438 boolean_t
5439 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
5440 {
5441 	rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
5442 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
5443 
5444 	if (priv != RCPRIV_PRIVILEGED)
5445 		return (B_FALSE);
5446 	if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
5447 		return (B_FALSE);
5448 	return (B_TRUE);
5449 }
5450 
5451 boolean_t
5452 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
5453 {
5454 	rctlblk_t *current, *next;
5455 	rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
5456 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
5457 	uint_t global_flags;
5458 
5459 	if (!zonecfg_valid_rctlblk(rctlblk))
5460 		return (B_FALSE);
5461 	if (!zonecfg_valid_rctlname(name))
5462 		return (B_FALSE);
5463 
5464 	current = alloca(rctlblk_size());
5465 	if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
5466 		return (B_TRUE);	/* not an rctl on this system */
5467 	/*
5468 	 * Make sure the proposed value isn't greater than the current system
5469 	 * value.
5470 	 */
5471 	next = alloca(rctlblk_size());
5472 	while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
5473 		rctlblk_t *tmp;
5474 
5475 		if (getrctl(name, current, next, RCTL_NEXT) != 0)
5476 			return (B_FALSE);	/* shouldn't happen */
5477 		tmp = current;
5478 		current = next;
5479 		next = tmp;
5480 	}
5481 	if (limit > rctlblk_get_value(current))
5482 		return (B_FALSE);
5483 
5484 	/*
5485 	 * Make sure the proposed action is allowed.
5486 	 */
5487 	global_flags = rctlblk_get_global_flags(current);
5488 	if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
5489 	    action == RCTL_LOCAL_DENY)
5490 		return (B_FALSE);
5491 	if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
5492 	    action == RCTL_LOCAL_NOACTION)
5493 		return (B_FALSE);
5494 
5495 	return (B_TRUE);
5496 }
5497 
5498 /*
5499  * There is always a race condition between reading the initial copy of
5500  * a zones state and its state changing.  We address this by providing
5501  * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
5502  * When zonecfg_critical_enter is called, sets the state field to LOCKED
5503  * and aquires biglock. Biglock protects against other threads executing
5504  * critical_enter and the state field protects against state changes during
5505  * the critical period.
5506  *
5507  * If any state changes occur, zn_cb will set the failed field of the znotify
5508  * structure.  This will cause the critical_exit function to re-lock the
5509  * channel and return an error. Since evsnts may be delayed, the critical_exit
5510  * function "flushes" the queue by putting an event on the queue and waiting for
5511  * zn_cb to notify critical_exit that it received the ping event.
5512  */
5513 static const char *
5514 string_get_tok(const char *in, char delim, int num)
5515 {
5516 	int i = 0;
5517 
5518 	for (; i < num; in++) {
5519 		if (*in == delim)
5520 			i++;
5521 		if (*in == 0)
5522 			return (NULL);
5523 	}
5524 	return (in);
5525 }
5526 
5527 static boolean_t
5528 is_ping(sysevent_t *ev)
5529 {
5530 	if (strcmp(sysevent_get_subclass_name(ev),
5531 	    ZONE_EVENT_PING_SUBCLASS) == 0) {
5532 		return (B_TRUE);
5533 	} else {
5534 		return (B_FALSE);
5535 	}
5536 }
5537 
5538 static boolean_t
5539 is_my_ping(sysevent_t *ev)
5540 {
5541 	const char *sender;
5542 	char mypid[sizeof (pid_t) * 3 + 1];
5543 
5544 	(void) snprintf(mypid, sizeof (mypid), "%i", getpid());
5545 	sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
5546 	if (sender == NULL)
5547 		return (B_FALSE);
5548 	if (strcmp(sender, mypid) != 0)
5549 		return (B_FALSE);
5550 	return (B_TRUE);
5551 }
5552 
5553 static int
5554 do_callback(struct znotify *zevtchan, sysevent_t *ev)
5555 {
5556 	nvlist_t *l;
5557 	int zid;
5558 	char *zonename;
5559 	char *newstate;
5560 	char *oldstate;
5561 	int ret;
5562 	hrtime_t when;
5563 
5564 	if (strcmp(sysevent_get_subclass_name(ev),
5565 	    ZONE_EVENT_STATUS_SUBCLASS) == 0) {
5566 
5567 		if (sysevent_get_attr_list(ev, &l) != 0) {
5568 			if (errno == ENOMEM) {
5569 				zevtchan->zn_failure_count++;
5570 				return (EAGAIN);
5571 			}
5572 			return (0);
5573 		}
5574 		ret = 0;
5575 
5576 		if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
5577 		    (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
5578 		    == 0) &&
5579 		    (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
5580 		    == 0) &&
5581 		    (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
5582 		    (uint64_t *)&when) == 0) &&
5583 		    (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
5584 			ret = zevtchan->zn_callback(zonename, zid, newstate,
5585 			    oldstate, when, zevtchan->zn_private);
5586 		}
5587 
5588 		zevtchan->zn_failure_count = 0;
5589 		nvlist_free(l);
5590 		return (ret);
5591 	} else {
5592 		/*
5593 		 * We have received an event in an unknown subclass. Ignore.
5594 		 */
5595 		zevtchan->zn_failure_count = 0;
5596 		return (0);
5597 	}
5598 }
5599 
5600 static int
5601 zn_cb(sysevent_t *ev, void *p)
5602 {
5603 	struct znotify *zevtchan = p;
5604 	int error;
5605 
5606 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
5607 
5608 	if (is_ping(ev) && !is_my_ping(ev)) {
5609 		(void) pthread_mutex_unlock((&zevtchan->zn_mutex));
5610 		return (0);
5611 	}
5612 
5613 	if (zevtchan->zn_state == ZN_LOCKED) {
5614 		assert(!is_ping(ev));
5615 		zevtchan->zn_failed = B_TRUE;
5616 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5617 		return (0);
5618 	}
5619 
5620 	if (zevtchan->zn_state == ZN_PING_INFLIGHT) {
5621 		if (is_ping(ev)) {
5622 			zevtchan->zn_state = ZN_PING_RECEIVED;
5623 			(void) pthread_cond_signal(&(zevtchan->zn_cond));
5624 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5625 			return (0);
5626 		} else {
5627 			zevtchan->zn_failed = B_TRUE;
5628 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5629 			return (0);
5630 		}
5631 	}
5632 
5633 	if (zevtchan->zn_state == ZN_UNLOCKED) {
5634 
5635 		error = do_callback(zevtchan, ev);
5636 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5637 		/*
5638 		 * Every ENOMEM failure causes do_callback to increment
5639 		 * zn_failure_count and every success causes it to
5640 		 * set zn_failure_count to zero.  If we got EAGAIN,
5641 		 * we will sleep for zn_failure_count seconds and return
5642 		 * EAGAIN to gpec to try again.
5643 		 *
5644 		 * After 55 seconds, or 10 try's we give up and drop the
5645 		 * event.
5646 		 */
5647 		if (error == EAGAIN) {
5648 			if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) {
5649 				return (0);
5650 			}
5651 			(void) sleep(zevtchan->zn_failure_count);
5652 		}
5653 		return (error);
5654 	}
5655 
5656 	if (zevtchan->zn_state == ZN_PING_RECEIVED) {
5657 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5658 		return (0);
5659 	}
5660 
5661 	abort();
5662 	return (0);
5663 }
5664 
5665 void
5666 zonecfg_notify_critical_enter(void *h)
5667 {
5668 	struct znotify *zevtchan = h;
5669 
5670 	(void) pthread_mutex_lock(&(zevtchan->zn_bigmutex));
5671 	zevtchan->zn_state = ZN_LOCKED;
5672 }
5673 
5674 int
5675 zonecfg_notify_critical_exit(void * h)
5676 {
5677 
5678 	struct znotify *zevtchan = h;
5679 
5680 	if (zevtchan->zn_state == ZN_UNLOCKED)
5681 		return (0);
5682 
5683 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
5684 	zevtchan->zn_state = ZN_PING_INFLIGHT;
5685 
5686 	(void) sysevent_evc_publish(zevtchan->zn_eventchan,
5687 	    ZONE_EVENT_STATUS_CLASS,
5688 	    ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER,
5689 	    zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP);
5690 
5691 	while (zevtchan->zn_state != ZN_PING_RECEIVED) {
5692 		(void) pthread_cond_wait(&(zevtchan->zn_cond),
5693 		    &(zevtchan->zn_mutex));
5694 	}
5695 
5696 	if (zevtchan->zn_failed == B_TRUE) {
5697 		zevtchan->zn_state = ZN_LOCKED;
5698 		zevtchan->zn_failed = B_FALSE;
5699 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5700 		return (1);
5701 	}
5702 
5703 	zevtchan->zn_state = ZN_UNLOCKED;
5704 	(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
5705 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
5706 	return (0);
5707 }
5708 
5709 void
5710 zonecfg_notify_critical_abort(void *h)
5711 {
5712 	struct znotify *zevtchan = h;
5713 
5714 	zevtchan->zn_state = ZN_UNLOCKED;
5715 	zevtchan->zn_failed = B_FALSE;
5716 	/*
5717 	 * Don't do anything about zn_lock. If it is held, it could only be
5718 	 * held by zn_cb and it will be unlocked soon.
5719 	 */
5720 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
5721 }
5722 
5723 void *
5724 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
5725     const char *newstate, const char *oldstate, hrtime_t when, void *p),
5726     void *p)
5727 {
5728 	struct znotify *zevtchan;
5729 	int i = 1;
5730 	int r;
5731 
5732 	zevtchan = malloc(sizeof (struct znotify));
5733 
5734 	if (zevtchan == NULL)
5735 		return (NULL);
5736 
5737 	zevtchan->zn_private = p;
5738 	zevtchan->zn_callback = func;
5739 	zevtchan->zn_state = ZN_UNLOCKED;
5740 	zevtchan->zn_failed = B_FALSE;
5741 
5742 	if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL))
5743 		goto out3;
5744 	if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) {
5745 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
5746 		goto out3;
5747 	}
5748 	if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) {
5749 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
5750 		(void) pthread_cond_destroy(&(zevtchan->zn_cond));
5751 		goto out3;
5752 	}
5753 
5754 	if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan),
5755 	    0) != 0)
5756 		goto out2;
5757 
5758 	do {
5759 		/*
5760 		 * At 4 digits the subscriber ID gets too long and we have
5761 		 * no chance of successfully registering.
5762 		 */
5763 		if (i > 999)
5764 			goto out1;
5765 
5766 		(void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i",
5767 		    getpid() % 999999l, i);
5768 
5769 		r = sysevent_evc_subscribe(zevtchan->zn_eventchan,
5770 		    zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb,
5771 		    zevtchan, 0);
5772 
5773 		i++;
5774 
5775 	} while (r);
5776 
5777 	return (zevtchan);
5778 out1:
5779 	sysevent_evc_unbind(zevtchan->zn_eventchan);
5780 out2:
5781 	(void) pthread_mutex_destroy(&zevtchan->zn_mutex);
5782 	(void) pthread_cond_destroy(&zevtchan->zn_cond);
5783 	(void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex));
5784 out3:
5785 	free(zevtchan);
5786 
5787 	return (NULL);
5788 }
5789 
5790 void
5791 zonecfg_notify_unbind(void *handle)
5792 {
5793 
5794 	int ret;
5795 
5796 	sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan);
5797 	/*
5798 	 * Check that all evc threads have gone away. This should be
5799 	 * enforced by sysevent_evc_unbind.
5800 	 */
5801 	ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex);
5802 
5803 	if (ret)
5804 		abort();
5805 
5806 	(void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex);
5807 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex);
5808 	(void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond);
5809 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex);
5810 
5811 	free(handle);
5812 }
5813 
5814 static int
5815 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
5816 {
5817 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
5818 	int err;
5819 
5820 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL);
5821 	if ((err = newprop(newnode, DTD_ATTR_NAME,
5822 	    tabptr->zone_dataset_name)) != Z_OK)
5823 		return (err);
5824 	return (Z_OK);
5825 }
5826 
5827 int
5828 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5829 {
5830 	int err;
5831 
5832 	if (tabptr == NULL)
5833 		return (Z_INVAL);
5834 
5835 	if ((err = operation_prep(handle)) != Z_OK)
5836 		return (err);
5837 
5838 	if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK)
5839 		return (err);
5840 
5841 	return (Z_OK);
5842 }
5843 
5844 static int
5845 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
5846 {
5847 	xmlNodePtr cur = handle->zone_dh_cur;
5848 
5849 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
5850 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5851 			continue;
5852 
5853 		if (match_prop(cur, DTD_ATTR_NAME,
5854 		    tabptr->zone_dataset_name)) {
5855 			xmlUnlinkNode(cur);
5856 			xmlFreeNode(cur);
5857 			return (Z_OK);
5858 		}
5859 	}
5860 	return (Z_NO_RESOURCE_ID);
5861 }
5862 
5863 int
5864 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5865 {
5866 	int err;
5867 
5868 	if (tabptr == NULL)
5869 		return (Z_INVAL);
5870 
5871 	if ((err = operation_prep(handle)) != Z_OK)
5872 		return (err);
5873 
5874 	if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK)
5875 		return (err);
5876 
5877 	return (Z_OK);
5878 }
5879 
5880 int
5881 zonecfg_modify_ds(
5882 	zone_dochandle_t handle,
5883 	struct zone_dstab *oldtabptr,
5884 	struct zone_dstab *newtabptr)
5885 {
5886 	int err;
5887 
5888 	if (oldtabptr == NULL || newtabptr == NULL)
5889 		return (Z_INVAL);
5890 
5891 	if ((err = operation_prep(handle)) != Z_OK)
5892 		return (err);
5893 
5894 	if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK)
5895 		return (err);
5896 
5897 	if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK)
5898 		return (err);
5899 
5900 	return (Z_OK);
5901 }
5902 
5903 int
5904 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
5905 {
5906 	xmlNodePtr cur, firstmatch;
5907 	int err;
5908 	char dataset[MAXNAMELEN];
5909 
5910 	if (tabptr == NULL)
5911 		return (Z_INVAL);
5912 
5913 	if ((err = operation_prep(handle)) != Z_OK)
5914 		return (err);
5915 
5916 	cur = handle->zone_dh_cur;
5917 	firstmatch = NULL;
5918 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
5919 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5920 			continue;
5921 		if (strlen(tabptr->zone_dataset_name) > 0) {
5922 			if ((fetchprop(cur, DTD_ATTR_NAME, dataset,
5923 			    sizeof (dataset)) == Z_OK) &&
5924 			    (strcmp(tabptr->zone_dataset_name,
5925 			    dataset) == 0)) {
5926 				if (firstmatch == NULL)
5927 					firstmatch = cur;
5928 				else
5929 					return (Z_INSUFFICIENT_SPEC);
5930 			}
5931 		}
5932 	}
5933 	if (firstmatch == NULL)
5934 		return (Z_NO_RESOURCE_ID);
5935 
5936 	cur = firstmatch;
5937 
5938 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
5939 	    sizeof (tabptr->zone_dataset_name))) != Z_OK)
5940 		return (err);
5941 
5942 	return (Z_OK);
5943 }
5944 
5945 int
5946 zonecfg_setdsent(zone_dochandle_t handle)
5947 {
5948 	return (zonecfg_setent(handle));
5949 }
5950 
5951 int
5952 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
5953 {
5954 	xmlNodePtr cur;
5955 	int err;
5956 
5957 	if (handle == NULL)
5958 		return (Z_INVAL);
5959 
5960 	if ((cur = handle->zone_dh_cur) == NULL)
5961 		return (Z_NO_ENTRY);
5962 
5963 	for (; cur != NULL; cur = cur->next)
5964 		if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET))
5965 			break;
5966 	if (cur == NULL) {
5967 		handle->zone_dh_cur = handle->zone_dh_top;
5968 		return (Z_NO_ENTRY);
5969 	}
5970 
5971 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
5972 	    sizeof (tabptr->zone_dataset_name))) != Z_OK) {
5973 		handle->zone_dh_cur = handle->zone_dh_top;
5974 		return (err);
5975 	}
5976 
5977 	handle->zone_dh_cur = cur->next;
5978 	return (Z_OK);
5979 }
5980 
5981 int
5982 zonecfg_enddsent(zone_dochandle_t handle)
5983 {
5984 	return (zonecfg_endent(handle));
5985 }
5986 
5987 /*
5988  * Support for aliased rctls; that is, rctls that have simplified names in
5989  * zonecfg.  For example, max-lwps is an alias for a well defined zone.max-lwps
5990  * rctl.  If there are multiple existing values for one of these rctls or if
5991  * there is a single value that does not match the well defined template (i.e.
5992  * it has a different action) then we cannot treat the rctl as having an alias
5993  * so we return Z_ALIAS_DISALLOW.  That means that the rctl cannot be
5994  * managed in zonecfg via an alias and that the standard rctl syntax must be
5995  * used.
5996  *
5997  * The possible return values are:
5998  *	Z_NO_PROPERTY_ID - invalid alias name
5999  *	Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition
6000  *	Z_NO_ENTRY - no rctl is configured for this alias
6001  *	Z_OK - we got a valid rctl for the specified alias
6002  */
6003 int
6004 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval)
6005 {
6006 	boolean_t found = B_FALSE;
6007 	boolean_t found_val = B_FALSE;
6008 	xmlNodePtr cur, val;
6009 	char savedname[MAXNAMELEN];
6010 	struct zone_rctlvaltab rctl;
6011 	int i;
6012 	int err;
6013 
6014 	for (i = 0; aliases[i].shortname != NULL; i++)
6015 		if (strcmp(name, aliases[i].shortname) == 0)
6016 			break;
6017 
6018 	if (aliases[i].shortname == NULL)
6019 		return (Z_NO_PROPERTY_ID);
6020 
6021 	if ((err = operation_prep(handle)) != Z_OK)
6022 		return (err);
6023 
6024 	cur = handle->zone_dh_cur;
6025 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6026 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0)
6027 			continue;
6028 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
6029 		    sizeof (savedname)) == Z_OK) &&
6030 		    (strcmp(savedname, aliases[i].realname) == 0)) {
6031 
6032 			/*
6033 			 * If we already saw one of these, we can't have an
6034 			 * alias since we just found another.
6035 			 */
6036 			if (found)
6037 				return (Z_ALIAS_DISALLOW);
6038 			found = B_TRUE;
6039 
6040 			for (val = cur->xmlChildrenNode; val != NULL;
6041 			    val = val->next) {
6042 				/*
6043 				 * If we already have one value, we can't have
6044 				 * an alias since we just found another.
6045 				 */
6046 				if (found_val)
6047 					return (Z_ALIAS_DISALLOW);
6048 				found_val = B_TRUE;
6049 
6050 				if ((fetchprop(val, DTD_ATTR_PRIV,
6051 				    rctl.zone_rctlval_priv,
6052 				    sizeof (rctl.zone_rctlval_priv)) != Z_OK))
6053 					break;
6054 				if ((fetchprop(val, DTD_ATTR_LIMIT,
6055 				    rctl.zone_rctlval_limit,
6056 				    sizeof (rctl.zone_rctlval_limit)) != Z_OK))
6057 					break;
6058 				if ((fetchprop(val, DTD_ATTR_ACTION,
6059 				    rctl.zone_rctlval_action,
6060 				    sizeof (rctl.zone_rctlval_action)) != Z_OK))
6061 					break;
6062 			}
6063 
6064 			/* check priv and action match the expected vals */
6065 			if (strcmp(rctl.zone_rctlval_priv,
6066 			    aliases[i].priv) != 0 ||
6067 			    strcmp(rctl.zone_rctlval_action,
6068 			    aliases[i].action) != 0)
6069 				return (Z_ALIAS_DISALLOW);
6070 		}
6071 	}
6072 
6073 	if (found) {
6074 		*rval = strtoull(rctl.zone_rctlval_limit, NULL, 10);
6075 		return (Z_OK);
6076 	}
6077 
6078 	return (Z_NO_ENTRY);
6079 }
6080 
6081 int
6082 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name)
6083 {
6084 	int i;
6085 	uint64_t val;
6086 	struct zone_rctltab rctltab;
6087 
6088 	/*
6089 	 * First check that we have a valid aliased rctl to remove.
6090 	 * This will catch an rctl entry with non-standard values or
6091 	 * multiple rctl values for this name.  We need to ignore those
6092 	 * rctl entries.
6093 	 */
6094 	if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK)
6095 		return (Z_OK);
6096 
6097 	for (i = 0; aliases[i].shortname != NULL; i++)
6098 		if (strcmp(name, aliases[i].shortname) == 0)
6099 			break;
6100 
6101 	if (aliases[i].shortname == NULL)
6102 		return (Z_NO_RESOURCE_ID);
6103 
6104 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6105 	    sizeof (rctltab.zone_rctl_name));
6106 
6107 	return (zonecfg_delete_rctl(handle, &rctltab));
6108 }
6109 
6110 boolean_t
6111 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name)
6112 {
6113 	uint64_t tmp_val;
6114 
6115 	switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) {
6116 	case Z_OK:
6117 		/*FALLTHRU*/
6118 	case Z_NO_ENTRY:
6119 		return (B_TRUE);
6120 	default:
6121 		return (B_FALSE);
6122 	}
6123 }
6124 
6125 int
6126 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val)
6127 {
6128 	int i;
6129 	int err;
6130 	struct zone_rctltab rctltab;
6131 	struct zone_rctlvaltab *rctlvaltab;
6132 	char buf[128];
6133 
6134 	if (!zonecfg_aliased_rctl_ok(handle, name))
6135 		return (Z_ALIAS_DISALLOW);
6136 
6137 	for (i = 0; aliases[i].shortname != NULL; i++)
6138 		if (strcmp(name, aliases[i].shortname) == 0)
6139 			break;
6140 
6141 	if (aliases[i].shortname == NULL)
6142 		return (Z_NO_RESOURCE_ID);
6143 
6144 	/* remove any pre-existing definition for this rctl */
6145 	(void) zonecfg_rm_aliased_rctl(handle, name);
6146 
6147 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6148 	    sizeof (rctltab.zone_rctl_name));
6149 
6150 	rctltab.zone_rctl_valptr = NULL;
6151 
6152 	if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL)
6153 		return (Z_NOMEM);
6154 
6155 	(void) snprintf(buf, sizeof (buf), "%llu", (long long)val);
6156 
6157 	(void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv,
6158 	    sizeof (rctlvaltab->zone_rctlval_priv));
6159 	(void) strlcpy(rctlvaltab->zone_rctlval_limit, buf,
6160 	    sizeof (rctlvaltab->zone_rctlval_limit));
6161 	(void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action,
6162 	    sizeof (rctlvaltab->zone_rctlval_action));
6163 
6164 	rctlvaltab->zone_rctlval_next = NULL;
6165 
6166 	if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK)
6167 		return (err);
6168 
6169 	return (zonecfg_add_rctl(handle, &rctltab));
6170 }
6171 
6172 static int
6173 delete_tmp_pool(zone_dochandle_t handle)
6174 {
6175 	int err;
6176 	xmlNodePtr cur = handle->zone_dh_cur;
6177 
6178 	if ((err = operation_prep(handle)) != Z_OK)
6179 		return (err);
6180 
6181 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6182 		if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6183 			xmlUnlinkNode(cur);
6184 			xmlFreeNode(cur);
6185 			return (Z_OK);
6186 		}
6187 	}
6188 
6189 	return (Z_NO_RESOURCE_ID);
6190 }
6191 
6192 static int
6193 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance)
6194 {
6195 	int err;
6196 	xmlNodePtr cur = handle->zone_dh_cur;
6197 	xmlNodePtr newnode;
6198 
6199 	err = delete_tmp_pool(handle);
6200 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6201 		return (err);
6202 
6203 	if (*pool_importance != '\0') {
6204 		if ((err = operation_prep(handle)) != Z_OK)
6205 			return (err);
6206 
6207 		newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL);
6208 		if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE,
6209 		    pool_importance)) != Z_OK)
6210 			return (err);
6211 	}
6212 
6213 	return (Z_OK);
6214 }
6215 
6216 static int
6217 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr)
6218 {
6219 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6220 	int err;
6221 
6222 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL);
6223 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN,
6224 	    tabptr->zone_ncpu_min)) != Z_OK)
6225 		return (err);
6226 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX,
6227 	    tabptr->zone_ncpu_max)) != Z_OK)
6228 		return (err);
6229 
6230 	if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK)
6231 		return (err);
6232 
6233 	return (Z_OK);
6234 }
6235 
6236 int
6237 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6238 {
6239 	int err;
6240 
6241 	if (tabptr == NULL)
6242 		return (Z_INVAL);
6243 
6244 	if ((err = operation_prep(handle)) != Z_OK)
6245 		return (err);
6246 
6247 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
6248 		return (err);
6249 
6250 	return (Z_OK);
6251 }
6252 
6253 int
6254 zonecfg_delete_pset(zone_dochandle_t handle)
6255 {
6256 	int err;
6257 	int res = Z_NO_RESOURCE_ID;
6258 	xmlNodePtr cur = handle->zone_dh_cur;
6259 
6260 	if ((err = operation_prep(handle)) != Z_OK)
6261 		return (err);
6262 
6263 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6264 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
6265 			xmlUnlinkNode(cur);
6266 			xmlFreeNode(cur);
6267 			res = Z_OK;
6268 			break;
6269 		}
6270 	}
6271 
6272 	/*
6273 	 * Once we have msets, we should check that a mset
6274 	 * do not exist before we delete the tmp_pool data.
6275 	 */
6276 	err = delete_tmp_pool(handle);
6277 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6278 		return (err);
6279 
6280 	return (res);
6281 }
6282 
6283 int
6284 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6285 {
6286 	int err;
6287 
6288 	if (tabptr == NULL)
6289 		return (Z_INVAL);
6290 
6291 	if ((err = zonecfg_delete_pset(handle)) != Z_OK)
6292 		return (err);
6293 
6294 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
6295 		return (err);
6296 
6297 	return (Z_OK);
6298 }
6299 
6300 int
6301 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6302 {
6303 	xmlNodePtr cur;
6304 	int err;
6305 	int res = Z_NO_ENTRY;
6306 
6307 	if (tabptr == NULL)
6308 		return (Z_INVAL);
6309 
6310 	if ((err = operation_prep(handle)) != Z_OK)
6311 		return (err);
6312 
6313 	/* this is an optional component */
6314 	tabptr->zone_importance[0] = '\0';
6315 
6316 	cur = handle->zone_dh_cur;
6317 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6318 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
6319 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN,
6320 			    tabptr->zone_ncpu_min,
6321 			    sizeof (tabptr->zone_ncpu_min))) != Z_OK) {
6322 				handle->zone_dh_cur = handle->zone_dh_top;
6323 				return (err);
6324 			}
6325 
6326 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX,
6327 			    tabptr->zone_ncpu_max,
6328 			    sizeof (tabptr->zone_ncpu_max))) != Z_OK) {
6329 				handle->zone_dh_cur = handle->zone_dh_top;
6330 				return (err);
6331 			}
6332 
6333 			res = Z_OK;
6334 
6335 		} else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6336 			if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE,
6337 			    tabptr->zone_importance,
6338 			    sizeof (tabptr->zone_importance))) != Z_OK) {
6339 				handle->zone_dh_cur = handle->zone_dh_top;
6340 				return (err);
6341 			}
6342 		}
6343 	}
6344 
6345 	return (res);
6346 }
6347 
6348 int
6349 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
6350 {
6351 	int err;
6352 
6353 	if ((err = zonecfg_setent(handle)) != Z_OK)
6354 		return (err);
6355 
6356 	err = zonecfg_lookup_pset(handle, tabptr);
6357 
6358 	(void) zonecfg_endent(handle);
6359 
6360 	return (err);
6361 }
6362 
6363 static int
6364 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6365 {
6366 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6367 	int err;
6368 
6369 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
6370 	if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
6371 	    != Z_OK)
6372 		return (err);
6373 
6374 	return (Z_OK);
6375 }
6376 
6377 int
6378 zonecfg_delete_mcap(zone_dochandle_t handle)
6379 {
6380 	int err;
6381 	xmlNodePtr cur = handle->zone_dh_cur;
6382 
6383 	if ((err = operation_prep(handle)) != Z_OK)
6384 		return (err);
6385 
6386 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6387 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6388 			continue;
6389 
6390 		xmlUnlinkNode(cur);
6391 		xmlFreeNode(cur);
6392 		return (Z_OK);
6393 	}
6394 	return (Z_NO_RESOURCE_ID);
6395 }
6396 
6397 int
6398 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6399 {
6400 	int err;
6401 
6402 	if (tabptr == NULL)
6403 		return (Z_INVAL);
6404 
6405 	err = zonecfg_delete_mcap(handle);
6406 	/* it is ok if there is no mcap entry */
6407 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6408 		return (err);
6409 
6410 	if ((err = add_mcap(handle, tabptr)) != Z_OK)
6411 		return (err);
6412 
6413 	return (Z_OK);
6414 }
6415 
6416 int
6417 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6418 {
6419 	xmlNodePtr cur;
6420 	int err;
6421 
6422 	if (tabptr == NULL)
6423 		return (Z_INVAL);
6424 
6425 	if ((err = operation_prep(handle)) != Z_OK)
6426 		return (err);
6427 
6428 	cur = handle->zone_dh_cur;
6429 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6430 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6431 			continue;
6432 		if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
6433 		    tabptr->zone_physmem_cap,
6434 		    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6435 			handle->zone_dh_cur = handle->zone_dh_top;
6436 			return (err);
6437 		}
6438 
6439 		return (Z_OK);
6440 	}
6441 
6442 	return (Z_NO_ENTRY);
6443 }
6444 
6445 static int
6446 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6447 {
6448 	xmlNodePtr cur;
6449 	int err;
6450 
6451 	if (handle == NULL)
6452 		return (Z_INVAL);
6453 
6454 	if ((cur = handle->zone_dh_cur) == NULL)
6455 		return (Z_NO_ENTRY);
6456 
6457 	for (; cur != NULL; cur = cur->next)
6458 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
6459 			break;
6460 	if (cur == NULL) {
6461 		handle->zone_dh_cur = handle->zone_dh_top;
6462 		return (Z_NO_ENTRY);
6463 	}
6464 
6465 	if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
6466 	    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6467 		handle->zone_dh_cur = handle->zone_dh_top;
6468 		return (err);
6469 	}
6470 
6471 	handle->zone_dh_cur = cur->next;
6472 	return (Z_OK);
6473 }
6474 
6475 int
6476 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6477 {
6478 	int err;
6479 
6480 	if ((err = zonecfg_setent(handle)) != Z_OK)
6481 		return (err);
6482 
6483 	err = getmcapent_core(handle, tabptr);
6484 
6485 	(void) zonecfg_endent(handle);
6486 
6487 	return (err);
6488 }
6489 
6490 int
6491 zonecfg_setpkgent(zone_dochandle_t handle)
6492 {
6493 	return (zonecfg_setent(handle));
6494 }
6495 
6496 int
6497 zonecfg_getpkgent(zone_dochandle_t handle, struct zone_pkgtab *tabptr)
6498 {
6499 	xmlNodePtr cur;
6500 	int err;
6501 
6502 	if (handle == NULL)
6503 		return (Z_INVAL);
6504 
6505 	if ((cur = handle->zone_dh_cur) == NULL)
6506 		return (Z_NO_ENTRY);
6507 
6508 	for (; cur != NULL; cur = cur->next)
6509 		if (!xmlStrcmp(cur->name, DTD_ELEM_PACKAGE))
6510 			break;
6511 	if (cur == NULL) {
6512 		handle->zone_dh_cur = handle->zone_dh_top;
6513 		return (Z_NO_ENTRY);
6514 	}
6515 
6516 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_pkg_name,
6517 	    sizeof (tabptr->zone_pkg_name))) != Z_OK) {
6518 		handle->zone_dh_cur = handle->zone_dh_top;
6519 		return (err);
6520 	}
6521 
6522 	if ((err = fetchprop(cur, DTD_ATTR_VERSION, tabptr->zone_pkg_version,
6523 	    sizeof (tabptr->zone_pkg_version))) != Z_OK) {
6524 		handle->zone_dh_cur = handle->zone_dh_top;
6525 		return (err);
6526 	}
6527 
6528 	handle->zone_dh_cur = cur->next;
6529 	return (Z_OK);
6530 }
6531 
6532 int
6533 zonecfg_endpkgent(zone_dochandle_t handle)
6534 {
6535 	return (zonecfg_endent(handle));
6536 }
6537 
6538 int
6539 zonecfg_setpatchent(zone_dochandle_t handle)
6540 {
6541 	return (zonecfg_setent(handle));
6542 }
6543 
6544 int
6545 zonecfg_getpatchent(zone_dochandle_t handle, struct zone_patchtab *tabptr)
6546 {
6547 	xmlNodePtr cur;
6548 	int err;
6549 
6550 	if (handle == NULL)
6551 		return (Z_INVAL);
6552 
6553 	if ((cur = handle->zone_dh_cur) == NULL)
6554 		return (Z_NO_ENTRY);
6555 
6556 	for (; cur != NULL; cur = cur->next)
6557 		if (!xmlStrcmp(cur->name, DTD_ELEM_PATCH))
6558 			break;
6559 	if (cur == NULL) {
6560 		handle->zone_dh_cur = handle->zone_dh_top;
6561 		return (Z_NO_ENTRY);
6562 	}
6563 
6564 	if ((err = fetchprop(cur, DTD_ATTR_ID, tabptr->zone_patch_id,
6565 	    sizeof (tabptr->zone_patch_id))) != Z_OK) {
6566 		handle->zone_dh_cur = handle->zone_dh_top;
6567 		return (err);
6568 	}
6569 
6570 	handle->zone_dh_cur = cur->next;
6571 	return (Z_OK);
6572 }
6573 
6574 int
6575 zonecfg_endpatchent(zone_dochandle_t handle)
6576 {
6577 	return (zonecfg_endent(handle));
6578 }
6579 
6580 int
6581 zonecfg_setdevperment(zone_dochandle_t handle)
6582 {
6583 	return (zonecfg_setent(handle));
6584 }
6585 
6586 int
6587 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr)
6588 {
6589 	xmlNodePtr cur;
6590 	int err;
6591 	char buf[128];
6592 
6593 	tabptr->zone_devperm_acl = NULL;
6594 
6595 	if (handle == NULL)
6596 		return (Z_INVAL);
6597 
6598 	if ((cur = handle->zone_dh_cur) == NULL)
6599 		return (Z_NO_ENTRY);
6600 
6601 	for (; cur != NULL; cur = cur->next)
6602 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM))
6603 			break;
6604 	if (cur == NULL) {
6605 		handle->zone_dh_cur = handle->zone_dh_top;
6606 		return (Z_NO_ENTRY);
6607 	}
6608 
6609 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name,
6610 	    sizeof (tabptr->zone_devperm_name))) != Z_OK) {
6611 		handle->zone_dh_cur = handle->zone_dh_top;
6612 		return (err);
6613 	}
6614 
6615 	if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) {
6616 		handle->zone_dh_cur = handle->zone_dh_top;
6617 		return (err);
6618 	}
6619 	tabptr->zone_devperm_uid = (uid_t)atol(buf);
6620 
6621 	if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) {
6622 		handle->zone_dh_cur = handle->zone_dh_top;
6623 		return (err);
6624 	}
6625 	tabptr->zone_devperm_gid = (gid_t)atol(buf);
6626 
6627 	if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) {
6628 		handle->zone_dh_cur = handle->zone_dh_top;
6629 		return (err);
6630 	}
6631 	tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8);
6632 
6633 	if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL,
6634 	    &(tabptr->zone_devperm_acl))) != Z_OK) {
6635 		handle->zone_dh_cur = handle->zone_dh_top;
6636 		return (err);
6637 	}
6638 
6639 	handle->zone_dh_cur = cur->next;
6640 	return (Z_OK);
6641 }
6642 
6643 int
6644 zonecfg_enddevperment(zone_dochandle_t handle)
6645 {
6646 	return (zonecfg_endent(handle));
6647 }
6648 
6649 /*
6650  * Process a list of pkgs from an entry in the contents file, adding each pkg
6651  * name to the list of pkgs.
6652  *
6653  * It is possible for the pkg name to be preceeded by a special character
6654  * which indicates some bookkeeping information for pkging.  Check if the
6655  * first char is not an Alpha char.  If so, skip over it.
6656  */
6657 static int
6658 add_pkg_list(char *lastp, char ***plist, int *pcnt)
6659 {
6660 	char	*p;
6661 	int	pkg_cnt = *pcnt;
6662 	char	**pkgs = *plist;
6663 	int	res = Z_OK;
6664 
6665 	while ((p = strtok_r(NULL, " ", &lastp)) != NULL) {
6666 		char	**tmpp;
6667 		int	i;
6668 
6669 		/* skip over any special pkg bookkeeping char */
6670 		if (!isalpha(*p))
6671 			p++;
6672 
6673 		/* Check if the pkg is already in the list */
6674 		for (i = 0; i < pkg_cnt; i++) {
6675 			if (strcmp(p, pkgs[i]) == 0)
6676 				break;
6677 		}
6678 
6679 		if (i < pkg_cnt)
6680 			continue;
6681 
6682 		/* The pkg is not in the list; add it. */
6683 		if ((tmpp = (char **)realloc(pkgs,
6684 		    sizeof (char *) * (pkg_cnt + 1))) == NULL) {
6685 			res = Z_NOMEM;
6686 			break;
6687 		}
6688 		pkgs = tmpp;
6689 
6690 		if ((pkgs[pkg_cnt] = strdup(p)) == NULL) {
6691 			res = Z_NOMEM;
6692 			break;
6693 		}
6694 		pkg_cnt++;
6695 	}
6696 
6697 	*plist = pkgs;
6698 	*pcnt = pkg_cnt;
6699 
6700 	return (res);
6701 }
6702 
6703 /*
6704  * Process an entry from the contents file (type "directory") and if the
6705  * directory path is in the list of paths, add the associated list of pkgs
6706  * to the pkg list.  The input parameter "entry" will be broken up by
6707  * the parser within this function so its value will be modified when this
6708  * function exits.
6709  *
6710  * The entries we are looking for will look something like:
6711  *	/usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf ....
6712  */
6713 static int
6714 get_path_pkgs(char *entry, char **paths, int cnt, char ***pkgs, int *pkg_cnt)
6715 {
6716 	char	*f1;
6717 	char	*f2;
6718 	char	*lastp;
6719 	int	i;
6720 	int	res = Z_OK;
6721 
6722 	if ((f1 = strtok_r(entry, " ", &lastp)) == NULL ||
6723 	    (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0)
6724 		return (Z_OK);
6725 
6726 	/* Check if this directory entry is in the list of paths. */
6727 	for (i = 0; i < cnt; i++) {
6728 		if (fnmatch(paths[i], f1, FNM_PATHNAME) == 0) {
6729 			/*
6730 			 * We do want the pkgs for this path.  First, skip
6731 			 * over the next 4 fields in the entry so that we call
6732 			 * add_pkg_list starting with the pkg names.
6733 			 */
6734 			int j;
6735 			char	*nlp;
6736 
6737 			for (j = 0; j < 4 &&
6738 			    strtok_r(NULL, " ", &lastp) != NULL; j++)
6739 				;
6740 			/*
6741 			 * If there are < 4 fields this entry is corrupt,
6742 			 * just skip it.
6743 			 */
6744 			if (j < 4)
6745 				return (Z_OK);
6746 
6747 			/* strip newline from the line */
6748 			nlp = (lastp + strlen(lastp) - 1);
6749 			if (*nlp == '\n')
6750 				*nlp = '\0';
6751 
6752 			res = add_pkg_list(lastp, pkgs, pkg_cnt);
6753 			break;
6754 		}
6755 	}
6756 
6757 	return (res);
6758 }
6759 
6760 /*
6761  * Read an entry from a pkginfo or contents file.  Some of these lines can
6762  * either be arbitrarily long or be continued by a backslash at the end of
6763  * the line.  This function coalesces lines that are longer than the read
6764  * buffer, and lines that are continued, into one buffer which is returned.
6765  * The caller must free this memory.  NULL is returned when we hit EOF or
6766  * if we run out of memory (errno is set to ENOMEM).
6767  */
6768 static char *
6769 read_pkg_data(FILE *fp)
6770 {
6771 	char *start;
6772 	char *inp;
6773 	char *p;
6774 	int char_cnt = 0;
6775 
6776 	errno = 0;
6777 	if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) {
6778 		errno = ENOMEM;
6779 		return (NULL);
6780 	}
6781 
6782 	inp = start;
6783 	while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) {
6784 		int len;
6785 
6786 		len = strlen(inp);
6787 		if (inp[len - 1] == '\n' &&
6788 		    (len == 1 || inp[len - 2] != '\\')) {
6789 			char_cnt = len;
6790 			break;
6791 		}
6792 
6793 		if (inp[len - 2] == '\\')
6794 			char_cnt += len - 2;
6795 		else
6796 			char_cnt += PKGINFO_RD_LEN - 1;
6797 
6798 		if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) {
6799 			errno = ENOMEM;
6800 			break;
6801 		}
6802 
6803 		start = p;
6804 		inp = start + char_cnt;
6805 	}
6806 
6807 	if (errno == ENOMEM || (p == NULL && char_cnt == 0)) {
6808 		free(start);
6809 		start = NULL;
6810 	}
6811 
6812 	return (start);
6813 }
6814 
6815 static void
6816 free_ipd_pkgs(char **pkgs, int cnt)
6817 {
6818 	int i;
6819 
6820 	for (i = 0; i < cnt; i++)
6821 		free(pkgs[i]);
6822 	free(pkgs);
6823 }
6824 
6825 /*
6826  * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the
6827  * list of pkgs that deliver into those dirs.
6828  */
6829 static int
6830 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt)
6831 {
6832 	int	res;
6833 	struct zone_fstab fstab;
6834 	int	ipd_cnt = 0;
6835 	char	**ipds = NULL;
6836 	int	pkg_cnt = 0;
6837 	char	**pkgs = NULL;
6838 	int	i;
6839 
6840 	if ((res = zonecfg_setipdent(handle)) != Z_OK)
6841 		return (res);
6842 
6843 	while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
6844 		char	**p;
6845 		int	len;
6846 
6847 		if ((p = (char **)realloc(ipds,
6848 		    sizeof (char *) * (ipd_cnt + 2))) == NULL) {
6849 			res = Z_NOMEM;
6850 			break;
6851 		}
6852 		ipds = p;
6853 
6854 		if ((ipds[ipd_cnt] = strdup(fstab.zone_fs_dir)) == NULL) {
6855 			res = Z_NOMEM;
6856 			break;
6857 		}
6858 		ipd_cnt++;
6859 
6860 		len = strlen(fstab.zone_fs_dir) + 3;
6861 		if ((ipds[ipd_cnt] = malloc(len)) == NULL) {
6862 			res = Z_NOMEM;
6863 			break;
6864 		}
6865 
6866 		(void) snprintf(ipds[ipd_cnt], len, "%s/*", fstab.zone_fs_dir);
6867 		ipd_cnt++;
6868 	}
6869 
6870 	(void) zonecfg_endipdent(handle);
6871 
6872 	if (res != Z_OK) {
6873 		for (i = 0; i < ipd_cnt; i++)
6874 			free(ipds[i]);
6875 		free(ipds);
6876 		return (res);
6877 	}
6878 
6879 	/* We only have to process the contents file if we have ipds. */
6880 	if (ipd_cnt > 0) {
6881 		FILE	*fp;
6882 
6883 		if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) {
6884 			char	*buf;
6885 
6886 			while ((buf = read_pkg_data(fp)) != NULL) {
6887 				res = get_path_pkgs(buf, ipds, ipd_cnt, &pkgs,
6888 				    &pkg_cnt);
6889 				free(buf);
6890 				if (res != Z_OK)
6891 					break;
6892 			}
6893 
6894 			(void) fclose(fp);
6895 		}
6896 	}
6897 
6898 	for (i = 0; i < ipd_cnt; i++)
6899 		free(ipds[i]);
6900 	free(ipds);
6901 
6902 	if (res != Z_OK) {
6903 		free_ipd_pkgs(pkgs, pkg_cnt);
6904 	} else {
6905 		*pkg_list = pkgs;
6906 		*cnt = pkg_cnt;
6907 	}
6908 
6909 	return (res);
6910 }
6911 
6912 /*
6913  * Return true if pkg_name is in the list of pkgs that deliver into an
6914  * inherited pkg directory for the zone.
6915  */
6916 static boolean_t
6917 dir_pkg(char *pkg_name, char **pkg_list, int cnt)
6918 {
6919 	int i;
6920 
6921 	for (i = 0; i < cnt; i++) {
6922 		if (strcmp(pkg_name, pkg_list[i]) == 0)
6923 			return (B_TRUE);
6924 	}
6925 
6926 	return (B_FALSE);
6927 }
6928 
6929 /*
6930  * Start by adding the patch to the sw inventory on the handle.
6931  *
6932  * The info parameter will be the portion of the PATCH_INFO_ entry following
6933  * the '='.  For example:
6934  * Installed: Wed Dec  7 07:13:51 PST 2005 From: mum Obsoletes: 120777-03 \
6935  *	121087-02 119108-07 Requires: 119575-02 119255-06 Incompatibles:
6936  *
6937  * A backed out patch will have an info line of "backed out\n".  We should
6938  * skip these patches.
6939  *
6940  * We also want to add the Obsolete and Incompatible patches to the
6941  * sw inventory description of this patch.
6942  */
6943 static int
6944 add_patch(zone_dochandle_t handle, char *patch, char *info)
6945 {
6946 	xmlNodePtr	node;
6947 	xmlNodePtr	cur;
6948 	int		err;
6949 	char		*p;
6950 	char		*lastp;
6951 	boolean_t	add_info = B_FALSE;
6952 	boolean_t	obsolete;
6953 
6954 	if (strcmp(info, "backed out\n") == 0)
6955 		return (Z_OK);
6956 
6957 	if ((err = operation_prep(handle)) != Z_OK)
6958 		return (err);
6959 
6960 	cur = handle->zone_dh_cur;
6961 	node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL);
6962 	if ((err = newprop(node, DTD_ATTR_ID, patch)) != Z_OK)
6963 		return (err);
6964 
6965 	/*
6966 	 * Start with the first token.  This will probably be "Installed:".
6967 	 * If we can't tokenize this entry, just return.
6968 	 */
6969 	if ((p = strtok_r(info, " ", &lastp)) == NULL)
6970 		return (Z_OK);
6971 
6972 	do {
6973 		xmlNodePtr new_node;
6974 		char	*nlp;
6975 
6976 		if (strcmp(p, "Installed:") == 0 ||
6977 		    strcmp(p, "Requires:") == 0 ||
6978 		    strcmp(p, "From:") == 0) {
6979 			add_info = B_FALSE;
6980 			continue;
6981 		} else if (strcmp(p, "Obsoletes:") == 0) {
6982 			obsolete = B_TRUE;
6983 			add_info = B_TRUE;
6984 			continue;
6985 		} else if (strcmp(p, "Incompatibles:") == 0) {
6986 			obsolete = B_FALSE;
6987 			add_info = B_TRUE;
6988 			continue;
6989 		}
6990 
6991 		if (!add_info)
6992 			continue;
6993 
6994 		/* strip newline from last patch in the line */
6995 		nlp = (p + strlen(p) - 1);
6996 		if (*nlp == '\n')
6997 			*nlp = '\0';
6998 
6999 		if (obsolete)
7000 			new_node = xmlNewTextChild(node, NULL,
7001 			    DTD_ELEM_OBSOLETES, NULL);
7002 		else
7003 			new_node = xmlNewTextChild(node, NULL,
7004 			    DTD_ELEM_INCOMPATIBLE, NULL);
7005 
7006 		if ((err = newprop(new_node, DTD_ATTR_ID, p)) != Z_OK)
7007 			return (err);
7008 
7009 	} while ((p = strtok_r(NULL, " ", &lastp)) != NULL);
7010 
7011 	return (Z_OK);
7012 }
7013 
7014 static boolean_t
7015 unique_patch(zone_dochandle_t handle, char *patch)
7016 {
7017 	xmlNodePtr	cur;
7018 	char		id[MAXNAMELEN];
7019 
7020 	cur = xmlDocGetRootElement(handle->zone_dh_doc);
7021 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
7022 		if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) {
7023 			if (fetchprop(cur, DTD_ATTR_ID, id, sizeof (id))
7024 			    != Z_OK)
7025 				continue;
7026 
7027 			if (strcmp(patch, id) == 0)
7028 				return (B_FALSE);
7029 		}
7030 	}
7031 
7032 	return (B_TRUE);
7033 }
7034 
7035 /*
7036  * Add the unique patches associated with this pkg to the sw inventory on the
7037  * handle.
7038  *
7039  * We are processing entries of the form:
7040  * PATCH_INFO_121454-02=Installed: Wed Dec  7 07:13:51 PST 2005 From: mum \
7041  *	Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \
7042  *	119255-06 Incompatibles:
7043  *
7044  */
7045 static int
7046 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop)
7047 {
7048 	int i;
7049 	int res = Z_OK;
7050 
7051 	for (i = 0; i < infop->zpi_patch_cnt; i++) {
7052 		char *p, *ep;
7053 
7054 		if (strlen(infop->zpi_patchinfo[i]) < (sizeof (PATCHINFO) - 1))
7055 			continue;
7056 
7057 		/* Skip over "PATCH_INFO_" to get the patch id. */
7058 		p = infop->zpi_patchinfo[i] + sizeof (PATCHINFO) - 1;
7059 		if ((ep = strchr(p, '=')) == NULL)
7060 			continue;
7061 
7062 		*ep = '\0';
7063 		if (unique_patch(handle, p))
7064 			if ((res = add_patch(handle, p, ep + 1)) != Z_OK)
7065 				break;
7066 	}
7067 
7068 	return (res);
7069 }
7070 
7071 /*
7072  * Add the pkg to the sw inventory on the handle.
7073  */
7074 static int
7075 add_pkg(zone_dochandle_t handle, char *name, char *version)
7076 {
7077 	xmlNodePtr newnode;
7078 	xmlNodePtr cur;
7079 	int err;
7080 
7081 	if ((err = operation_prep(handle)) != Z_OK)
7082 		return (err);
7083 
7084 	cur = handle->zone_dh_cur;
7085 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL);
7086 	if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK)
7087 		return (err);
7088 	if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK)
7089 		return (err);
7090 	return (Z_OK);
7091 }
7092 
7093 static void
7094 free_pkginfo(struct zone_pkginfo *infop)
7095 {
7096 	free(infop->zpi_version);
7097 	if (infop->zpi_patch_cnt > 0) {
7098 		int i;
7099 
7100 		for (i = 0; i < infop->zpi_patch_cnt; i++)
7101 			free(infop->zpi_patchinfo[i]);
7102 		free(infop->zpi_patchinfo);
7103 	}
7104 }
7105 
7106 /*
7107  * Read the pkginfo file and populate the structure with the data we need
7108  * from this pkg for a sw inventory.
7109  */
7110 static int
7111 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop)
7112 {
7113 	FILE	*fp;
7114 	char	*buf;
7115 	int	err = 0;
7116 
7117 	infop->zpi_all_zones = B_FALSE;
7118 	infop->zpi_this_zone = B_FALSE;
7119 	infop->zpi_version = NULL;
7120 	infop->zpi_patch_cnt = 0;
7121 	infop->zpi_patchinfo = NULL;
7122 
7123 	if ((fp = fopen(pkginfo, "r")) == NULL)
7124 		return (errno);
7125 
7126 	while ((buf = read_pkg_data(fp)) != NULL) {
7127 		if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) {
7128 			int len;
7129 
7130 			if ((infop->zpi_version =
7131 			    strdup(buf + sizeof (VERSION) - 1)) == NULL) {
7132 				err = ENOMEM;
7133 				break;
7134 			}
7135 
7136 			/* remove trailing newline */
7137 			len = strlen(infop->zpi_version);
7138 			*(infop->zpi_version + len - 1) = 0;
7139 
7140 		} else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) {
7141 			infop->zpi_all_zones = B_TRUE;
7142 
7143 		} else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) {
7144 			infop->zpi_this_zone = B_TRUE;
7145 
7146 		} else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1)
7147 		    == 0) {
7148 			char **p;
7149 
7150 			if ((p = (char **)realloc(infop->zpi_patchinfo,
7151 			    sizeof (char *) * (infop->zpi_patch_cnt + 1)))
7152 			    == NULL) {
7153 				err = ENOMEM;
7154 				break;
7155 			}
7156 			infop->zpi_patchinfo = p;
7157 
7158 			if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] =
7159 			    strdup(buf)) == NULL) {
7160 				err = ENOMEM;
7161 				break;
7162 			}
7163 			infop->zpi_patch_cnt++;
7164 		}
7165 
7166 		free(buf);
7167 	}
7168 
7169 	free(buf);
7170 
7171 	if (errno == ENOMEM) {
7172 		err = ENOMEM;
7173 		/* Clean up anything we did manage to allocate. */
7174 		free_pkginfo(infop);
7175 	}
7176 
7177 	(void) fclose(fp);
7178 
7179 	return (err);
7180 }
7181 
7182 /*
7183  * Take a software inventory of the global zone.  We need to get the set of
7184  * packages and patches that are on the global zone that the specified
7185  * non-global zone depends on.  The packages we need in the inventory are:
7186  *
7187  * - skip the package if SUNW_PKG_THISZONE is 'true'
7188  * otherwise,
7189  * - add the package if
7190  * a) SUNW_PKG_ALLZONES is 'true',
7191  * or
7192  * b) any file delivered by the package is in a file system that is inherited
7193  * from the global zone.
7194  * If the zone does not inherit any file systems (whole root)
7195  * then (b) will be skipped.
7196  *
7197  * For each of the packages that is being added to the inventory, we will also
7198  * add all of the associated, unique patches to the inventory.
7199  */
7200 static int
7201 zonecfg_sw_inventory(zone_dochandle_t handle)
7202 {
7203 	char		pkginfo[MAXPATHLEN];
7204 	int		res;
7205 	struct dirent	*dp;
7206 	DIR		*dirp;
7207 	struct stat	buf;
7208 	struct zone_pkginfo	info;
7209 	int		pkg_cnt = 0;
7210 	char		**pkgs = NULL;
7211 
7212 	if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK)
7213 		return (res);
7214 
7215 	if ((dirp = opendir(PKG_PATH)) == NULL) {
7216 		free_ipd_pkgs(pkgs, pkg_cnt);
7217 		return (Z_OK);
7218 	}
7219 
7220 	while ((dp = readdir(dirp)) != (struct dirent *)0) {
7221 		if (strcmp(dp->d_name, ".") == 0 ||
7222 		    strcmp(dp->d_name, "..") == 0)
7223 			continue;
7224 
7225 		(void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo",
7226 		    PKG_PATH, dp->d_name);
7227 
7228 		if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode))
7229 			continue;
7230 
7231 		if (get_pkginfo(pkginfo, &info) != 0) {
7232 			res = Z_NOMEM;
7233 			break;
7234 		}
7235 
7236 		if (!info.zpi_this_zone &&
7237 		    (info.zpi_all_zones ||
7238 		    dir_pkg(dp->d_name, pkgs, pkg_cnt))) {
7239 			if ((res = add_pkg(handle, dp->d_name,
7240 			    info.zpi_version)) == Z_OK) {
7241 				if (info.zpi_patch_cnt > 0)
7242 					res = add_patches(handle, &info);
7243 			}
7244 		}
7245 
7246 		free_pkginfo(&info);
7247 
7248 		if (res != Z_OK)
7249 			break;
7250 	}
7251 
7252 	(void) closedir(dirp);
7253 
7254 	free_ipd_pkgs(pkgs, pkg_cnt);
7255 
7256 	if (res == Z_OK)
7257 		handle->zone_dh_sw_inv = B_TRUE;
7258 
7259 	return (res);
7260 }
7261 
7262 /*
7263  * zonecfg_devwalk call-back function used during detach to generate the
7264  * dev info in the manifest.
7265  */
7266 static int
7267 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
7268     const char *acl, void *hdl)
7269 {
7270 	zone_dochandle_t handle = (zone_dochandle_t)hdl;
7271 	xmlNodePtr newnode;
7272 	xmlNodePtr cur;
7273 	int err;
7274 	char buf[128];
7275 
7276 	if ((err = operation_prep(handle)) != Z_OK)
7277 		return (err);
7278 
7279 	cur = handle->zone_dh_cur;
7280 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
7281 	if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
7282 		return (err);
7283 	(void) snprintf(buf, sizeof (buf), "%lu", uid);
7284 	if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
7285 		return (err);
7286 	(void) snprintf(buf, sizeof (buf), "%lu", gid);
7287 	if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
7288 		return (err);
7289 	(void) snprintf(buf, sizeof (buf), "%o", mode);
7290 	if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
7291 		return (err);
7292 	if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
7293 		return (err);
7294 	return (Z_OK);
7295 }
7296 
7297 /*
7298  * Get the information required to support detaching a zone.  This is
7299  * called on the source system when detaching (the detaching parameter should
7300  * be set to true) and on the destination system before attaching (the
7301  * detaching parameter should be false).
7302  *
7303  * For native Solaris zones, the detach/attach process involves validating
7304  * that the software on the global zone can support the zone when we attach.
7305  * To do this we take a software inventory of the global zone.  We also
7306  * have to keep track of the device configuration so that we can properly
7307  * recreate it on the destination.
7308  */
7309 int
7310 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching)
7311 {
7312 	int		res;
7313 
7314 	if ((res = zonecfg_sw_inventory(handle)) != Z_OK)
7315 		return (res);
7316 
7317 	if (detaching)
7318 		res = zonecfg_devwalk(handle, get_detach_dev_entry, handle);
7319 
7320 	return (res);
7321 }
7322