1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <libsysevent.h>
30 #include <pthread.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <fnmatch.h>
34 #include <strings.h>
35 #include <unistd.h>
36 #include <sys/stat.h>
37 #include <assert.h>
38 #include <libgen.h>
39 #include <libintl.h>
40 #include <alloca.h>
41 #include <ctype.h>
42 #include <sys/mntio.h>
43 #include <sys/mnttab.h>
44 #include <sys/types.h>
45 #include <sys/nvpair.h>
46 #include <sys/acl.h>
47 #include <ftw.h>
48 
49 #include <arpa/inet.h>
50 #include <netdb.h>
51 
52 #include <libxml/xmlmemory.h>
53 #include <libxml/parser.h>
54 
55 #include <libdevinfo.h>
56 #include <uuid/uuid.h>
57 
58 #include <dirent.h>
59 
60 #include <libzonecfg.h>
61 #include "zonecfg_impl.h"
62 
63 
64 #define	_PATH_TMPFILE	"/zonecfg.XXXXXX"
65 #define	ZONE_CB_RETRY_COUNT		10
66 #define	ZONE_EVENT_PING_SUBCLASS	"ping"
67 #define	ZONE_EVENT_PING_PUBLISHER	"solaris"
68 
69 /* Hard-code the DTD element/attribute/entity names just once, here. */
70 #define	DTD_ELEM_ATTR		(const xmlChar *) "attr"
71 #define	DTD_ELEM_COMMENT	(const xmlChar *) "comment"
72 #define	DTD_ELEM_DEVICE		(const xmlChar *) "device"
73 #define	DTD_ELEM_FS		(const xmlChar *) "filesystem"
74 #define	DTD_ELEM_FSOPTION	(const xmlChar *) "fsoption"
75 #define	DTD_ELEM_IPD		(const xmlChar *) "inherited-pkg-dir"
76 #define	DTD_ELEM_NET		(const xmlChar *) "network"
77 #define	DTD_ELEM_RCTL		(const xmlChar *) "rctl"
78 #define	DTD_ELEM_RCTLVALUE	(const xmlChar *) "rctl-value"
79 #define	DTD_ELEM_ZONE		(const xmlChar *) "zone"
80 #define	DTD_ELEM_DATASET	(const xmlChar *) "dataset"
81 #define	DTD_ELEM_PACKAGE	(const xmlChar *) "package"
82 #define	DTD_ELEM_PATCH		(const xmlChar *) "patch"
83 #define	DTD_ELEM_OBSOLETES	(const xmlChar *) "obsoletes"
84 #define	DTD_ELEM_INCOMPATIBLE	(const xmlChar *) "incompatible"
85 #define	DTD_ELEM_DEV_PERM	(const xmlChar *) "dev-perm"
86 
87 #define	DTD_ATTR_ACTION		(const xmlChar *) "action"
88 #define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
89 #define	DTD_ATTR_AUTOBOOT	(const xmlChar *) "autoboot"
90 #define	DTD_ATTR_DIR		(const xmlChar *) "directory"
91 #define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
92 #define	DTD_ATTR_LIMITPRIV	(const xmlChar *) "limitpriv"
93 #define	DTD_ATTR_MATCH		(const xmlChar *) "match"
94 #define	DTD_ATTR_NAME		(const xmlChar *) "name"
95 #define	DTD_ATTR_PHYSICAL	(const xmlChar *) "physical"
96 #define	DTD_ATTR_POOL		(const xmlChar *) "pool"
97 #define	DTD_ATTR_PRIV		(const xmlChar *) "priv"
98 #define	DTD_ATTR_RAW		(const xmlChar *) "raw"
99 #define	DTD_ATTR_SPECIAL	(const xmlChar *) "special"
100 #define	DTD_ATTR_TYPE		(const xmlChar *) "type"
101 #define	DTD_ATTR_VALUE		(const xmlChar *) "value"
102 #define	DTD_ATTR_ZONEPATH	(const xmlChar *) "zonepath"
103 #define	DTD_ATTR_VERSION	(const xmlChar *) "version"
104 #define	DTD_ATTR_ID		(const xmlChar *) "id"
105 #define	DTD_ATTR_UID		(const xmlChar *) "uid"
106 #define	DTD_ATTR_GID		(const xmlChar *) "gid"
107 #define	DTD_ATTR_MODE		(const xmlChar *) "mode"
108 #define	DTD_ATTR_ACL		(const xmlChar *) "acl"
109 
110 #define	DTD_ENTITY_BOOLEAN	"boolean"
111 #define	DTD_ENTITY_DEVPATH	"devpath"
112 #define	DTD_ENTITY_DRIVER	"driver"
113 #define	DTD_ENTITY_DRVMIN	"drv_min"
114 #define	DTD_ENTITY_FALSE	"false"
115 #define	DTD_ENTITY_INT		"int"
116 #define	DTD_ENTITY_STRING	"string"
117 #define	DTD_ENTITY_TRUE		"true"
118 #define	DTD_ENTITY_UINT		"uint"
119 
120 #define	DTD_ENTITY_BOOL_LEN	6	/* "false" */
121 
122 #define	DETACHED	"SUNWdetached.xml"
123 #define	ATTACH_FORCED	"SUNWattached.xml"
124 #define	PKG_PATH	"/var/sadm/pkg"
125 #define	CONTENTS_FILE	"/var/sadm/install/contents"
126 #define	SUNW_PKG_ALL_ZONES	"SUNW_PKG_ALLZONES=true\n"
127 #define	SUNW_PKG_THIS_ZONE	"SUNW_PKG_THISZONE=true\n"
128 #define	VERSION		"VERSION="
129 #define	PATCHLIST	"PATCHLIST="
130 #define	PATCHINFO	"PATCH_INFO_"
131 #define	PKGINFO_RD_LEN	128
132 
133 struct zone_dochandle {
134 	char		*zone_dh_rootdir;
135 	xmlDocPtr	zone_dh_doc;
136 	xmlNodePtr	zone_dh_cur;
137 	xmlNodePtr	zone_dh_top;
138 	boolean_t	zone_dh_newzone;
139 	boolean_t	zone_dh_snapshot;
140 	boolean_t	zone_dh_sw_inv;
141 	char		zone_dh_delete_name[ZONENAME_MAX];
142 };
143 
144 struct znotify {
145 	void * zn_private;
146 	evchan_t *zn_eventchan;
147 	int (*zn_callback)(const  char *zonename, zoneid_t zid,
148 	    const char *newstate, const char *oldstate, hrtime_t when, void *p);
149 	pthread_mutex_t zn_mutex;
150 	pthread_cond_t zn_cond;
151 	pthread_mutex_t zn_bigmutex;
152 	volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
153 	    ZN_PING_RECEIVED} zn_state;
154 	char zn_subscriber_id[MAX_SUBID_LEN];
155 	volatile boolean_t zn_failed;
156 	int zn_failure_count;
157 };
158 
159 struct zone_pkginfo {
160 	boolean_t	zpi_all_zones;
161 	boolean_t	zpi_this_zone;
162 	int		zpi_patch_cnt;
163 	char		*zpi_version;
164 	char		**zpi_patchinfo;
165 };
166 
167 char *zonecfg_root = "";
168 
169 /*
170  * For functions which return int, which is most of the functions herein,
171  * the return values should be from the Z_foo set defined in <libzonecfg.h>.
172  * In some instances, we take pains mapping some libc errno values to Z_foo
173  * values from this set.
174  */
175 
176 /*
177  * Set the root (/) path for all zonecfg configuration files.  This is a
178  * private interface used by Live Upgrade extensions to access zone
179  * configuration inside mounted alternate boot environments.
180  */
181 void
182 zonecfg_set_root(const char *rootpath)
183 {
184 	if (*zonecfg_root != '\0')
185 		free(zonecfg_root);
186 	if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
187 	    (zonecfg_root = strdup(rootpath)) == NULL)
188 		zonecfg_root = "";
189 }
190 
191 const char *
192 zonecfg_get_root(void)
193 {
194 	return (zonecfg_root);
195 }
196 
197 boolean_t
198 zonecfg_in_alt_root(void)
199 {
200 	return (*zonecfg_root != '\0');
201 }
202 
203 /*
204  * Callers of the _file_path() functions are expected to have the second
205  * parameter be a (char foo[MAXPATHLEN]).
206  */
207 
208 static boolean_t
209 config_file_path(const char *zonename, char *answer)
210 {
211 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
212 	    ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
213 }
214 
215 static boolean_t
216 snap_file_path(const char *zonename, char *answer)
217 {
218 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
219 	    zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
220 }
221 
222 /*ARGSUSED*/
223 static void
224 zonecfg_error_func(void *ctx, const char *msg, ...)
225 {
226 	/*
227 	 * This function does nothing by design.  Its purpose is to prevent
228 	 * libxml from dumping unwanted messages to stdout/stderr.
229 	 */
230 }
231 
232 zone_dochandle_t
233 zonecfg_init_handle(void)
234 {
235 	zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
236 	if (handle == NULL) {
237 		errno = Z_NOMEM;
238 		return (NULL);
239 	}
240 
241 	/* generic libxml initialization */
242 	xmlLineNumbersDefault(1);
243 	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
244 	xmlDoValidityCheckingDefaultValue = 1;
245 	(void) xmlKeepBlanksDefault(0);
246 	xmlGetWarningsDefaultValue = 0;
247 	xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
248 
249 	return (handle);
250 }
251 
252 int
253 zonecfg_check_handle(zone_dochandle_t handle)
254 {
255 	if (handle == NULL || handle->zone_dh_doc == NULL)
256 		return (Z_BAD_HANDLE);
257 	return (Z_OK);
258 }
259 
260 void
261 zonecfg_fini_handle(zone_dochandle_t handle)
262 {
263 	if (zonecfg_check_handle(handle) == Z_OK)
264 		xmlFreeDoc(handle->zone_dh_doc);
265 	if (handle != NULL)
266 		free(handle);
267 }
268 
269 static int
270 zonecfg_destroy_impl(char *filename)
271 {
272 	if (unlink(filename) == -1) {
273 		if (errno == EACCES)
274 			return (Z_ACCES);
275 		if (errno == ENOENT)
276 			return (Z_NO_ZONE);
277 		return (Z_MISC_FS);
278 	}
279 	return (Z_OK);
280 }
281 
282 int
283 zonecfg_destroy(const char *zonename, boolean_t force)
284 {
285 	char path[MAXPATHLEN];
286 	struct zoneent ze;
287 	int err, state_err;
288 	zone_state_t state;
289 
290 	if (!config_file_path(zonename, path))
291 		return (Z_MISC_FS);
292 
293 	state_err = zone_get_state((char *)zonename, &state);
294 	err = access(path, W_OK);
295 
296 	/*
297 	 * If there is no file, and no index entry, reliably indicate that no
298 	 * such zone exists.
299 	 */
300 	if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
301 		return (Z_NO_ZONE);
302 
303 	/*
304 	 * Handle any other filesystem related errors (except if the XML
305 	 * file is missing, which we treat silently), unless we're forcing,
306 	 * in which case we plow on.
307 	 */
308 	if (err == -1 && errno != ENOENT) {
309 		if (errno == EACCES)
310 			return (Z_ACCES);
311 		else if (!force)
312 			return (Z_MISC_FS);
313 	}
314 
315 	if (state > ZONE_STATE_INSTALLED)
316 		return (Z_BAD_ZONE_STATE);
317 
318 	if (!force && state > ZONE_STATE_CONFIGURED)
319 		return (Z_BAD_ZONE_STATE);
320 
321 	/*
322 	 * Index deletion succeeds even if the entry doesn't exist.  So this
323 	 * will fail only if we've had some more severe problem.
324 	 */
325 	bzero(&ze, sizeof (ze));
326 	(void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
327 	if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
328 		if (!force)
329 			return (err);
330 
331 	err = zonecfg_destroy_impl(path);
332 
333 	/*
334 	 * Treat failure to find the XML file silently, since, well, it's
335 	 * gone, and with the index file cleaned up, we're done.
336 	 */
337 	if (err == Z_OK || err == Z_NO_ZONE)
338 		return (Z_OK);
339 	return (err);
340 }
341 
342 int
343 zonecfg_destroy_snapshot(const char *zonename)
344 {
345 	char path[MAXPATHLEN];
346 
347 	if (!snap_file_path(zonename, path))
348 		return (Z_MISC_FS);
349 	return (zonecfg_destroy_impl(path));
350 }
351 
352 static int
353 getroot(zone_dochandle_t handle, xmlNodePtr *root)
354 {
355 	if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
356 		return (Z_BAD_HANDLE);
357 
358 	*root = xmlDocGetRootElement(handle->zone_dh_doc);
359 
360 	if (*root == NULL)
361 		return (Z_EMPTY_DOCUMENT);
362 
363 	if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
364 		return (Z_WRONG_DOC_TYPE);
365 
366 	return (Z_OK);
367 }
368 
369 static int
370 operation_prep(zone_dochandle_t handle)
371 {
372 	xmlNodePtr root;
373 	int err;
374 
375 	if ((err = getroot(handle, &root)) != 0)
376 		return (err);
377 
378 	handle->zone_dh_cur = root;
379 	handle->zone_dh_top = root;
380 	return (Z_OK);
381 }
382 
383 static int
384 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
385 {
386 	xmlChar *property;
387 	size_t srcsize;
388 
389 	if ((property = xmlGetProp(cur, propname)) == NULL)
390 		return (Z_BAD_PROPERTY);
391 	srcsize = strlcpy(dst, (char *)property, dstsize);
392 	xmlFree(property);
393 	if (srcsize >= dstsize)
394 		return (Z_TOO_BIG);
395 	return (Z_OK);
396 }
397 
398 static int
399 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst)
400 {
401 	xmlChar *property;
402 
403 	if ((property = xmlGetProp(cur, propname)) == NULL)
404 		return (Z_BAD_PROPERTY);
405 	if ((*dst = strdup((char *)property)) == NULL) {
406 		xmlFree(property);
407 		return (Z_NOMEM);
408 	}
409 	xmlFree(property);
410 	return (Z_OK);
411 }
412 
413 static int
414 getrootattr(zone_dochandle_t handle, const xmlChar *propname,
415     char *propval, size_t propsize)
416 {
417 	xmlNodePtr root;
418 	int err;
419 
420 	if ((err = getroot(handle, &root)) != 0)
421 		return (err);
422 
423 	return (fetchprop(root, propname, propval, propsize));
424 }
425 
426 static int
427 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname,
428     char **propval)
429 {
430 	xmlNodePtr root;
431 	int err;
432 
433 	if ((err = getroot(handle, &root)) != 0)
434 		return (err);
435 
436 	return (fetch_alloc_prop(root, propname, propval));
437 }
438 
439 static int
440 setrootattr(zone_dochandle_t handle, const xmlChar *propname,
441     const char *propval)
442 {
443 	int err;
444 	xmlNodePtr root;
445 
446 	if (propval == NULL)
447 		return (Z_INVAL);
448 
449 	if ((err = getroot(handle, &root)) != Z_OK)
450 		return (err);
451 
452 	if (xmlSetProp(root, propname, (const xmlChar *) propval) == NULL)
453 		return (Z_INVAL);
454 	return (Z_OK);
455 }
456 
457 static void
458 addcomment(zone_dochandle_t handle, const char *comment)
459 {
460 	xmlNodePtr node;
461 	node = xmlNewComment((xmlChar *) comment);
462 
463 	if (node != NULL)
464 		(void) xmlAddPrevSibling(handle->zone_dh_top, node);
465 }
466 
467 static void
468 stripcomments(zone_dochandle_t handle)
469 {
470 	xmlDocPtr top;
471 	xmlNodePtr child, next;
472 
473 	top = handle->zone_dh_doc;
474 	for (child = top->xmlChildrenNode; child != NULL; child = next) {
475 		next = child->next;
476 		if (child->name == NULL)
477 			continue;
478 		if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
479 			next = child->next;
480 			xmlUnlinkNode(child);
481 			xmlFreeNode(child);
482 		}
483 	}
484 }
485 
486 static void
487 strip_sw_inv(zone_dochandle_t handle)
488 {
489 	xmlNodePtr root, child, next;
490 
491 	root = xmlDocGetRootElement(handle->zone_dh_doc);
492 	for (child = root->xmlChildrenNode; child != NULL; child = next) {
493 		next = child->next;
494 		if (child->name == NULL)
495 			continue;
496 		if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0 ||
497 		    xmlStrcmp(child->name, DTD_ELEM_PATCH) == 0) {
498 			next = child->next;
499 			xmlUnlinkNode(child);
500 			xmlFreeNode(child);
501 		}
502 	}
503 }
504 
505 static int
506 zonecfg_get_handle_impl(const char *zonename, const char *filename,
507     zone_dochandle_t handle)
508 {
509 	xmlValidCtxtPtr cvp;
510 	struct stat statbuf;
511 	int valid;
512 
513 	if (zonename == NULL)
514 		return (Z_NO_ZONE);
515 	if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
516 		/* distinguish file not found vs. found but not parsed */
517 		if (stat(filename, &statbuf) == 0)
518 			return (Z_INVALID_DOCUMENT);
519 		return (Z_NO_ZONE);
520 	}
521 	if ((cvp = xmlNewValidCtxt()) == NULL)
522 		return (Z_NOMEM);
523 	cvp->error = zonecfg_error_func;
524 	cvp->warning = zonecfg_error_func;
525 	valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
526 	xmlFreeValidCtxt(cvp);
527 	if (valid == 0)
528 		return (Z_INVALID_DOCUMENT);
529 
530 	/* delete any comments such as inherited Sun copyright / ident str */
531 	stripcomments(handle);
532 	return (Z_OK);
533 }
534 
535 int
536 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
537 {
538 	char path[MAXPATHLEN];
539 
540 	if (!config_file_path(zonename, path))
541 		return (Z_MISC_FS);
542 	handle->zone_dh_newzone = B_FALSE;
543 
544 	return (zonecfg_get_handle_impl(zonename, path, handle));
545 }
546 
547 int
548 zonecfg_get_attach_handle(const char *path, const char *zonename,
549     boolean_t preserve_sw, zone_dochandle_t handle)
550 {
551 	char		migpath[MAXPATHLEN];
552 	int		err;
553 	struct stat	buf;
554 
555 	if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
556 	    sizeof (migpath))
557 		return (Z_NOMEM);
558 
559 	if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
560 		return (Z_NO_ZONE);
561 
562 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >=
563 	    sizeof (migpath))
564 		return (Z_NOMEM);
565 
566 	if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
567 		return (err);
568 
569 	if (!preserve_sw)
570 		strip_sw_inv(handle);
571 
572 	handle->zone_dh_newzone = B_TRUE;
573 	if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
574 		return (err);
575 
576 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
577 }
578 
579 int
580 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
581 {
582 	char path[MAXPATHLEN];
583 
584 	if (!snap_file_path(zonename, path))
585 		return (Z_MISC_FS);
586 	handle->zone_dh_newzone = B_FALSE;
587 	return (zonecfg_get_handle_impl(zonename, path, handle));
588 }
589 
590 int
591 zonecfg_get_template_handle(const char *template, const char *zonename,
592     zone_dochandle_t handle)
593 {
594 	char path[MAXPATHLEN];
595 	int err;
596 
597 	if (!config_file_path(template, path))
598 		return (Z_MISC_FS);
599 
600 	if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
601 		return (err);
602 	handle->zone_dh_newzone = B_TRUE;
603 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
604 }
605 
606 static boolean_t
607 is_renaming(zone_dochandle_t handle)
608 {
609 	if (handle->zone_dh_newzone)
610 		return (B_FALSE);
611 	if (strlen(handle->zone_dh_delete_name) > 0)
612 		return (B_TRUE);
613 	return (B_FALSE);
614 }
615 
616 static boolean_t
617 is_new(zone_dochandle_t handle)
618 {
619 	return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
620 }
621 
622 static boolean_t
623 is_snapshot(zone_dochandle_t handle)
624 {
625 	return (handle->zone_dh_snapshot);
626 }
627 
628 /*
629  * It would be great to be able to use libc's ctype(3c) macros, but we
630  * can't, as they are locale sensitive, and it would break our limited thread
631  * safety if this routine had to change the app locale on the fly.
632  */
633 int
634 zonecfg_validate_zonename(const char *zone)
635 {
636 	int i;
637 
638 	if (strcmp(zone, GLOBAL_ZONENAME) == 0)
639 		return (Z_BOGUS_ZONE_NAME);
640 
641 	if (strlen(zone) >= ZONENAME_MAX)
642 		return (Z_BOGUS_ZONE_NAME);
643 
644 	if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
645 	    (zone[0] >= 'A' && zone[0] <= 'Z') ||
646 	    (zone[0] >= '0' && zone[0] <= '9')))
647 		return (Z_BOGUS_ZONE_NAME);
648 
649 	for (i = 1; zone[i] != '\0'; i++) {
650 		if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
651 		    (zone[i] >= 'A' && zone[i] <= 'Z') ||
652 		    (zone[i] >= '0' && zone[i] <= '9') ||
653 		    (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
654 			return (Z_BOGUS_ZONE_NAME);
655 	}
656 
657 	return (Z_OK);
658 }
659 
660 /*
661  * Changing the zone name requires us to track both the old and new
662  * name of the zone until commit time.
663  */
664 int
665 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
666 {
667 	return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
668 }
669 
670 int
671 zonecfg_set_name(zone_dochandle_t handle, char *name)
672 {
673 	zone_state_t state;
674 	char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
675 	int err;
676 
677 	if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
678 	    sizeof (curname))) != Z_OK)
679 		return (err);
680 
681 	if (strcmp(name, curname) == 0)
682 		return (Z_OK);
683 
684 	/*
685 	 * Switching zone names to one beginning with SUNW is not permitted.
686 	 */
687 	if (strncmp(name, "SUNW", 4) == 0)
688 		return (Z_BOGUS_ZONE_NAME);
689 
690 	if ((err = zonecfg_validate_zonename(name)) != Z_OK)
691 		return (err);
692 
693 	/*
694 	 * Setting the name back to the original name (effectively a revert of
695 	 * the name) is fine.  But if we carry on, we'll falsely identify the
696 	 * name as "in use," so special case here.
697 	 */
698 	if (strcmp(name, handle->zone_dh_delete_name) == 0) {
699 		err = setrootattr(handle, DTD_ATTR_NAME, name);
700 		handle->zone_dh_delete_name[0] = '\0';
701 		return (err);
702 	}
703 
704 	/* Check to see if new name chosen is already in use */
705 	if (zone_get_state(name, &state) != Z_NO_ZONE)
706 		return (Z_NAME_IN_USE);
707 
708 	/*
709 	 * If this isn't already "new" or in a renaming transition, then
710 	 * we're initiating a rename here; so stash the "delete name"
711 	 * (i.e. the name of the zone we'll be removing) for the rename.
712 	 */
713 	(void) strlcpy(old_delname, handle->zone_dh_delete_name,
714 	    sizeof (old_delname));
715 	if (!is_new(handle) && !is_renaming(handle)) {
716 		/*
717 		 * Name change is allowed only when the zone we're altering
718 		 * is not ready or running.
719 		 */
720 		err = zone_get_state(curname, &state);
721 		if (err == Z_OK) {
722 			if (state > ZONE_STATE_INSTALLED)
723 				return (Z_BAD_ZONE_STATE);
724 		} else if (err != Z_NO_ZONE) {
725 			return (err);
726 		}
727 
728 		(void) strlcpy(handle->zone_dh_delete_name, curname,
729 		    sizeof (handle->zone_dh_delete_name));
730 		assert(is_renaming(handle));
731 	} else if (is_renaming(handle)) {
732 		err = zone_get_state(handle->zone_dh_delete_name, &state);
733 		if (err == Z_OK) {
734 			if (state > ZONE_STATE_INSTALLED)
735 				return (Z_BAD_ZONE_STATE);
736 		} else if (err != Z_NO_ZONE) {
737 			return (err);
738 		}
739 	}
740 
741 	if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
742 		/*
743 		 * Restore the deletename to whatever it was at the
744 		 * top of the routine, since we've had a failure.
745 		 */
746 		(void) strlcpy(handle->zone_dh_delete_name, old_delname,
747 		    sizeof (handle->zone_dh_delete_name));
748 		return (err);
749 	}
750 
751 	return (Z_OK);
752 }
753 
754 int
755 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
756 {
757 	size_t len;
758 
759 	if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize)
760 		return (Z_TOO_BIG);
761 	return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len,
762 	    pathsize - len));
763 }
764 
765 int
766 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
767 {
768 	return (setrootattr(handle, DTD_ATTR_ZONEPATH, zonepath));
769 }
770 
771 int
772 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
773 {
774 	char autobootstr[DTD_ENTITY_BOOL_LEN];
775 	int ret;
776 
777 	if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
778 	    sizeof (autobootstr))) != Z_OK)
779 		return (ret);
780 
781 	if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
782 		*autoboot = B_TRUE;
783 	else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
784 		*autoboot = B_FALSE;
785 	else
786 		ret = Z_BAD_PROPERTY;
787 	return (ret);
788 }
789 
790 int
791 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
792 {
793 	return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
794 	    autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
795 }
796 
797 int
798 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
799 {
800 	return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
801 }
802 
803 int
804 zonecfg_set_pool(zone_dochandle_t handle, char *pool)
805 {
806 	return (setrootattr(handle, DTD_ATTR_POOL, pool));
807 }
808 
809 int
810 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv)
811 {
812 	return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
813 }
814 
815 int
816 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitprivsize)
817 {
818 	return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitprivsize));
819 }
820 
821 /*
822  * /etc/zones/index caches a vital piece of information which is also
823  * in the <zonename>.xml file: the path to the zone.  This is for performance,
824  * since we need to walk all zonepath's in order to be able to detect conflicts
825  * (see crosscheck_zonepaths() in the zoneadm command).
826  *
827  * An additional complexity is that when doing a rename, we'd like the entire
828  * index update operation (rename, and potential state changes) to be atomic.
829  * In general, the operation of this function should succeed or fail as
830  * a unit.
831  */
832 int
833 zonecfg_refresh_index_file(zone_dochandle_t handle)
834 {
835 	char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
836 	struct zoneent ze;
837 	int err;
838 	int opcode;
839 	char *zn;
840 
841 	bzero(&ze, sizeof (ze));
842 	ze.zone_state = -1;	/* Preserve existing state in index */
843 
844 	if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
845 		return (err);
846 	(void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
847 
848 	if ((err = zonecfg_get_zonepath(handle, zonepath,
849 	    sizeof (zonepath))) != Z_OK)
850 		return (err);
851 	(void) strlcpy(ze.zone_path, zonepath, sizeof (ze.zone_path));
852 
853 	if (is_renaming(handle)) {
854 		opcode = PZE_MODIFY;
855 		(void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
856 		    sizeof (ze.zone_name));
857 		(void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
858 	} else if (is_new(handle)) {
859 		FILE *cookie;
860 		/*
861 		 * Be tolerant of the zone already existing in the index file,
862 		 * since we might be forcibly overwriting an existing
863 		 * configuration with a new one (for example 'create -F'
864 		 * in zonecfg).
865 		 */
866 		opcode = PZE_ADD;
867 		cookie = setzoneent();
868 		while ((zn = getzoneent(cookie)) != NULL) {
869 			if (strcmp(zn, name) == 0) {
870 				opcode = PZE_MODIFY;
871 				free(zn);
872 				break;
873 			}
874 			free(zn);
875 		}
876 		endzoneent(cookie);
877 		ze.zone_state = ZONE_STATE_CONFIGURED;
878 	} else {
879 		opcode = PZE_MODIFY;
880 	}
881 
882 	if ((err = putzoneent(&ze, opcode)) != Z_OK)
883 		return (err);
884 
885 	return (Z_OK);
886 }
887 
888 /*
889  * The goal of this routine is to cause the index file update and the
890  * document save to happen as an atomic operation.  We do the document
891  * first, saving a backup copy using a hard link; if that succeeds, we go
892  * on to the index.  If that fails, we roll the document back into place.
893  *
894  * Strategy:
895  *
896  * New zone 'foo' configuration:
897  * 	Create tmpfile (zonecfg.xxxxxx)
898  * 	Write XML to tmpfile
899  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
900  * 	Add entry to index file
901  * 	If it fails, delete foo.xml, leaving nothing behind.
902  *
903  * Save existing zone 'foo':
904  * 	Make backup of foo.xml -> .backup
905  * 	Create tmpfile (zonecfg.xxxxxx)
906  * 	Write XML to tmpfile
907  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
908  * 	Modify index file as needed
909  * 	If it fails, recover from .backup -> foo.xml
910  *
911  * Rename 'foo' to 'bar':
912  * 	Create tmpfile (zonecfg.xxxxxx)
913  * 	Write XML to tmpfile
914  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
915  * 	Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
916  * 	If it fails, delete bar.xml; foo.xml is left behind.
917  */
918 static int
919 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
920 {
921 	char tmpfile[MAXPATHLEN];
922 	char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
923 	int tmpfd, err;
924 	xmlValidCtxt cvp = { NULL };
925 	boolean_t backup;
926 
927 	(void) strlcpy(tmpfile, filename, sizeof (tmpfile));
928 	(void) dirname(tmpfile);
929 	(void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
930 
931 	tmpfd = mkstemp(tmpfile);
932 	if (tmpfd == -1) {
933 		(void) unlink(tmpfile);
934 		return (Z_TEMP_FILE);
935 	}
936 	(void) close(tmpfd);
937 
938 	cvp.error = zonecfg_error_func;
939 	cvp.warning = zonecfg_error_func;
940 
941 	/*
942 	 * We do a final validation of the document-- but the library has
943 	 * malfunctioned if it fails to validate, so it's an assert.
944 	 */
945 	assert(xmlValidateDocument(&cvp, handle->zone_dh_doc) != 0);
946 
947 	if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
948 		goto err;
949 
950 	(void) chmod(tmpfile, 0644);
951 
952 	/*
953 	 * In the event we are doing a standard save, hard link a copy of the
954 	 * original file in .backup.<pid>.filename so we can restore it if
955 	 * something goes wrong.
956 	 */
957 	if (!is_new(handle) && !is_renaming(handle)) {
958 		backup = B_TRUE;
959 
960 		(void) strlcpy(bakdir, filename, sizeof (bakdir));
961 		(void) strlcpy(bakbase, filename, sizeof (bakbase));
962 		(void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
963 		    dirname(bakdir), getpid(), basename(bakbase));
964 
965 		if (link(filename, bakfile) == -1) {
966 			err = errno;
967 			(void) unlink(tmpfile);
968 			if (errno == EACCES)
969 				return (Z_ACCES);
970 			return (Z_MISC_FS);
971 		}
972 	}
973 
974 	/*
975 	 * Move the new document over top of the old.
976 	 * i.e.:   zonecfg.XXXXXX  ->  myzone.xml
977 	 */
978 	if (rename(tmpfile, filename) == -1) {
979 		err = errno;
980 		(void) unlink(tmpfile);
981 		if (backup)
982 			(void) unlink(bakfile);
983 		if (err == EACCES)
984 			return (Z_ACCES);
985 		return (Z_MISC_FS);
986 	}
987 
988 	/*
989 	 * If this is a snapshot, we're done-- don't add an index entry.
990 	 */
991 	if (is_snapshot(handle))
992 		return (Z_OK);
993 
994 	/* now update the index file to reflect whatever we just did */
995 	if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
996 		if (backup) {
997 			/*
998 			 * Try to restore from our backup.
999 			 */
1000 			(void) unlink(filename);
1001 			(void) rename(bakfile, filename);
1002 		} else {
1003 			/*
1004 			 * Either the zone is new, in which case we can delete
1005 			 * new.xml, or we're doing a rename, so ditto.
1006 			 */
1007 			assert(is_new(handle) || is_renaming(handle));
1008 			(void) unlink(filename);
1009 		}
1010 		return (Z_UPDATING_INDEX);
1011 	}
1012 
1013 	if (backup)
1014 		(void) unlink(bakfile);
1015 
1016 	return (Z_OK);
1017 
1018 err:
1019 	(void) unlink(tmpfile);
1020 	return (Z_SAVING_FILE);
1021 }
1022 
1023 int
1024 zonecfg_save(zone_dochandle_t handle)
1025 {
1026 	char zname[ZONENAME_MAX], path[MAXPATHLEN];
1027 	char delpath[MAXPATHLEN];
1028 	int err = Z_SAVING_FILE;
1029 
1030 	if (zonecfg_check_handle(handle) != Z_OK)
1031 		return (Z_BAD_HANDLE);
1032 
1033 	/*
1034 	 * We don't support saving snapshots or a tree containing a sw
1035 	 * inventory at this time.
1036 	 */
1037 	if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1038 		return (Z_INVAL);
1039 
1040 	if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1041 		return (err);
1042 
1043 	if (!config_file_path(zname, path))
1044 		return (Z_MISC_FS);
1045 
1046 	addcomment(handle, "\n    DO NOT EDIT THIS "
1047 	    "FILE.  Use zonecfg(1M) instead.\n");
1048 
1049 	err = zonecfg_save_impl(handle, path);
1050 
1051 	stripcomments(handle);
1052 
1053 	if (err != Z_OK)
1054 		return (err);
1055 
1056 	handle->zone_dh_newzone = B_FALSE;
1057 
1058 	if (is_renaming(handle)) {
1059 		if (config_file_path(handle->zone_dh_delete_name, delpath))
1060 			(void) unlink(delpath);
1061 		handle->zone_dh_delete_name[0] = '\0';
1062 	}
1063 
1064 	return (Z_OK);
1065 }
1066 
1067 int
1068 zonecfg_detach_save(zone_dochandle_t handle)
1069 {
1070 	char zname[ZONENAME_MAX];
1071 	char path[MAXPATHLEN];
1072 	char migpath[MAXPATHLEN];
1073 	xmlValidCtxt cvp = { NULL };
1074 	int err = Z_SAVING_FILE;
1075 
1076 	if (zonecfg_check_handle(handle) != Z_OK)
1077 		return (Z_BAD_HANDLE);
1078 
1079 	/*
1080 	 * We can only detach if we have taken a sw inventory.
1081 	 */
1082 	if (!handle->zone_dh_sw_inv)
1083 		return (Z_INVAL);
1084 
1085 	if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1086 		return (err);
1087 
1088 	if ((err = zone_get_zonepath(zname, path, sizeof (path))) != Z_OK)
1089 		return (err);
1090 
1091 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >=
1092 	    sizeof (migpath))
1093 		return (Z_NOMEM);
1094 
1095 	if ((err = operation_prep(handle)) != Z_OK)
1096 		return (err);
1097 
1098 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1099 	    "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1100 
1101 	cvp.error = zonecfg_error_func;
1102 	cvp.warning = zonecfg_error_func;
1103 
1104 	/*
1105 	 * We do a final validation of the document-- but the library has
1106 	 * malfunctioned if it fails to validate, so it's an assert.
1107 	 */
1108 	assert(xmlValidateDocument(&cvp, handle->zone_dh_doc) != 0);
1109 
1110 	if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1111 		return (Z_SAVING_FILE);
1112 
1113 	(void) chmod(migpath, 0644);
1114 
1115 	stripcomments(handle);
1116 
1117 	handle->zone_dh_newzone = B_FALSE;
1118 
1119 	return (Z_OK);
1120 }
1121 
1122 boolean_t
1123 zonecfg_detached(const char *path)
1124 {
1125 	char		migpath[MAXPATHLEN];
1126 	struct stat	buf;
1127 
1128 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >=
1129 	    sizeof (migpath))
1130 		return (B_FALSE);
1131 
1132 	if (stat(migpath, &buf) != -1)
1133 		return (B_TRUE);
1134 
1135 	return (B_FALSE);
1136 }
1137 
1138 void
1139 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced)
1140 {
1141 	char zname[ZONENAME_MAX];
1142 	char path[MAXPATHLEN];
1143 	char detached[MAXPATHLEN];
1144 	char attached[MAXPATHLEN];
1145 
1146 	if (zonecfg_check_handle(handle) != Z_OK)
1147 		return;
1148 
1149 	if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK)
1150 		return;
1151 
1152 	if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK)
1153 		return;
1154 
1155 	(void) snprintf(detached, sizeof (detached), "%s/%s", path, DETACHED);
1156 	(void) snprintf(attached, sizeof (attached), "%s/%s", path,
1157 	    ATTACH_FORCED);
1158 
1159 	if (forced) {
1160 		(void) rename(detached, attached);
1161 	} else {
1162 		(void) unlink(attached);
1163 		(void) unlink(detached);
1164 	}
1165 }
1166 
1167 /*
1168  * Special case: if access(2) fails with ENOENT, then try again using
1169  * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
1170  * work around the case of a config file which has not been created yet:
1171  * the user will need access to the directory so use that as a heuristic.
1172  */
1173 
1174 int
1175 zonecfg_access(const char *zonename, int amode)
1176 {
1177 	char path[MAXPATHLEN];
1178 
1179 	if (!config_file_path(zonename, path))
1180 		return (Z_INVAL);
1181 	if (access(path, amode) == 0)
1182 		return (Z_OK);
1183 	if (errno == ENOENT) {
1184 		if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1185 		    ZONE_CONFIG_ROOT) >= sizeof (path))
1186 			return (Z_INVAL);
1187 		if (access(path, amode) == 0)
1188 			return (Z_OK);
1189 	}
1190 	if (errno == EACCES)
1191 		return (Z_ACCES);
1192 	if (errno == EINVAL)
1193 		return (Z_INVAL);
1194 	return (Z_MISC_FS);
1195 }
1196 
1197 int
1198 zonecfg_create_snapshot(const char *zonename)
1199 {
1200 	zone_dochandle_t handle;
1201 	char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
1202 	int error = Z_OK, res;
1203 
1204 	if ((handle = zonecfg_init_handle()) == NULL) {
1205 		return (Z_NOMEM);
1206 	}
1207 
1208 	handle->zone_dh_newzone = B_TRUE;
1209 	handle->zone_dh_snapshot = B_TRUE;
1210 
1211 	if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
1212 		goto out;
1213 	if ((error = operation_prep(handle)) != Z_OK)
1214 		goto out;
1215 	error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
1216 	if (error != Z_OK)
1217 		goto out;
1218 	if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
1219 		error = Z_RESOLVED_PATH;
1220 		goto out;
1221 	}
1222 	/*
1223 	 * If the resolved path is not the same as the original path, then
1224 	 * save the resolved path in the snapshot, thus preventing any
1225 	 * potential problems down the line when zoneadmd goes to unmount
1226 	 * file systems and depends on initial string matches with resolved
1227 	 * paths.
1228 	 */
1229 	rpath[res] = '\0';
1230 	if (strcmp(zonepath, rpath) != 0) {
1231 		if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1232 			goto out;
1233 	}
1234 	if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1235 	    ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1236 		error = Z_MISC_FS;
1237 		goto out;
1238 	}
1239 	if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1240 		error = Z_MISC_FS;
1241 		goto out;
1242 	}
1243 
1244 	if (!snap_file_path(zonename, path)) {
1245 		error = Z_MISC_FS;
1246 		goto out;
1247 	}
1248 
1249 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1250 	    "It is a snapshot of running zone state.\n");
1251 
1252 	error = zonecfg_save_impl(handle, path);
1253 
1254 	stripcomments(handle);
1255 
1256 out:
1257 	zonecfg_fini_handle(handle);
1258 	return (error);
1259 }
1260 
1261 static int
1262 newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
1263 {
1264 	xmlAttrPtr newattr;
1265 
1266 	newattr = xmlNewProp(node, attrname, (xmlChar *)src);
1267 	if (newattr == NULL) {
1268 		xmlUnlinkNode(node);
1269 		xmlFreeNode(node);
1270 		return (Z_BAD_PROPERTY);
1271 	}
1272 	return (Z_OK);
1273 }
1274 
1275 static int
1276 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1277 {
1278 	xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
1279 	zone_fsopt_t *ptr;
1280 	int err;
1281 
1282 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
1283 	if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
1284 	    tabptr->zone_fs_special)) != Z_OK)
1285 		return (err);
1286 	if (tabptr->zone_fs_raw[0] != '\0' &&
1287 	    (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
1288 		return (err);
1289 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1290 		return (err);
1291 	if ((err = newprop(newnode, DTD_ATTR_TYPE,
1292 	    tabptr->zone_fs_type)) != Z_OK)
1293 		return (err);
1294 	if (tabptr->zone_fs_options != NULL) {
1295 		for (ptr = tabptr->zone_fs_options; ptr != NULL;
1296 		    ptr = ptr->zone_fsopt_next) {
1297 			options_node = xmlNewTextChild(newnode, NULL,
1298 			    DTD_ELEM_FSOPTION, NULL);
1299 			if ((err = newprop(options_node, DTD_ATTR_NAME,
1300 			    ptr->zone_fsopt_opt)) != Z_OK)
1301 				return (err);
1302 		}
1303 	}
1304 	return (Z_OK);
1305 }
1306 
1307 int
1308 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1309 {
1310 	int err;
1311 
1312 	if (tabptr == NULL)
1313 		return (Z_INVAL);
1314 
1315 	if ((err = operation_prep(handle)) != Z_OK)
1316 		return (err);
1317 
1318 	if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
1319 		return (err);
1320 
1321 	return (Z_OK);
1322 }
1323 
1324 static int
1325 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1326 {
1327 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
1328 	int err;
1329 
1330 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL);
1331 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1332 		return (err);
1333 	return (Z_OK);
1334 }
1335 
1336 int
1337 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
1338 {
1339 	int err;
1340 
1341 	if (tabptr == NULL)
1342 		return (Z_INVAL);
1343 
1344 	if ((err = operation_prep(handle)) != Z_OK)
1345 		return (err);
1346 
1347 	if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK)
1348 		return (err);
1349 
1350 	return (Z_OK);
1351 }
1352 
1353 int
1354 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
1355 {
1356 	zone_fsopt_t *last, *old, *new;
1357 
1358 	last = tabptr->zone_fs_options;
1359 	for (old = last; old != NULL; old = old->zone_fsopt_next)
1360 		last = old;	/* walk to the end of the list */
1361 	new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
1362 	if (new == NULL)
1363 		return (Z_NOMEM);
1364 	(void) strlcpy(new->zone_fsopt_opt, option,
1365 	    sizeof (new->zone_fsopt_opt));
1366 	new->zone_fsopt_next = NULL;
1367 	if (last == NULL)
1368 		tabptr->zone_fs_options = new;
1369 	else
1370 		last->zone_fsopt_next = new;
1371 	return (Z_OK);
1372 }
1373 
1374 int
1375 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
1376 {
1377 	zone_fsopt_t *last, *this, *next;
1378 
1379 	last = tabptr->zone_fs_options;
1380 	for (this = last; this != NULL; this = this->zone_fsopt_next) {
1381 		if (strcmp(this->zone_fsopt_opt, option) == 0) {
1382 			next = this->zone_fsopt_next;
1383 			if (this == tabptr->zone_fs_options)
1384 				tabptr->zone_fs_options = next;
1385 			else
1386 				last->zone_fsopt_next = next;
1387 			free(this);
1388 			return (Z_OK);
1389 		} else
1390 			last = this;
1391 	}
1392 	return (Z_NO_PROPERTY_ID);
1393 }
1394 
1395 void
1396 zonecfg_free_fs_option_list(zone_fsopt_t *list)
1397 {
1398 	zone_fsopt_t *this, *next;
1399 
1400 	for (this = list; this != NULL; this = next) {
1401 		next = this->zone_fsopt_next;
1402 		free(this);
1403 	}
1404 }
1405 
1406 void
1407 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
1408 {
1409 	if (valtab == NULL)
1410 		return;
1411 	zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
1412 	free(valtab);
1413 }
1414 
1415 static boolean_t
1416 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
1417 {
1418 	xmlChar *gotten_prop;
1419 	int prop_result;
1420 
1421 	gotten_prop = xmlGetProp(cur, attr);
1422 	if (gotten_prop == NULL)	/* shouldn't happen */
1423 		return (B_FALSE);
1424 	prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
1425 	xmlFree(gotten_prop);
1426 	return ((prop_result == 0));
1427 }
1428 
1429 static int
1430 zonecfg_delete_filesystem_core(zone_dochandle_t handle,
1431     struct zone_fstab *tabptr)
1432 {
1433 	xmlNodePtr cur = handle->zone_dh_cur;
1434 	boolean_t dir_match, spec_match, raw_match, type_match;
1435 
1436 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1437 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1438 			continue;
1439 		dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
1440 		spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
1441 		    tabptr->zone_fs_special);
1442 		raw_match = match_prop(cur, DTD_ATTR_RAW,
1443 		    tabptr->zone_fs_raw);
1444 		type_match = match_prop(cur, DTD_ATTR_TYPE,
1445 		    tabptr->zone_fs_type);
1446 		if (dir_match && spec_match && raw_match && type_match) {
1447 			xmlUnlinkNode(cur);
1448 			xmlFreeNode(cur);
1449 			return (Z_OK);
1450 		}
1451 	}
1452 	return (Z_NO_RESOURCE_ID);
1453 }
1454 
1455 int
1456 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1457 {
1458 	int err;
1459 
1460 	if (tabptr == NULL)
1461 		return (Z_INVAL);
1462 
1463 	if ((err = operation_prep(handle)) != Z_OK)
1464 		return (err);
1465 
1466 	if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
1467 		return (err);
1468 
1469 	return (Z_OK);
1470 }
1471 
1472 int
1473 zonecfg_modify_filesystem(
1474 	zone_dochandle_t handle,
1475 	struct zone_fstab *oldtabptr,
1476 	struct zone_fstab *newtabptr)
1477 {
1478 	int err;
1479 
1480 	if (oldtabptr == NULL || newtabptr == NULL)
1481 		return (Z_INVAL);
1482 
1483 	if ((err = operation_prep(handle)) != Z_OK)
1484 		return (err);
1485 
1486 	if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
1487 		return (err);
1488 
1489 	if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
1490 		return (err);
1491 
1492 	return (Z_OK);
1493 }
1494 
1495 static int
1496 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1497 {
1498 	xmlNodePtr cur = handle->zone_dh_cur;
1499 
1500 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1501 		if (xmlStrcmp(cur->name, DTD_ELEM_IPD))
1502 			continue;
1503 		if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) {
1504 			xmlUnlinkNode(cur);
1505 			xmlFreeNode(cur);
1506 			return (Z_OK);
1507 		}
1508 	}
1509 	return (Z_NO_RESOURCE_ID);
1510 }
1511 
1512 int
1513 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
1514 {
1515 	int err;
1516 
1517 	if (tabptr == NULL)
1518 		return (Z_INVAL);
1519 
1520 	if ((err = operation_prep(handle)) != Z_OK)
1521 		return (err);
1522 
1523 	if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK)
1524 		return (err);
1525 
1526 	return (Z_OK);
1527 }
1528 
1529 int
1530 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr,
1531     struct zone_fstab *newtabptr)
1532 {
1533 	int err;
1534 
1535 	if (oldtabptr == NULL || newtabptr == NULL)
1536 		return (Z_INVAL);
1537 
1538 	if ((err = operation_prep(handle)) != Z_OK)
1539 		return (err);
1540 
1541 	if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK)
1542 		return (err);
1543 
1544 	if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK)
1545 		return (err);
1546 
1547 	return (Z_OK);
1548 }
1549 
1550 int
1551 zonecfg_lookup_filesystem(
1552 	zone_dochandle_t handle,
1553 	struct zone_fstab *tabptr)
1554 {
1555 	xmlNodePtr cur, options, firstmatch;
1556 	int err;
1557 	char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
1558 	char type[FSTYPSZ];
1559 	char options_str[MAX_MNTOPT_STR];
1560 
1561 	if (tabptr == NULL)
1562 		return (Z_INVAL);
1563 
1564 	if ((err = operation_prep(handle)) != Z_OK)
1565 		return (err);
1566 
1567 	/*
1568 	 * Walk the list of children looking for matches on any properties
1569 	 * specified in the fstab parameter.  If more than one resource
1570 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1571 	 * Z_NO_RESOURCE_ID.
1572 	 */
1573 	cur = handle->zone_dh_cur;
1574 	firstmatch = NULL;
1575 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1576 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1577 			continue;
1578 		if (strlen(tabptr->zone_fs_dir) > 0) {
1579 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1580 			    sizeof (dirname)) == Z_OK) &&
1581 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1582 				if (firstmatch == NULL)
1583 					firstmatch = cur;
1584 				else
1585 					return (Z_INSUFFICIENT_SPEC);
1586 			}
1587 		}
1588 		if (strlen(tabptr->zone_fs_special) > 0) {
1589 			if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
1590 			    sizeof (special)) == Z_OK)) {
1591 				if (strcmp(tabptr->zone_fs_special,
1592 				    special) == 0) {
1593 					if (firstmatch == NULL)
1594 						firstmatch = cur;
1595 					else if (firstmatch != cur)
1596 						return (Z_INSUFFICIENT_SPEC);
1597 				} else {
1598 					/*
1599 					 * If another property matched but this
1600 					 * one doesn't then reset firstmatch.
1601 					 */
1602 					if (firstmatch == cur)
1603 						firstmatch = NULL;
1604 				}
1605 			}
1606 		}
1607 		if (strlen(tabptr->zone_fs_raw) > 0) {
1608 			if ((fetchprop(cur, DTD_ATTR_RAW, raw,
1609 			    sizeof (raw)) == Z_OK)) {
1610 				if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
1611 					if (firstmatch == NULL)
1612 						firstmatch = cur;
1613 					else if (firstmatch != cur)
1614 						return (Z_INSUFFICIENT_SPEC);
1615 				} else {
1616 					/*
1617 					 * If another property matched but this
1618 					 * one doesn't then reset firstmatch.
1619 					 */
1620 					if (firstmatch == cur)
1621 						firstmatch = NULL;
1622 				}
1623 			}
1624 		}
1625 		if (strlen(tabptr->zone_fs_type) > 0) {
1626 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
1627 			    sizeof (type)) == Z_OK)) {
1628 				if (strcmp(tabptr->zone_fs_type, type) == 0) {
1629 					if (firstmatch == NULL)
1630 						firstmatch = cur;
1631 					else if (firstmatch != cur)
1632 						return (Z_INSUFFICIENT_SPEC);
1633 				} else {
1634 					/*
1635 					 * If another property matched but this
1636 					 * one doesn't then reset firstmatch.
1637 					 */
1638 					if (firstmatch == cur)
1639 						firstmatch = NULL;
1640 				}
1641 			}
1642 		}
1643 	}
1644 
1645 	if (firstmatch == NULL)
1646 		return (Z_NO_RESOURCE_ID);
1647 
1648 	cur = firstmatch;
1649 
1650 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1651 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
1652 		return (err);
1653 
1654 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
1655 	    sizeof (tabptr->zone_fs_special))) != Z_OK)
1656 		return (err);
1657 
1658 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
1659 	    sizeof (tabptr->zone_fs_raw))) != Z_OK)
1660 		return (err);
1661 
1662 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
1663 	    sizeof (tabptr->zone_fs_type))) != Z_OK)
1664 		return (err);
1665 
1666 	/* options are optional */
1667 	tabptr->zone_fs_options = NULL;
1668 	for (options = cur->xmlChildrenNode; options != NULL;
1669 	    options = options->next) {
1670 		if ((fetchprop(options, DTD_ATTR_NAME, options_str,
1671 		    sizeof (options_str)) != Z_OK))
1672 			break;
1673 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
1674 			break;
1675 	}
1676 	return (Z_OK);
1677 }
1678 
1679 int
1680 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
1681 {
1682 	xmlNodePtr cur, match;
1683 	int err;
1684 	char dirname[MAXPATHLEN];
1685 
1686 	if (tabptr == NULL)
1687 		return (Z_INVAL);
1688 
1689 	if ((err = operation_prep(handle)) != Z_OK)
1690 		return (err);
1691 
1692 	/*
1693 	 * General algorithm:
1694 	 * Walk the list of children looking for matches on any properties
1695 	 * specified in the fstab parameter.  If more than one resource
1696 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1697 	 * Z_NO_RESOURCE_ID.
1698 	 */
1699 	cur = handle->zone_dh_cur;
1700 	match = NULL;
1701 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1702 		if (xmlStrcmp(cur->name, DTD_ELEM_IPD))
1703 			continue;
1704 		if (strlen(tabptr->zone_fs_dir) > 0) {
1705 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1706 			    sizeof (dirname)) == Z_OK) &&
1707 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1708 				if (match == NULL)
1709 					match = cur;
1710 				else
1711 					return (Z_INSUFFICIENT_SPEC);
1712 			}
1713 		}
1714 	}
1715 
1716 	if (match == NULL)
1717 		return (Z_NO_RESOURCE_ID);
1718 
1719 	cur = match;
1720 
1721 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1722 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
1723 		return (err);
1724 
1725 	return (Z_OK);
1726 }
1727 
1728 /*
1729  * Compare two IP addresses in string form.  Allow for the possibility that
1730  * one might have "/<prefix-length>" at the end: allow a match on just the
1731  * IP address (or host name) part.
1732  */
1733 
1734 boolean_t
1735 zonecfg_same_net_address(char *a1, char *a2)
1736 {
1737 	char *slashp, *slashp1, *slashp2;
1738 	int result;
1739 
1740 	if (strcmp(a1, a2) == 0)
1741 		return (B_TRUE);
1742 
1743 	/*
1744 	 * If neither has a slash or both do, they need to match to be
1745 	 * considered the same, but they did not match above, so fail.
1746 	 */
1747 	slashp1 = strchr(a1, '/');
1748 	slashp2 = strchr(a2, '/');
1749 	if ((slashp1 == NULL && slashp2 == NULL) ||
1750 	    (slashp1 != NULL && slashp2 != NULL))
1751 		return (B_FALSE);
1752 
1753 	/*
1754 	 * Only one had a slash: pick that one, zero out the slash, compare
1755 	 * the "address only" strings, restore the slash, and return the
1756 	 * result of the comparison.
1757 	 */
1758 	slashp = (slashp1 == NULL) ? slashp2 : slashp1;
1759 	*slashp = '\0';
1760 	result = strcmp(a1, a2);
1761 	*slashp = '/';
1762 	return ((result == 0));
1763 }
1764 
1765 int
1766 zonecfg_valid_net_address(char *address, struct lifreq *lifr)
1767 {
1768 	struct sockaddr_in *sin4;
1769 	struct sockaddr_in6 *sin6;
1770 	struct addrinfo hints, *result;
1771 	char *slashp = strchr(address, '/');
1772 
1773 	bzero(lifr, sizeof (struct lifreq));
1774 	sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
1775 	sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
1776 	if (slashp != NULL)
1777 		*slashp = '\0';
1778 	if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
1779 		sin4->sin_family = AF_INET;
1780 	} else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
1781 		if (slashp == NULL)
1782 			return (Z_IPV6_ADDR_PREFIX_LEN);
1783 		sin6->sin6_family = AF_INET6;
1784 	} else {
1785 		/* "address" may be a host name */
1786 		(void) memset(&hints, 0, sizeof (hints));
1787 		hints.ai_family = PF_INET;
1788 		if (getaddrinfo(address, NULL, &hints, &result) != 0)
1789 			return (Z_BOGUS_ADDRESS);
1790 		sin4->sin_family = result->ai_family;
1791 
1792 		(void) memcpy(&sin4->sin_addr,
1793 		    /* LINTED E_BAD_PTR_CAST_ALIGN */
1794 		    &((struct sockaddr_in *)result->ai_addr)->sin_addr,
1795 		    sizeof (struct in_addr));
1796 
1797 		freeaddrinfo(result);
1798 	}
1799 	return (Z_OK);
1800 }
1801 
1802 int
1803 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1804 {
1805 	xmlNodePtr cur, firstmatch;
1806 	int err;
1807 	char address[INET6_ADDRSTRLEN], physical[LIFNAMSIZ];
1808 
1809 	if (tabptr == NULL)
1810 		return (Z_INVAL);
1811 
1812 	if ((err = operation_prep(handle)) != Z_OK)
1813 		return (err);
1814 
1815 	cur = handle->zone_dh_cur;
1816 	firstmatch = NULL;
1817 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1818 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
1819 			continue;
1820 		if (strlen(tabptr->zone_nwif_physical) > 0) {
1821 			if ((fetchprop(cur, DTD_ATTR_PHYSICAL, physical,
1822 			    sizeof (physical)) == Z_OK) &&
1823 			    (strcmp(tabptr->zone_nwif_physical,
1824 			    physical) == 0)) {
1825 				if (firstmatch == NULL)
1826 					firstmatch = cur;
1827 				else
1828 					return (Z_INSUFFICIENT_SPEC);
1829 			}
1830 		}
1831 		if (strlen(tabptr->zone_nwif_address) > 0) {
1832 			if ((fetchprop(cur, DTD_ATTR_ADDRESS, address,
1833 			    sizeof (address)) == Z_OK)) {
1834 				if (zonecfg_same_net_address(
1835 				    tabptr->zone_nwif_address, address)) {
1836 					if (firstmatch == NULL)
1837 						firstmatch = cur;
1838 					else if (firstmatch != cur)
1839 						return (Z_INSUFFICIENT_SPEC);
1840 				} else {
1841 					/*
1842 					 * If another property matched but this
1843 					 * one doesn't then reset firstmatch.
1844 					 */
1845 					if (firstmatch == cur)
1846 						firstmatch = NULL;
1847 				}
1848 			}
1849 		}
1850 	}
1851 	if (firstmatch == NULL)
1852 		return (Z_NO_RESOURCE_ID);
1853 
1854 	cur = firstmatch;
1855 
1856 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
1857 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK)
1858 		return (err);
1859 
1860 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
1861 	    sizeof (tabptr->zone_nwif_address))) != Z_OK)
1862 		return (err);
1863 
1864 	return (Z_OK);
1865 }
1866 
1867 static int
1868 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1869 {
1870 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
1871 	int err;
1872 
1873 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
1874 	if ((err = newprop(newnode, DTD_ATTR_ADDRESS,
1875 	    tabptr->zone_nwif_address)) != Z_OK)
1876 		return (err);
1877 	if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
1878 	    tabptr->zone_nwif_physical)) != Z_OK)
1879 		return (err);
1880 	return (Z_OK);
1881 }
1882 
1883 int
1884 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1885 {
1886 	int err;
1887 
1888 	if (tabptr == NULL)
1889 		return (Z_INVAL);
1890 
1891 	if ((err = operation_prep(handle)) != Z_OK)
1892 		return (err);
1893 
1894 	if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
1895 		return (err);
1896 
1897 	return (Z_OK);
1898 }
1899 
1900 static int
1901 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1902 {
1903 	xmlNodePtr cur = handle->zone_dh_cur;
1904 	boolean_t addr_match, phys_match;
1905 
1906 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1907 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
1908 			continue;
1909 
1910 		addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
1911 		    tabptr->zone_nwif_address);
1912 		phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
1913 		    tabptr->zone_nwif_physical);
1914 
1915 		if (addr_match && phys_match) {
1916 			xmlUnlinkNode(cur);
1917 			xmlFreeNode(cur);
1918 			return (Z_OK);
1919 		}
1920 	}
1921 	return (Z_NO_RESOURCE_ID);
1922 }
1923 
1924 int
1925 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1926 {
1927 	int err;
1928 
1929 	if (tabptr == NULL)
1930 		return (Z_INVAL);
1931 
1932 	if ((err = operation_prep(handle)) != Z_OK)
1933 		return (err);
1934 
1935 	if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
1936 		return (err);
1937 
1938 	return (Z_OK);
1939 }
1940 
1941 int
1942 zonecfg_modify_nwif(
1943 	zone_dochandle_t handle,
1944 	struct zone_nwiftab *oldtabptr,
1945 	struct zone_nwiftab *newtabptr)
1946 {
1947 	int err;
1948 
1949 	if (oldtabptr == NULL || newtabptr == NULL)
1950 		return (Z_INVAL);
1951 
1952 	if ((err = operation_prep(handle)) != Z_OK)
1953 		return (err);
1954 
1955 	if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
1956 		return (err);
1957 
1958 	if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
1959 		return (err);
1960 
1961 	return (Z_OK);
1962 }
1963 
1964 int
1965 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
1966 {
1967 	xmlNodePtr cur, firstmatch;
1968 	int err;
1969 	char match[MAXPATHLEN];
1970 
1971 	if (tabptr == NULL)
1972 		return (Z_INVAL);
1973 
1974 	if ((err = operation_prep(handle)) != Z_OK)
1975 		return (err);
1976 
1977 	cur = handle->zone_dh_cur;
1978 	firstmatch = NULL;
1979 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1980 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
1981 			continue;
1982 		if (strlen(tabptr->zone_dev_match) == 0)
1983 			continue;
1984 
1985 		if ((fetchprop(cur, DTD_ATTR_MATCH, match,
1986 		    sizeof (match)) == Z_OK)) {
1987 			if (strcmp(tabptr->zone_dev_match,
1988 			    match) == 0) {
1989 				if (firstmatch == NULL)
1990 					firstmatch = cur;
1991 				else if (firstmatch != cur)
1992 					return (Z_INSUFFICIENT_SPEC);
1993 			} else {
1994 				/*
1995 				 * If another property matched but this
1996 				 * one doesn't then reset firstmatch.
1997 				 */
1998 				if (firstmatch == cur)
1999 					firstmatch = NULL;
2000 			}
2001 		}
2002 	}
2003 	if (firstmatch == NULL)
2004 		return (Z_NO_RESOURCE_ID);
2005 
2006 	cur = firstmatch;
2007 
2008 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2009 	    sizeof (tabptr->zone_dev_match))) != Z_OK)
2010 		return (err);
2011 
2012 	return (Z_OK);
2013 }
2014 
2015 static int
2016 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2017 {
2018 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2019 	int err;
2020 
2021 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2022 
2023 	if ((err = newprop(newnode, DTD_ATTR_MATCH,
2024 	    tabptr->zone_dev_match)) != Z_OK)
2025 		return (err);
2026 
2027 	return (Z_OK);
2028 }
2029 
2030 int
2031 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2032 {
2033 	int err;
2034 
2035 	if (tabptr == NULL)
2036 		return (Z_INVAL);
2037 
2038 	if ((err = operation_prep(handle)) != Z_OK)
2039 		return (err);
2040 
2041 	if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2042 		return (err);
2043 
2044 	return (Z_OK);
2045 }
2046 
2047 static int
2048 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2049 {
2050 	xmlNodePtr cur = handle->zone_dh_cur;
2051 	int match_match;
2052 
2053 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2054 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2055 			continue;
2056 
2057 		match_match = match_prop(cur, DTD_ATTR_MATCH,
2058 		    tabptr->zone_dev_match);
2059 
2060 		if (match_match) {
2061 			xmlUnlinkNode(cur);
2062 			xmlFreeNode(cur);
2063 			return (Z_OK);
2064 		}
2065 	}
2066 	return (Z_NO_RESOURCE_ID);
2067 }
2068 
2069 int
2070 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2071 {
2072 	int err;
2073 
2074 	if (tabptr == NULL)
2075 		return (Z_INVAL);
2076 
2077 	if ((err = operation_prep(handle)) != Z_OK)
2078 		return (err);
2079 
2080 	if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
2081 		return (err);
2082 
2083 	return (Z_OK);
2084 }
2085 
2086 int
2087 zonecfg_modify_dev(
2088 	zone_dochandle_t handle,
2089 	struct zone_devtab *oldtabptr,
2090 	struct zone_devtab *newtabptr)
2091 {
2092 	int err;
2093 
2094 	if (oldtabptr == NULL || newtabptr == NULL)
2095 		return (Z_INVAL);
2096 
2097 	if ((err = operation_prep(handle)) != Z_OK)
2098 		return (err);
2099 
2100 	if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
2101 		return (err);
2102 
2103 	if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
2104 		return (err);
2105 
2106 	return (Z_OK);
2107 }
2108 
2109 /* Lock to serialize all zonecfg_devwalks */
2110 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
2111 /*
2112  * Global variables used to pass data from zonecfg_devwalk to the nftw
2113  * call-back (zonecfg_devwalk_cb).  g_devwalk_data is really the void*
2114  * parameter and g_devwalk_cb is really the *cb parameter from zonecfg_devwalk.
2115  */
2116 static void *g_devwalk_data;
2117 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *,
2118     void *);
2119 static size_t g_devwalk_skip_prefix;
2120 
2121 /*
2122  * This is the nftw call-back function used by zonecfg_devwalk.  It is
2123  * responsible for calling the actual call-back that is passed in to
2124  * zonecfg_devwalk as the *cb argument.
2125  */
2126 /* ARGSUSED2 */
2127 static int
2128 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f,
2129     struct FTW *ftw)
2130 {
2131 	acl_t *acl;
2132 	char *acl_txt = NULL;
2133 
2134 	/* skip all but character and block devices */
2135 	if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
2136 		return (0);
2137 
2138 	if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) &&
2139 	    acl != NULL) {
2140 		acl_txt = acl_totext(acl, ACL_NORESOLVE);
2141 		acl_free(acl);
2142 	}
2143 
2144 	if (strlen(path) <= g_devwalk_skip_prefix)
2145 		return (0);
2146 
2147 	g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid,
2148 	    st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "",
2149 	    g_devwalk_data);
2150 	free(acl_txt);
2151 	return (0);
2152 }
2153 
2154 /*
2155  * Walk the dev tree for the zone specified by hdl and call the call-back (cb)
2156  * function for each entry in the tree.  The call-back will be passed the
2157  * name, uid, gid, mode, acl string and the void *data input parameter
2158  * for each dev entry.
2159  *
2160  * Data is passed to the zonecfg_devwalk_cb through the global variables
2161  * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix.  The
2162  * zonecfg_devwalk_cb function will actually call *cb.
2163  */
2164 int
2165 zonecfg_devwalk(zone_dochandle_t hdl,
2166     int (*cb)(const char *, uid_t, gid_t, mode_t, const char *, void *),
2167     void *data)
2168 {
2169 	char path[MAXPATHLEN];
2170 	int ret;
2171 
2172 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
2173 		return (ret);
2174 
2175 	if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path))
2176 		return (Z_TOO_BIG);
2177 	g_devwalk_skip_prefix = strlen(path) + 1;
2178 
2179 	/*
2180 	 * We have to serialize all zonecfg_devwalks in the same process
2181 	 * (which should be fine), since nftw() is so badly designed.
2182 	 */
2183 	(void) pthread_mutex_lock(&zonecfg_devwalk_lock);
2184 
2185 	g_devwalk_data = data;
2186 	g_devwalk_cb = cb;
2187 	(void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS);
2188 
2189 	(void) pthread_mutex_unlock(&zonecfg_devwalk_lock);
2190 	return (Z_OK);
2191 }
2192 
2193 /*
2194  * Update the owner, group, mode and acl on the specified dev (inpath) for
2195  * the zone (hdl).  This function can be used to fix up the dev tree after
2196  * attaching a migrated zone.
2197  */
2198 int
2199 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner,
2200     gid_t group, mode_t mode, const char *acltxt)
2201 {
2202 	int ret;
2203 	char path[MAXPATHLEN];
2204 	struct stat st;
2205 	acl_t *aclp;
2206 
2207 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
2208 		return (ret);
2209 
2210 	if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path))
2211 		return (Z_TOO_BIG);
2212 	if (strlcat(path, inpath, sizeof (path)) >= sizeof (path))
2213 		return (Z_TOO_BIG);
2214 
2215 	if (stat(path, &st) == -1)
2216 		return (Z_INVAL);
2217 
2218 	/* make sure we're only touching device nodes */
2219 	if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
2220 		return (Z_INVAL);
2221 
2222 	if (chown(path, owner, group) == -1)
2223 		return (Z_SYSTEM);
2224 
2225 	if (chmod(path, mode) == -1)
2226 		return (Z_SYSTEM);
2227 
2228 	if ((acltxt == NULL) || (strcmp(acltxt, "") == 0))
2229 		return (Z_OK);
2230 
2231 	if (acl_fromtext(acltxt, &aclp) != 0)
2232 		return (Z_SYSTEM);
2233 
2234 	errno = 0;
2235 	if (acl_set(path, aclp) == -1) {
2236 		free(aclp);
2237 		return (Z_SYSTEM);
2238 	}
2239 
2240 	free(aclp);
2241 	return (Z_OK);
2242 }
2243 
2244 /*
2245  * This is the set of devices which must be present in every zone.  Users
2246  * can augment this list with additional device rules in their zone
2247  * configuration, but at present cannot remove any of the this set of
2248  * standard devices.  All matching is done by /dev pathname (the "/dev"
2249  * part is implicit.  Try to keep rules which match a large number of
2250  * devices (like the pts rule) first.
2251  */
2252 static const char *standard_devs[] = {
2253 	"pts/*",
2254 	"ptmx",
2255 	"random",
2256 	"urandom",
2257 	"poll",
2258 	"pool",
2259 	"kstat",
2260 	"zero",
2261 	"null",
2262 	"crypto",
2263 	"cryptoadm",
2264 	"ticots",
2265 	"ticotsord",
2266 	"ticlts",
2267 	"lo0",
2268 	"lo1",
2269 	"lo2",
2270 	"lo3",
2271 	"sad/user",
2272 	"tty",
2273 	"logindmux",
2274 	"log",
2275 	"conslog",
2276 	"arp",
2277 	"tcp",
2278 	"tcp6",
2279 	"udp",
2280 	"udp6",
2281 	"sysevent",
2282 #ifdef __sparc
2283 	"openprom",
2284 #endif
2285 	"cpu/self/cpuid",
2286 	"dtrace/helper",
2287 	"zfs",
2288 	NULL
2289 };
2290 
2291 /*
2292  * This function finds everything mounted under a zone's rootpath.
2293  * This returns the number of mounts under rootpath, or -1 on error.
2294  * callback is called once per mount found with the first argument
2295  * pointing to the  mount point.
2296  *
2297  * If the callback function returns non-zero zonecfg_find_mounts
2298  * aborts with an error.
2299  */
2300 
2301 int
2302 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *),
2303     void *priv) {
2304 	FILE *mnttab;
2305 	struct mnttab m;
2306 	size_t l;
2307 	int zfsl;
2308 	int rv = 0;
2309 	char zfs_path[MAXPATHLEN];
2310 
2311 	assert(rootpath != NULL);
2312 
2313 	if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath))
2314 	    >= sizeof (zfs_path))
2315 		return (-1);
2316 
2317 	l = strlen(rootpath);
2318 
2319 	mnttab = fopen("/etc/mnttab", "r");
2320 
2321 	if (mnttab == NULL)
2322 		return (-1);
2323 
2324 	if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0)  {
2325 		rv = -1;
2326 		goto out;
2327 	}
2328 
2329 	while (!getmntent(mnttab, &m)) {
2330 		if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
2331 		    (m.mnt_mountp[l] == '/') &&
2332 		    (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) {
2333 			rv++;
2334 			if (callback == NULL)
2335 				continue;
2336 			if (callback(m.mnt_mountp, priv)) {
2337 				rv = -1;
2338 				goto out;
2339 
2340 			}
2341 		}
2342 	}
2343 
2344 out:
2345 	(void) fclose(mnttab);
2346 	return (rv);
2347 }
2348 
2349 /*
2350  * This routine is used to determine if a given device should appear in the
2351  * zone represented by 'handle'.  First it consults the list of "standard"
2352  * zone devices.  Then it scans the user-supplied device entries.
2353  */
2354 int
2355 zonecfg_match_dev(zone_dochandle_t handle, char *devpath,
2356     struct zone_devtab *out_match)
2357 {
2358 	int err;
2359 	boolean_t found = B_FALSE;
2360 	char match[MAXPATHLEN];
2361 	const char **stdmatch;
2362 	xmlNodePtr cur;
2363 
2364 	if (handle == NULL || devpath == NULL)
2365 		return (Z_INVAL);
2366 
2367 	/*
2368 	 * Check the "standard" devices which we require to be present.
2369 	 */
2370 	for (stdmatch = &standard_devs[0]; *stdmatch != NULL; stdmatch++) {
2371 		/*
2372 		 * fnmatch gives us simple but powerful shell-style matching.
2373 		 */
2374 		if (fnmatch(*stdmatch, devpath, FNM_PATHNAME) == 0) {
2375 			if (!out_match)
2376 				return (Z_OK);
2377 			(void) snprintf(out_match->zone_dev_match,
2378 			    sizeof (out_match->zone_dev_match),
2379 			    "/dev/%s", *stdmatch);
2380 			return (Z_OK);
2381 		}
2382 	}
2383 
2384 	/*
2385 	 * We got no hits in the set of standard devices.  On to the user
2386 	 * supplied ones.
2387 	 */
2388 	if ((err = operation_prep(handle)) != Z_OK) {
2389 		handle->zone_dh_cur = NULL;
2390 		return (err);
2391 	}
2392 
2393 	cur = handle->zone_dh_cur;
2394 	cur = cur->xmlChildrenNode;
2395 	if (cur == NULL)
2396 		return (Z_NO_ENTRY);
2397 	handle->zone_dh_cur = cur;
2398 
2399 	for (; cur != NULL; cur = cur->next) {
2400 		char *m;
2401 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE) != 0)
2402 			continue;
2403 		if ((err = fetchprop(cur, DTD_ATTR_MATCH, match,
2404 		    sizeof (match))) != Z_OK) {
2405 			handle->zone_dh_cur = handle->zone_dh_top;
2406 			return (err);
2407 		}
2408 		m = match;
2409 		/*
2410 		 * fnmatch gives us simple but powerful shell-style matching;
2411 		 * but first, we need to strip out /dev/ from the matching rule.
2412 		 */
2413 		if (strncmp(m, "/dev/", 5) == 0)
2414 			m += 5;
2415 
2416 		if (fnmatch(m, devpath, FNM_PATHNAME) == 0) {
2417 			found = B_TRUE;
2418 			break;
2419 		}
2420 	}
2421 
2422 	if (!found)
2423 		return (Z_NO_ENTRY);
2424 
2425 	if (!out_match)
2426 		return (Z_OK);
2427 
2428 	(void) strlcpy(out_match->zone_dev_match, match,
2429 	    sizeof (out_match->zone_dev_match));
2430 	return (Z_OK);
2431 }
2432 
2433 int
2434 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2435 {
2436 	xmlNodePtr cur, firstmatch;
2437 	int err;
2438 	char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
2439 
2440 	if (tabptr == NULL)
2441 		return (Z_INVAL);
2442 
2443 	if ((err = operation_prep(handle)) != Z_OK)
2444 		return (err);
2445 
2446 	cur = handle->zone_dh_cur;
2447 	firstmatch = NULL;
2448 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2449 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
2450 			continue;
2451 		if (strlen(tabptr->zone_attr_name) > 0) {
2452 			if ((fetchprop(cur, DTD_ATTR_NAME, name,
2453 			    sizeof (name)) == Z_OK) &&
2454 			    (strcmp(tabptr->zone_attr_name, name) == 0)) {
2455 				if (firstmatch == NULL)
2456 					firstmatch = cur;
2457 				else
2458 					return (Z_INSUFFICIENT_SPEC);
2459 			}
2460 		}
2461 		if (strlen(tabptr->zone_attr_type) > 0) {
2462 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
2463 			    sizeof (type)) == Z_OK)) {
2464 				if (strcmp(tabptr->zone_attr_type, type) == 0) {
2465 					if (firstmatch == NULL)
2466 						firstmatch = cur;
2467 					else if (firstmatch != cur)
2468 						return (Z_INSUFFICIENT_SPEC);
2469 				} else {
2470 					/*
2471 					 * If another property matched but this
2472 					 * one doesn't then reset firstmatch.
2473 					 */
2474 					if (firstmatch == cur)
2475 						firstmatch = NULL;
2476 				}
2477 			}
2478 		}
2479 		if (strlen(tabptr->zone_attr_value) > 0) {
2480 			if ((fetchprop(cur, DTD_ATTR_VALUE, value,
2481 			    sizeof (value)) == Z_OK)) {
2482 				if (strcmp(tabptr->zone_attr_value, value) ==
2483 				    0) {
2484 					if (firstmatch == NULL)
2485 						firstmatch = cur;
2486 					else if (firstmatch != cur)
2487 						return (Z_INSUFFICIENT_SPEC);
2488 				} else {
2489 					/*
2490 					 * If another property matched but this
2491 					 * one doesn't then reset firstmatch.
2492 					 */
2493 					if (firstmatch == cur)
2494 						firstmatch = NULL;
2495 				}
2496 			}
2497 		}
2498 	}
2499 	if (firstmatch == NULL)
2500 		return (Z_NO_RESOURCE_ID);
2501 
2502 	cur = firstmatch;
2503 
2504 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
2505 	    sizeof (tabptr->zone_attr_name))) != Z_OK)
2506 		return (err);
2507 
2508 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
2509 	    sizeof (tabptr->zone_attr_type))) != Z_OK)
2510 		return (err);
2511 
2512 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
2513 	    sizeof (tabptr->zone_attr_value))) != Z_OK)
2514 		return (err);
2515 
2516 	return (Z_OK);
2517 }
2518 
2519 static int
2520 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2521 {
2522 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2523 	int err;
2524 
2525 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
2526 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
2527 	if (err != Z_OK)
2528 		return (err);
2529 	err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
2530 	if (err != Z_OK)
2531 		return (err);
2532 	err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
2533 	if (err != Z_OK)
2534 		return (err);
2535 	return (Z_OK);
2536 }
2537 
2538 int
2539 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2540 {
2541 	int err;
2542 
2543 	if (tabptr == NULL)
2544 		return (Z_INVAL);
2545 
2546 	if ((err = operation_prep(handle)) != Z_OK)
2547 		return (err);
2548 
2549 	if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
2550 		return (err);
2551 
2552 	return (Z_OK);
2553 }
2554 
2555 static int
2556 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2557 {
2558 	xmlNodePtr cur = handle->zone_dh_cur;
2559 	int name_match, type_match, value_match;
2560 
2561 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2562 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
2563 			continue;
2564 
2565 		name_match = match_prop(cur, DTD_ATTR_NAME,
2566 		    tabptr->zone_attr_name);
2567 		type_match = match_prop(cur, DTD_ATTR_TYPE,
2568 		    tabptr->zone_attr_type);
2569 		value_match = match_prop(cur, DTD_ATTR_VALUE,
2570 		    tabptr->zone_attr_value);
2571 
2572 		if (name_match && type_match && value_match) {
2573 			xmlUnlinkNode(cur);
2574 			xmlFreeNode(cur);
2575 			return (Z_OK);
2576 		}
2577 	}
2578 	return (Z_NO_RESOURCE_ID);
2579 }
2580 
2581 int
2582 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2583 {
2584 	int err;
2585 
2586 	if (tabptr == NULL)
2587 		return (Z_INVAL);
2588 
2589 	if ((err = operation_prep(handle)) != Z_OK)
2590 		return (err);
2591 
2592 	if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
2593 		return (err);
2594 
2595 	return (Z_OK);
2596 }
2597 
2598 int
2599 zonecfg_modify_attr(
2600 	zone_dochandle_t handle,
2601 	struct zone_attrtab *oldtabptr,
2602 	struct zone_attrtab *newtabptr)
2603 {
2604 	int err;
2605 
2606 	if (oldtabptr == NULL || newtabptr == NULL)
2607 		return (Z_INVAL);
2608 
2609 	if ((err = operation_prep(handle)) != Z_OK)
2610 		return (err);
2611 
2612 	if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK)
2613 		return (err);
2614 
2615 	if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK)
2616 		return (err);
2617 
2618 	return (Z_OK);
2619 }
2620 
2621 int
2622 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value)
2623 {
2624 	if (attr == NULL)
2625 		return (Z_INVAL);
2626 
2627 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0)
2628 		return (Z_INVAL);
2629 
2630 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) {
2631 		*value = B_TRUE;
2632 		return (Z_OK);
2633 	}
2634 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) {
2635 		*value = B_FALSE;
2636 		return (Z_OK);
2637 	}
2638 	return (Z_INVAL);
2639 }
2640 
2641 int
2642 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value)
2643 {
2644 	long long result;
2645 	char *endptr;
2646 
2647 	if (attr == NULL)
2648 		return (Z_INVAL);
2649 
2650 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0)
2651 		return (Z_INVAL);
2652 
2653 	errno = 0;
2654 	result = strtoll(attr->zone_attr_value, &endptr, 10);
2655 	if (errno != 0 || *endptr != '\0')
2656 		return (Z_INVAL);
2657 	*value = result;
2658 	return (Z_OK);
2659 }
2660 
2661 int
2662 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value,
2663     size_t val_sz)
2664 {
2665 	if (attr == NULL)
2666 		return (Z_INVAL);
2667 
2668 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0)
2669 		return (Z_INVAL);
2670 
2671 	if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz)
2672 		return (Z_TOO_BIG);
2673 	return (Z_OK);
2674 }
2675 
2676 int
2677 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value)
2678 {
2679 	unsigned long long result;
2680 	long long neg_result;
2681 	char *endptr;
2682 
2683 	if (attr == NULL)
2684 		return (Z_INVAL);
2685 
2686 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0)
2687 		return (Z_INVAL);
2688 
2689 	errno = 0;
2690 	result = strtoull(attr->zone_attr_value, &endptr, 10);
2691 	if (errno != 0 || *endptr != '\0')
2692 		return (Z_INVAL);
2693 	errno = 0;
2694 	neg_result = strtoll(attr->zone_attr_value, &endptr, 10);
2695 	/*
2696 	 * Incredibly, strtoull("<negative number>", ...) will not fail but
2697 	 * return whatever (negative) number cast as a u_longlong_t, so we
2698 	 * need to look for this here.
2699 	 */
2700 	if (errno == 0 && neg_result < 0)
2701 		return (Z_INVAL);
2702 	*value = result;
2703 	return (Z_OK);
2704 }
2705 
2706 int
2707 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2708 {
2709 	xmlNodePtr cur, val;
2710 	char savedname[MAXNAMELEN];
2711 	struct zone_rctlvaltab *valptr;
2712 	int err;
2713 
2714 	if (tabptr->zone_rctl_name == NULL ||
2715 	    strlen(tabptr->zone_rctl_name) == 0)
2716 		return (Z_INVAL);
2717 
2718 	if ((err = operation_prep(handle)) != Z_OK)
2719 		return (err);
2720 
2721 	cur = handle->zone_dh_cur;
2722 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2723 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
2724 			continue;
2725 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
2726 		    sizeof (savedname)) == Z_OK) &&
2727 		    (strcmp(savedname, tabptr->zone_rctl_name) == 0)) {
2728 			tabptr->zone_rctl_valptr = NULL;
2729 			for (val = cur->xmlChildrenNode; val != NULL;
2730 			    val = val->next) {
2731 				valptr = (struct zone_rctlvaltab *)malloc(
2732 				    sizeof (struct zone_rctlvaltab));
2733 				if (valptr == NULL)
2734 					return (Z_NOMEM);
2735 				if ((fetchprop(val, DTD_ATTR_PRIV,
2736 				    valptr->zone_rctlval_priv,
2737 				    sizeof (valptr->zone_rctlval_priv)) !=
2738 				    Z_OK))
2739 					break;
2740 				if ((fetchprop(val, DTD_ATTR_LIMIT,
2741 				    valptr->zone_rctlval_limit,
2742 				    sizeof (valptr->zone_rctlval_limit)) !=
2743 				    Z_OK))
2744 					break;
2745 				if ((fetchprop(val, DTD_ATTR_ACTION,
2746 				    valptr->zone_rctlval_action,
2747 				    sizeof (valptr->zone_rctlval_action)) !=
2748 				    Z_OK))
2749 					break;
2750 				if (zonecfg_add_rctl_value(tabptr, valptr) !=
2751 				    Z_OK)
2752 					break;
2753 			}
2754 			return (Z_OK);
2755 		}
2756 	}
2757 	return (Z_NO_RESOURCE_ID);
2758 }
2759 
2760 static int
2761 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2762 {
2763 	xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
2764 	struct zone_rctlvaltab *valptr;
2765 	int err;
2766 
2767 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL);
2768 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name);
2769 	if (err != Z_OK)
2770 		return (err);
2771 	for (valptr = tabptr->zone_rctl_valptr; valptr != NULL;
2772 	    valptr = valptr->zone_rctlval_next) {
2773 		valnode = xmlNewTextChild(newnode, NULL,
2774 		    DTD_ELEM_RCTLVALUE, NULL);
2775 		err = newprop(valnode, DTD_ATTR_PRIV,
2776 		    valptr->zone_rctlval_priv);
2777 		if (err != Z_OK)
2778 			return (err);
2779 		err = newprop(valnode, DTD_ATTR_LIMIT,
2780 		    valptr->zone_rctlval_limit);
2781 		if (err != Z_OK)
2782 			return (err);
2783 		err = newprop(valnode, DTD_ATTR_ACTION,
2784 		    valptr->zone_rctlval_action);
2785 		if (err != Z_OK)
2786 			return (err);
2787 	}
2788 	return (Z_OK);
2789 }
2790 
2791 int
2792 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2793 {
2794 	int err;
2795 
2796 	if (tabptr == NULL || tabptr->zone_rctl_name == NULL)
2797 		return (Z_INVAL);
2798 
2799 	if ((err = operation_prep(handle)) != Z_OK)
2800 		return (err);
2801 
2802 	if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK)
2803 		return (err);
2804 
2805 	return (Z_OK);
2806 }
2807 
2808 static int
2809 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2810 {
2811 	xmlNodePtr cur = handle->zone_dh_cur;
2812 	xmlChar *savedname;
2813 	int name_result;
2814 
2815 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2816 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
2817 			continue;
2818 
2819 		savedname = xmlGetProp(cur, DTD_ATTR_NAME);
2820 		if (savedname == NULL)	/* shouldn't happen */
2821 			continue;
2822 		name_result = xmlStrcmp(savedname,
2823 		    (const xmlChar *) tabptr->zone_rctl_name);
2824 		xmlFree(savedname);
2825 
2826 		if (name_result == 0) {
2827 			xmlUnlinkNode(cur);
2828 			xmlFreeNode(cur);
2829 			return (Z_OK);
2830 		}
2831 	}
2832 	return (Z_NO_RESOURCE_ID);
2833 }
2834 
2835 int
2836 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2837 {
2838 	int err;
2839 
2840 	if (tabptr == NULL || tabptr->zone_rctl_name == NULL)
2841 		return (Z_INVAL);
2842 
2843 	if ((err = operation_prep(handle)) != Z_OK)
2844 		return (err);
2845 
2846 	if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK)
2847 		return (err);
2848 
2849 	return (Z_OK);
2850 }
2851 
2852 int
2853 zonecfg_modify_rctl(
2854 	zone_dochandle_t handle,
2855 	struct zone_rctltab *oldtabptr,
2856 	struct zone_rctltab *newtabptr)
2857 {
2858 	int err;
2859 
2860 	if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL ||
2861 	    newtabptr == NULL || newtabptr->zone_rctl_name == NULL)
2862 		return (Z_INVAL);
2863 
2864 	if ((err = operation_prep(handle)) != Z_OK)
2865 		return (err);
2866 
2867 	if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK)
2868 		return (err);
2869 
2870 	if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK)
2871 		return (err);
2872 
2873 	return (Z_OK);
2874 }
2875 
2876 int
2877 zonecfg_add_rctl_value(
2878 	struct zone_rctltab *tabptr,
2879 	struct zone_rctlvaltab *valtabptr)
2880 {
2881 	struct zone_rctlvaltab *last, *old, *new;
2882 	rctlblk_t *rctlblk = alloca(rctlblk_size());
2883 
2884 	last = tabptr->zone_rctl_valptr;
2885 	for (old = last; old != NULL; old = old->zone_rctlval_next)
2886 		last = old;	/* walk to the end of the list */
2887 	new = valtabptr;	/* alloc'd by caller */
2888 	new->zone_rctlval_next = NULL;
2889 	if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK)
2890 		return (Z_INVAL);
2891 	if (!zonecfg_valid_rctlblk(rctlblk))
2892 		return (Z_INVAL);
2893 	if (last == NULL)
2894 		tabptr->zone_rctl_valptr = new;
2895 	else
2896 		last->zone_rctlval_next = new;
2897 	return (Z_OK);
2898 }
2899 
2900 int
2901 zonecfg_remove_rctl_value(
2902 	struct zone_rctltab *tabptr,
2903 	struct zone_rctlvaltab *valtabptr)
2904 {
2905 	struct zone_rctlvaltab *last, *this, *next;
2906 
2907 	last = tabptr->zone_rctl_valptr;
2908 	for (this = last; this != NULL; this = this->zone_rctlval_next) {
2909 		if (strcmp(this->zone_rctlval_priv,
2910 		    valtabptr->zone_rctlval_priv) == 0 &&
2911 		    strcmp(this->zone_rctlval_limit,
2912 		    valtabptr->zone_rctlval_limit) == 0 &&
2913 		    strcmp(this->zone_rctlval_action,
2914 		    valtabptr->zone_rctlval_action) == 0) {
2915 			next = this->zone_rctlval_next;
2916 			if (this == tabptr->zone_rctl_valptr)
2917 				tabptr->zone_rctl_valptr = next;
2918 			else
2919 				last->zone_rctlval_next = next;
2920 			free(this);
2921 			return (Z_OK);
2922 		} else
2923 			last = this;
2924 	}
2925 	return (Z_NO_PROPERTY_ID);
2926 }
2927 
2928 char *
2929 zonecfg_strerror(int errnum)
2930 {
2931 	switch (errnum) {
2932 	case Z_OK:
2933 		return (dgettext(TEXT_DOMAIN, "OK"));
2934 	case Z_EMPTY_DOCUMENT:
2935 		return (dgettext(TEXT_DOMAIN, "Empty document"));
2936 	case Z_WRONG_DOC_TYPE:
2937 		return (dgettext(TEXT_DOMAIN, "Wrong document type"));
2938 	case Z_BAD_PROPERTY:
2939 		return (dgettext(TEXT_DOMAIN, "Bad document property"));
2940 	case Z_TEMP_FILE:
2941 		return (dgettext(TEXT_DOMAIN,
2942 		    "Problem creating temporary file"));
2943 	case Z_SAVING_FILE:
2944 		return (dgettext(TEXT_DOMAIN, "Problem saving file"));
2945 	case Z_NO_ENTRY:
2946 		return (dgettext(TEXT_DOMAIN, "No such entry"));
2947 	case Z_BOGUS_ZONE_NAME:
2948 		return (dgettext(TEXT_DOMAIN, "Bogus zone name"));
2949 	case Z_REQD_RESOURCE_MISSING:
2950 		return (dgettext(TEXT_DOMAIN, "Required resource missing"));
2951 	case Z_REQD_PROPERTY_MISSING:
2952 		return (dgettext(TEXT_DOMAIN, "Required property missing"));
2953 	case Z_BAD_HANDLE:
2954 		return (dgettext(TEXT_DOMAIN, "Bad handle"));
2955 	case Z_NOMEM:
2956 		return (dgettext(TEXT_DOMAIN, "Out of memory"));
2957 	case Z_INVAL:
2958 		return (dgettext(TEXT_DOMAIN, "Invalid argument"));
2959 	case Z_ACCES:
2960 		return (dgettext(TEXT_DOMAIN, "Permission denied"));
2961 	case Z_TOO_BIG:
2962 		return (dgettext(TEXT_DOMAIN, "Argument list too long"));
2963 	case Z_MISC_FS:
2964 		return (dgettext(TEXT_DOMAIN,
2965 		    "Miscellaneous file system error"));
2966 	case Z_NO_ZONE:
2967 		return (dgettext(TEXT_DOMAIN, "No such zone configured"));
2968 	case Z_NO_RESOURCE_TYPE:
2969 		return (dgettext(TEXT_DOMAIN, "No such resource type"));
2970 	case Z_NO_RESOURCE_ID:
2971 		return (dgettext(TEXT_DOMAIN, "No such resource with that id"));
2972 	case Z_NO_PROPERTY_TYPE:
2973 		return (dgettext(TEXT_DOMAIN, "No such property type"));
2974 	case Z_NO_PROPERTY_ID:
2975 		return (dgettext(TEXT_DOMAIN, "No such property with that id"));
2976 	case Z_BAD_ZONE_STATE:
2977 		return (dgettext(TEXT_DOMAIN,
2978 		    "Zone state is invalid for the requested operation"));
2979 	case Z_INVALID_DOCUMENT:
2980 		return (dgettext(TEXT_DOMAIN, "Invalid document"));
2981 	case Z_NAME_IN_USE:
2982 		return (dgettext(TEXT_DOMAIN, "Zone name already in use"));
2983 	case Z_NO_SUCH_ID:
2984 		return (dgettext(TEXT_DOMAIN, "No such zone ID"));
2985 	case Z_UPDATING_INDEX:
2986 		return (dgettext(TEXT_DOMAIN, "Problem updating index file"));
2987 	case Z_LOCKING_FILE:
2988 		return (dgettext(TEXT_DOMAIN, "Locking index file"));
2989 	case Z_UNLOCKING_FILE:
2990 		return (dgettext(TEXT_DOMAIN, "Unlocking index file"));
2991 	case Z_INSUFFICIENT_SPEC:
2992 		return (dgettext(TEXT_DOMAIN, "Insufficient specification"));
2993 	case Z_RESOLVED_PATH:
2994 		return (dgettext(TEXT_DOMAIN, "Resolved path mismatch"));
2995 	case Z_IPV6_ADDR_PREFIX_LEN:
2996 		return (dgettext(TEXT_DOMAIN,
2997 		    "IPv6 address missing required prefix length"));
2998 	case Z_BOGUS_ADDRESS:
2999 		return (dgettext(TEXT_DOMAIN,
3000 		    "Neither an IPv4 nor an IPv6 address nor a host name"));
3001 	case Z_PRIV_PROHIBITED:
3002 		return (dgettext(TEXT_DOMAIN,
3003 		    "Specified privilege is prohibited"));
3004 	case Z_PRIV_REQUIRED:
3005 		return (dgettext(TEXT_DOMAIN,
3006 		    "Required privilege is missing"));
3007 	case Z_PRIV_UNKNOWN:
3008 		return (dgettext(TEXT_DOMAIN,
3009 		    "Specified privilege is unknown"));
3010 	default:
3011 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
3012 	}
3013 }
3014 
3015 /*
3016  * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
3017  * same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
3018  */
3019 
3020 static int
3021 zonecfg_setent(zone_dochandle_t handle)
3022 {
3023 	xmlNodePtr cur;
3024 	int err;
3025 
3026 	if (handle == NULL)
3027 		return (Z_INVAL);
3028 
3029 	if ((err = operation_prep(handle)) != Z_OK) {
3030 		handle->zone_dh_cur = NULL;
3031 		return (err);
3032 	}
3033 	cur = handle->zone_dh_cur;
3034 	cur = cur->xmlChildrenNode;
3035 	handle->zone_dh_cur = cur;
3036 	return (Z_OK);
3037 }
3038 
3039 static int
3040 zonecfg_endent(zone_dochandle_t handle)
3041 {
3042 	if (handle == NULL)
3043 		return (Z_INVAL);
3044 
3045 	handle->zone_dh_cur = handle->zone_dh_top;
3046 	return (Z_OK);
3047 }
3048 
3049 int
3050 zonecfg_setfsent(zone_dochandle_t handle)
3051 {
3052 	return (zonecfg_setent(handle));
3053 }
3054 
3055 int
3056 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr)
3057 {
3058 	xmlNodePtr cur, options;
3059 	char options_str[MAX_MNTOPT_STR];
3060 	int err;
3061 
3062 	if (handle == NULL)
3063 		return (Z_INVAL);
3064 
3065 	if ((cur = handle->zone_dh_cur) == NULL)
3066 		return (Z_NO_ENTRY);
3067 
3068 	for (; cur != NULL; cur = cur->next)
3069 		if (!xmlStrcmp(cur->name, DTD_ELEM_FS))
3070 			break;
3071 	if (cur == NULL) {
3072 		handle->zone_dh_cur = handle->zone_dh_top;
3073 		return (Z_NO_ENTRY);
3074 	}
3075 
3076 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
3077 	    sizeof (tabptr->zone_fs_special))) != Z_OK) {
3078 		handle->zone_dh_cur = handle->zone_dh_top;
3079 		return (err);
3080 	}
3081 
3082 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
3083 	    sizeof (tabptr->zone_fs_raw))) != Z_OK) {
3084 		handle->zone_dh_cur = handle->zone_dh_top;
3085 		return (err);
3086 	}
3087 
3088 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
3089 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
3090 		handle->zone_dh_cur = handle->zone_dh_top;
3091 		return (err);
3092 	}
3093 
3094 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
3095 	    sizeof (tabptr->zone_fs_type))) != Z_OK) {
3096 		handle->zone_dh_cur = handle->zone_dh_top;
3097 		return (err);
3098 	}
3099 
3100 	/* OK for options to be NULL */
3101 	tabptr->zone_fs_options = NULL;
3102 	for (options = cur->xmlChildrenNode; options != NULL;
3103 	    options = options->next) {
3104 		if (fetchprop(options, DTD_ATTR_NAME, options_str,
3105 		    sizeof (options_str)) != Z_OK)
3106 			break;
3107 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
3108 			break;
3109 	}
3110 
3111 	handle->zone_dh_cur = cur->next;
3112 	return (Z_OK);
3113 }
3114 
3115 int
3116 zonecfg_endfsent(zone_dochandle_t handle)
3117 {
3118 	return (zonecfg_endent(handle));
3119 }
3120 
3121 int
3122 zonecfg_setipdent(zone_dochandle_t handle)
3123 {
3124 	return (zonecfg_setent(handle));
3125 }
3126 
3127 int
3128 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr)
3129 {
3130 	xmlNodePtr cur;
3131 	int err;
3132 
3133 	if (handle == NULL)
3134 		return (Z_INVAL);
3135 
3136 	if ((cur = handle->zone_dh_cur) == NULL)
3137 		return (Z_NO_ENTRY);
3138 
3139 	for (; cur != NULL; cur = cur->next)
3140 		if (!xmlStrcmp(cur->name, DTD_ELEM_IPD))
3141 			break;
3142 	if (cur == NULL) {
3143 		handle->zone_dh_cur = handle->zone_dh_top;
3144 		return (Z_NO_ENTRY);
3145 	}
3146 
3147 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
3148 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
3149 		handle->zone_dh_cur = handle->zone_dh_top;
3150 		return (err);
3151 	}
3152 
3153 	handle->zone_dh_cur = cur->next;
3154 	return (Z_OK);
3155 }
3156 
3157 int
3158 zonecfg_endipdent(zone_dochandle_t handle)
3159 {
3160 	return (zonecfg_endent(handle));
3161 }
3162 
3163 int
3164 zonecfg_setnwifent(zone_dochandle_t handle)
3165 {
3166 	return (zonecfg_setent(handle));
3167 }
3168 
3169 int
3170 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
3171 {
3172 	xmlNodePtr cur;
3173 	int err;
3174 
3175 	if (handle == NULL)
3176 		return (Z_INVAL);
3177 
3178 	if ((cur = handle->zone_dh_cur) == NULL)
3179 		return (Z_NO_ENTRY);
3180 
3181 	for (; cur != NULL; cur = cur->next)
3182 		if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
3183 			break;
3184 	if (cur == NULL) {
3185 		handle->zone_dh_cur = handle->zone_dh_top;
3186 		return (Z_NO_ENTRY);
3187 	}
3188 
3189 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
3190 	    sizeof (tabptr->zone_nwif_address))) != Z_OK) {
3191 		handle->zone_dh_cur = handle->zone_dh_top;
3192 		return (err);
3193 	}
3194 
3195 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
3196 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
3197 		handle->zone_dh_cur = handle->zone_dh_top;
3198 		return (err);
3199 	}
3200 
3201 	handle->zone_dh_cur = cur->next;
3202 	return (Z_OK);
3203 }
3204 
3205 int
3206 zonecfg_endnwifent(zone_dochandle_t handle)
3207 {
3208 	return (zonecfg_endent(handle));
3209 }
3210 
3211 int
3212 zonecfg_setdevent(zone_dochandle_t handle)
3213 {
3214 	return (zonecfg_setent(handle));
3215 }
3216 
3217 int
3218 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
3219 {
3220 	xmlNodePtr cur;
3221 	int err;
3222 
3223 	if (handle == NULL)
3224 		return (Z_INVAL);
3225 
3226 	if ((cur = handle->zone_dh_cur) == NULL)
3227 		return (Z_NO_ENTRY);
3228 
3229 	for (; cur != NULL; cur = cur->next)
3230 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
3231 			break;
3232 	if (cur == NULL) {
3233 		handle->zone_dh_cur = handle->zone_dh_top;
3234 		return (Z_NO_ENTRY);
3235 	}
3236 
3237 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
3238 	    sizeof (tabptr->zone_dev_match))) != Z_OK) {
3239 		handle->zone_dh_cur = handle->zone_dh_top;
3240 		return (err);
3241 	}
3242 
3243 	handle->zone_dh_cur = cur->next;
3244 	return (Z_OK);
3245 }
3246 
3247 int
3248 zonecfg_enddevent(zone_dochandle_t handle)
3249 {
3250 	return (zonecfg_endent(handle));
3251 }
3252 
3253 int
3254 zonecfg_setrctlent(zone_dochandle_t handle)
3255 {
3256 	return (zonecfg_setent(handle));
3257 }
3258 
3259 int
3260 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3261 {
3262 	xmlNodePtr cur, val;
3263 	struct zone_rctlvaltab *valptr;
3264 	int err;
3265 
3266 	if (handle == NULL)
3267 		return (Z_INVAL);
3268 
3269 	if ((cur = handle->zone_dh_cur) == NULL)
3270 		return (Z_NO_ENTRY);
3271 
3272 	for (; cur != NULL; cur = cur->next)
3273 		if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL))
3274 			break;
3275 	if (cur == NULL) {
3276 		handle->zone_dh_cur = handle->zone_dh_top;
3277 		return (Z_NO_ENTRY);
3278 	}
3279 
3280 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name,
3281 	    sizeof (tabptr->zone_rctl_name))) != Z_OK) {
3282 		handle->zone_dh_cur = handle->zone_dh_top;
3283 		return (err);
3284 	}
3285 
3286 	tabptr->zone_rctl_valptr = NULL;
3287 	for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
3288 		valptr = (struct zone_rctlvaltab *)malloc(
3289 		    sizeof (struct zone_rctlvaltab));
3290 		if (valptr == NULL)
3291 			return (Z_NOMEM);
3292 		if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv,
3293 		    sizeof (valptr->zone_rctlval_priv)) != Z_OK)
3294 			break;
3295 		if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit,
3296 		    sizeof (valptr->zone_rctlval_limit)) != Z_OK)
3297 			break;
3298 		if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action,
3299 		    sizeof (valptr->zone_rctlval_action)) != Z_OK)
3300 			break;
3301 		if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK)
3302 			break;
3303 	}
3304 
3305 	handle->zone_dh_cur = cur->next;
3306 	return (Z_OK);
3307 }
3308 
3309 int
3310 zonecfg_endrctlent(zone_dochandle_t handle)
3311 {
3312 	return (zonecfg_endent(handle));
3313 }
3314 
3315 int
3316 zonecfg_setattrent(zone_dochandle_t handle)
3317 {
3318 	return (zonecfg_setent(handle));
3319 }
3320 
3321 int
3322 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3323 {
3324 	xmlNodePtr cur;
3325 	int err;
3326 
3327 	if (handle == NULL)
3328 		return (Z_INVAL);
3329 
3330 	if ((cur = handle->zone_dh_cur) == NULL)
3331 		return (Z_NO_ENTRY);
3332 
3333 	for (; cur != NULL; cur = cur->next)
3334 		if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3335 			break;
3336 	if (cur == NULL) {
3337 		handle->zone_dh_cur = handle->zone_dh_top;
3338 		return (Z_NO_ENTRY);
3339 	}
3340 
3341 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
3342 	    sizeof (tabptr->zone_attr_name))) != Z_OK) {
3343 		handle->zone_dh_cur = handle->zone_dh_top;
3344 		return (err);
3345 	}
3346 
3347 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
3348 	    sizeof (tabptr->zone_attr_type))) != Z_OK) {
3349 		handle->zone_dh_cur = handle->zone_dh_top;
3350 		return (err);
3351 	}
3352 
3353 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
3354 	    sizeof (tabptr->zone_attr_value))) != Z_OK) {
3355 		handle->zone_dh_cur = handle->zone_dh_top;
3356 		return (err);
3357 	}
3358 
3359 	handle->zone_dh_cur = cur->next;
3360 	return (Z_OK);
3361 }
3362 
3363 int
3364 zonecfg_endattrent(zone_dochandle_t handle)
3365 {
3366 	return (zonecfg_endent(handle));
3367 }
3368 
3369 /*
3370  * The privileges available on the system and described in privileges(5)
3371  * fall into four categories with respect to non-global zones; those that
3372  * are required in order for a non-global zone to boot, those which are in
3373  * the default set of privileges available to non-global zones, those
3374  * privileges which should not be allowed to be given to non-global zones
3375  * and all other privileges, which are optional and potentially useful for
3376  * processes executing inside a non-global zone.
3377  *
3378  * When privileges are added to the system, a determination needs to be
3379  * made as to which category the privilege belongs to.  Ideally,
3380  * privileges should be fine-grained enough and the mechanisms they cover
3381  * virtualized enough so that they can be made available to non-global
3382  * zones.
3383  */
3384 
3385 /*
3386  * Set of privileges required in order to get a zone booted and init(1M)
3387  * started.  These cannot be removed from the zone's privilege set.
3388  */
3389 static const char *required_priv_list[] = {
3390 	PRIV_PROC_EXEC,
3391 	PRIV_PROC_FORK,
3392 	PRIV_SYS_MOUNT,
3393 	NULL
3394 };
3395 
3396 /*
3397  * Default set of privileges considered safe for all non-global zones.
3398  * These privileges are "safe" in the sense that a privileged process in
3399  * the zone cannot affect processes in other non-global zones on the
3400  * system or in the global zone.  Privileges which are considered by
3401  * default, "unsafe", include ones which affect a global resource, such as
3402  * the system clock or physical memory.
3403  */
3404 static const char *default_priv_list[] = {
3405 	PRIV_CONTRACT_EVENT,
3406 	PRIV_CONTRACT_OBSERVER,
3407 	PRIV_FILE_CHOWN,
3408 	PRIV_FILE_CHOWN_SELF,
3409 	PRIV_FILE_DAC_EXECUTE,
3410 	PRIV_FILE_DAC_READ,
3411 	PRIV_FILE_DAC_SEARCH,
3412 	PRIV_FILE_DAC_WRITE,
3413 	PRIV_FILE_OWNER,
3414 	PRIV_FILE_SETID,
3415 	PRIV_IPC_DAC_READ,
3416 	PRIV_IPC_DAC_WRITE,
3417 	PRIV_IPC_OWNER,
3418 	PRIV_NET_BINDMLP,
3419 	PRIV_NET_ICMPACCESS,
3420 	PRIV_NET_MAC_AWARE,
3421 	PRIV_NET_PRIVADDR,
3422 	PRIV_PROC_CHROOT,
3423 	PRIV_SYS_AUDIT,
3424 	PRIV_PROC_AUDIT,
3425 	PRIV_PROC_OWNER,
3426 	PRIV_PROC_SETID,
3427 	PRIV_PROC_TASKID,
3428 	PRIV_SYS_ACCT,
3429 	PRIV_SYS_ADMIN,
3430 	PRIV_SYS_MOUNT,
3431 	PRIV_SYS_NFS,
3432 	PRIV_SYS_RESOURCE,
3433 	NULL
3434 };
3435 
3436 /*
3437  * Set of privileges not currently permitted within a non-global zone.
3438  * Some of these privileges are overly broad and cover more than one
3439  * mechanism in the system.  In other cases, there has not been sufficient
3440  * virtualization in the parts of the system the privilege covers to allow
3441  * its use within a non-global zone.
3442  */
3443 static const char *prohibited_priv_list[] = {
3444 	PRIV_DTRACE_KERNEL,
3445 	PRIV_PROC_ZONE,
3446 	PRIV_SYS_CONFIG,
3447 	PRIV_SYS_DEVICES,
3448 	PRIV_SYS_LINKDIR,
3449 	PRIV_SYS_NET_CONFIG,
3450 	PRIV_SYS_RES_CONFIG,
3451 	PRIV_SYS_SUSER_COMPAT,
3452 	NULL
3453 };
3454 
3455 /*
3456  * Define some of the tokens that priv_str_to_set(3C) recognizes.  Since
3457  * the privilege string separator can be any character, although it is
3458  * usually a comma character, define these here as well in the event that
3459  * they change or are augmented in the future.
3460  */
3461 #define	BASIC_TOKEN		"basic"
3462 #define	DEFAULT_TOKEN		"default"
3463 #define	ZONE_TOKEN		"zone"
3464 #define	TOKEN_PRIV_CHAR		','
3465 #define	TOKEN_PRIV_STR		","
3466 
3467 int
3468 zonecfg_default_privset(priv_set_t *privs)
3469 {
3470 	const char **strp;
3471 	priv_set_t *basic;
3472 
3473 	basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL);
3474 	if (basic == NULL)
3475 		return (errno == ENOMEM ? Z_NOMEM : Z_INVAL);
3476 
3477 	priv_union(basic, privs);
3478 	priv_freeset(basic);
3479 
3480 	for (strp = default_priv_list; *strp != NULL; strp++) {
3481 		if (priv_addset(privs, *strp) != 0) {
3482 			return (Z_INVAL);
3483 		}
3484 	}
3485 	return (Z_OK);
3486 }
3487 
3488 void
3489 append_priv_token(char *priv, char *str, size_t strlen)
3490 {
3491 	if (*str != '\0')
3492 		(void) strlcat(str, TOKEN_PRIV_STR, strlen);
3493 	(void) strlcat(str, priv, strlen);
3494 }
3495 
3496 /*
3497  * Verify that the supplied string is a valid privilege limit set for a
3498  * non-global zone.  This string must not only be acceptable to
3499  * priv_str_to_set(3C) which parses it, but it also must resolve to a
3500  * privilege set that includes certain required privileges and lacks
3501  * certain prohibited privileges.
3502  */
3503 static int
3504 verify_privset(char *privbuf, priv_set_t *privs, char **privname,
3505     boolean_t add_default)
3506 {
3507 	char *cp;
3508 	char *lasts;
3509 	size_t len;
3510 	priv_set_t *mergeset;
3511 	const char **strp;
3512 	char *tmp;
3513 	const char *token;
3514 
3515 	/*
3516 	 * The verification of the privilege string occurs in several
3517 	 * phases.  In the first phase, the supplied string is scanned for
3518 	 * the ZONE_TOKEN token which is not support as part of the
3519 	 * "limitpriv" property.
3520 	 *
3521 	 * Duplicate the supplied privilege string since strtok_r(3C)
3522 	 * tokenizes its input by null-terminating the tokens.
3523 	 */
3524 	if ((tmp = strdup(privbuf)) == NULL)
3525 		return (Z_NOMEM);
3526 	for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL;
3527 	    cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) {
3528 		if (strcmp(cp, ZONE_TOKEN) == 0) {
3529 			free(tmp);
3530 			if ((*privname = strdup(ZONE_TOKEN)) == NULL)
3531 				return (Z_NOMEM);
3532 			else
3533 				return (Z_PRIV_UNKNOWN);
3534 		}
3535 	}
3536 	free(tmp);
3537 
3538 	if (add_default) {
3539 		/*
3540 		 * If DEFAULT_TOKEN was specified, a string needs to be
3541 		 * built containing the privileges from the default, safe
3542 		 * set along with those of the "limitpriv" property.
3543 		 */
3544 		len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2;
3545 		for (strp = default_priv_list; *strp != NULL; strp++)
3546 			len += strlen(*strp) + 1;
3547 		tmp = alloca(len);
3548 		*tmp = '\0';
3549 
3550 		append_priv_token(BASIC_TOKEN, tmp, len);
3551 		for (strp = default_priv_list; *strp != NULL; strp++)
3552 			append_priv_token((char *)*strp, tmp, len);
3553 		(void) strlcat(tmp, TOKEN_PRIV_STR, len);
3554 		(void) strlcat(tmp, privbuf, len);
3555 	} else {
3556 		tmp = privbuf;
3557 	}
3558 
3559 
3560 	/*
3561 	 * In the next phase, attempt to convert the merged privilege
3562 	 * string into a privilege set.  In the case of an error, either
3563 	 * there was a memory allocation failure or there was an invalid
3564 	 * privilege token in the string.  In either case, return an
3565 	 * appropriate error code but in the event of an invalid token,
3566 	 * allocate a string containing its name and return that back to
3567 	 * the caller.
3568 	 */
3569 	mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token);
3570 	if (mergeset == NULL) {
3571 		if (token == NULL)
3572 			return (Z_NOMEM);
3573 		if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL)
3574 			*cp = '\0';
3575 		if ((*privname = strdup(token)) == NULL)
3576 			return (Z_NOMEM);
3577 		else
3578 			return (Z_PRIV_UNKNOWN);
3579 	}
3580 
3581 	/*
3582 	 * Next, verify that none of the prohibited zone privileges are
3583 	 * present in the merged privilege set.
3584 	 */
3585 	for (strp = prohibited_priv_list; *strp != NULL; strp++) {
3586 		if (priv_ismember(mergeset, *strp)) {
3587 			priv_freeset(mergeset);
3588 			if ((*privname = strdup(*strp)) == NULL)
3589 				return (Z_NOMEM);
3590 			else
3591 				return (Z_PRIV_PROHIBITED);
3592 		}
3593 	}
3594 
3595 	/*
3596 	 * Finally, verify that all of the required zone privileges are
3597 	 * present in the merged privilege set.
3598 	 */
3599 	for (strp = required_priv_list; *strp != NULL; strp++) {
3600 		if (!priv_ismember(mergeset, *strp)) {
3601 			priv_freeset(mergeset);
3602 			if ((*privname = strdup(*strp)) == NULL)
3603 				return (Z_NOMEM);
3604 			else
3605 				return (Z_PRIV_REQUIRED);
3606 		}
3607 	}
3608 
3609 	priv_copyset(mergeset, privs);
3610 	priv_freeset(mergeset);
3611 	return (Z_OK);
3612 }
3613 
3614 /*
3615  * Fill in the supplied privilege set with either the default, safe set of
3616  * privileges suitable for a non-global zone, or one based on the
3617  * "limitpriv" property in the zone's configuration.
3618  *
3619  * In the event of an invalid privilege specification in the
3620  * configuration, a string is allocated and returned containing the
3621  * "privilege" causing the issue.  It is the caller's responsibility to
3622  * free this memory when it is done with it.
3623  */
3624 int
3625 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs,
3626     char **privname)
3627 {
3628 	char *cp;
3629 	int err;
3630 	int limitlen;
3631 	char *limitpriv = NULL;
3632 
3633 	/*
3634 	 * Attempt to lookup the "limitpriv" property.  If it does not
3635 	 * exist or matches the string DEFAULT_TOKEN exactly, then the
3636 	 * default, safe privilege set is returned.
3637 	 */
3638 	err = zonecfg_get_limitpriv(handle, &limitpriv);
3639 	if (err != Z_OK)
3640 		return (err);
3641 	limitlen = strlen(limitpriv);
3642 	if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) {
3643 		free(limitpriv);
3644 		return (zonecfg_default_privset(privs));
3645 	}
3646 
3647 	/*
3648 	 * Check if the string DEFAULT_TOKEN is the first token in a list
3649 	 * of privileges.
3650 	 */
3651 	cp = strchr(limitpriv, TOKEN_PRIV_CHAR);
3652 	if (cp != NULL &&
3653 	    strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0)
3654 		err = verify_privset(cp + 1, privs, privname, B_TRUE);
3655 	else
3656 		err = verify_privset(limitpriv, privs, privname, B_FALSE);
3657 
3658 	free(limitpriv);
3659 	return (err);
3660 }
3661 
3662 int
3663 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
3664 {
3665 	zone_dochandle_t handle;
3666 	boolean_t found = B_FALSE;
3667 	struct zoneent *ze;
3668 	FILE *cookie;
3669 	int err;
3670 	char *cp;
3671 
3672 	if (zone_name == NULL)
3673 		return (Z_INVAL);
3674 
3675 	(void) strlcpy(zonepath, zonecfg_root, rp_sz);
3676 	cp = zonepath + strlen(zonepath);
3677 	while (cp > zonepath && cp[-1] == '/')
3678 		*--cp = '\0';
3679 
3680 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
3681 		if (zonepath[0] == '\0')
3682 			(void) strlcpy(zonepath, "/", rp_sz);
3683 		return (Z_OK);
3684 	}
3685 
3686 	/*
3687 	 * First check the index file.  Because older versions did not have
3688 	 * a copy of the zone path, allow for it to be zero length, in which
3689 	 * case we ignore this result and fall back to the XML files.
3690 	 */
3691 	cookie = setzoneent();
3692 	while ((ze = getzoneent_private(cookie)) != NULL) {
3693 		if (strcmp(ze->zone_name, zone_name) == 0) {
3694 			found = B_TRUE;
3695 			if (ze->zone_path[0] != '\0')
3696 				(void) strlcpy(cp, ze->zone_path,
3697 				    rp_sz - (cp - zonepath));
3698 		}
3699 		free(ze);
3700 		if (found)
3701 			break;
3702 	}
3703 	endzoneent(cookie);
3704 	if (found && *cp != '\0')
3705 		return (Z_OK);
3706 
3707 	/* Fall back to the XML files. */
3708 	if ((handle = zonecfg_init_handle()) == NULL)
3709 		return (Z_NOMEM);
3710 
3711 	/*
3712 	 * Check the snapshot first: if a zone is running, its zonepath
3713 	 * may have changed.
3714 	 */
3715 	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
3716 		if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK)
3717 			return (err);
3718 	}
3719 	err = zonecfg_get_zonepath(handle, zonepath, rp_sz);
3720 	zonecfg_fini_handle(handle);
3721 	return (err);
3722 }
3723 
3724 int
3725 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz)
3726 {
3727 	int err;
3728 
3729 	/* This function makes sense for non-global zones only. */
3730 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
3731 		return (Z_BOGUS_ZONE_NAME);
3732 	if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK)
3733 		return (err);
3734 	if (strlcat(rootpath, "/root", rp_sz) >= rp_sz)
3735 		return (Z_TOO_BIG);
3736 	return (Z_OK);
3737 }
3738 
3739 static zone_state_t
3740 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state)
3741 {
3742 	char zoneroot[MAXPATHLEN];
3743 	size_t zlen;
3744 
3745 	assert(kernel_state <= ZONE_MAX_STATE);
3746 	switch (kernel_state) {
3747 		case ZONE_IS_UNINITIALIZED:
3748 			return (ZONE_STATE_READY);
3749 		case ZONE_IS_READY:
3750 			/*
3751 			 * If the zone's root is mounted on $ZONEPATH/lu, then
3752 			 * it's a mounted scratch zone.
3753 			 */
3754 			if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
3755 			    sizeof (zoneroot)) >= 0) {
3756 				zlen = strlen(zoneroot);
3757 				if (zlen > 3 &&
3758 				    strcmp(zoneroot + zlen - 3, "/lu") == 0)
3759 					return (ZONE_STATE_MOUNTED);
3760 			}
3761 			return (ZONE_STATE_READY);
3762 		case ZONE_IS_BOOTING:
3763 		case ZONE_IS_RUNNING:
3764 			return (ZONE_STATE_RUNNING);
3765 		case ZONE_IS_SHUTTING_DOWN:
3766 		case ZONE_IS_EMPTY:
3767 			return (ZONE_STATE_SHUTTING_DOWN);
3768 		case ZONE_IS_DOWN:
3769 		case ZONE_IS_DYING:
3770 		case ZONE_IS_DEAD:
3771 		default:
3772 			return (ZONE_STATE_DOWN);
3773 	}
3774 	/* NOTREACHED */
3775 }
3776 
3777 int
3778 zone_get_state(char *zone_name, zone_state_t *state_num)
3779 {
3780 	zone_status_t status;
3781 	zoneid_t zone_id;
3782 	struct zoneent *ze;
3783 	boolean_t found = B_FALSE;
3784 	FILE *cookie;
3785 	char kernzone[ZONENAME_MAX];
3786 	FILE *fp;
3787 
3788 	if (zone_name == NULL)
3789 		return (Z_INVAL);
3790 
3791 	/*
3792 	 * If we're looking at an alternate root, then we need to query the
3793 	 * kernel using the scratch zone name.
3794 	 */
3795 	zone_id = -1;
3796 	if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
3797 		if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
3798 			if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
3799 			    kernzone, sizeof (kernzone)) == 0)
3800 				zone_id = getzoneidbyname(kernzone);
3801 			zonecfg_close_scratch(fp);
3802 		}
3803 	} else {
3804 		zone_id = getzoneidbyname(zone_name);
3805 	}
3806 
3807 	/* check to see if zone is running */
3808 	if (zone_id != -1 &&
3809 	    zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
3810 	    sizeof (status)) >= 0) {
3811 		*state_num = kernel_state_to_user_state(zone_id, status);
3812 		return (Z_OK);
3813 	}
3814 
3815 	cookie = setzoneent();
3816 	while ((ze = getzoneent_private(cookie)) != NULL) {
3817 		if (strcmp(ze->zone_name, zone_name) == 0) {
3818 			found = B_TRUE;
3819 			*state_num = ze->zone_state;
3820 		}
3821 		free(ze);
3822 		if (found)
3823 			break;
3824 	}
3825 	endzoneent(cookie);
3826 	return ((found) ? Z_OK : Z_NO_ZONE);
3827 }
3828 
3829 int
3830 zone_set_state(char *zone, zone_state_t state)
3831 {
3832 	struct zoneent ze;
3833 
3834 	if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
3835 	    state != ZONE_STATE_INCOMPLETE)
3836 		return (Z_INVAL);
3837 
3838 	bzero(&ze, sizeof (ze));
3839 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
3840 	ze.zone_state = state;
3841 	(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
3842 	return (putzoneent(&ze, PZE_MODIFY));
3843 }
3844 
3845 /*
3846  * Get id (if any) for specified zone.  There are four possible outcomes:
3847  * - If the string corresponds to the numeric id of an active (booted)
3848  *   zone, sets *zip to the zone id and returns 0.
3849  * - If the string corresponds to the name of an active (booted) zone,
3850  *   sets *zip to the zone id and returns 0.
3851  * - If the string is a name in the configuration but is not booted,
3852  *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
3853  * - Otherwise, leaves *zip unchanged and returns -1.
3854  *
3855  * This function acts as an auxiliary filter on the function of the same
3856  * name in libc; the linker binds to this version if libzonecfg exists,
3857  * and the libc version if it doesn't.  Any changes to this version of
3858  * the function should probably be reflected in the libc version as well.
3859  */
3860 int
3861 zone_get_id(const char *str, zoneid_t *zip)
3862 {
3863 	zone_dochandle_t hdl;
3864 	zoneid_t zoneid;
3865 	char *cp;
3866 	int err;
3867 
3868 	/* first try looking for active zone by id */
3869 	errno = 0;
3870 	zoneid = (zoneid_t)strtol(str, &cp, 0);
3871 	if (errno == 0 && cp != str && *cp == '\0' &&
3872 	    getzonenamebyid(zoneid, NULL, 0) != -1) {
3873 		*zip = zoneid;
3874 		return (0);
3875 	}
3876 
3877 	/* then look for active zone by name */
3878 	if ((zoneid = getzoneidbyname(str)) != -1) {
3879 		*zip = zoneid;
3880 		return (0);
3881 	}
3882 
3883 	/* if in global zone, try looking up name in configuration database */
3884 	if (getzoneid() != GLOBAL_ZONEID ||
3885 	    (hdl = zonecfg_init_handle()) == NULL)
3886 		return (-1);
3887 
3888 	if (zonecfg_get_handle(str, hdl) == Z_OK) {
3889 		/* zone exists but isn't active */
3890 		*zip = ZONE_ID_UNDEFINED;
3891 		err = 0;
3892 	} else {
3893 		err = -1;
3894 	}
3895 
3896 	zonecfg_fini_handle(hdl);
3897 	return (err);
3898 }
3899 
3900 char *
3901 zone_state_str(zone_state_t state_num)
3902 {
3903 	switch (state_num) {
3904 	case ZONE_STATE_CONFIGURED:
3905 		return (ZONE_STATE_STR_CONFIGURED);
3906 	case ZONE_STATE_INCOMPLETE:
3907 		return (ZONE_STATE_STR_INCOMPLETE);
3908 	case ZONE_STATE_INSTALLED:
3909 		return (ZONE_STATE_STR_INSTALLED);
3910 	case ZONE_STATE_READY:
3911 		return (ZONE_STATE_STR_READY);
3912 	case ZONE_STATE_MOUNTED:
3913 		return (ZONE_STATE_STR_MOUNTED);
3914 	case ZONE_STATE_RUNNING:
3915 		return (ZONE_STATE_STR_RUNNING);
3916 	case ZONE_STATE_SHUTTING_DOWN:
3917 		return (ZONE_STATE_STR_SHUTTING_DOWN);
3918 	case ZONE_STATE_DOWN:
3919 		return (ZONE_STATE_STR_DOWN);
3920 	default:
3921 		return ("unknown");
3922 	}
3923 }
3924 
3925 /*
3926  * Given a UUID value, find an associated zone name.  This is intended to be
3927  * used by callers who set up some 'default' name (corresponding to the
3928  * expected name for the zone) in the zonename buffer, and thus the function
3929  * doesn't touch this buffer on failure.
3930  */
3931 int
3932 zonecfg_get_name_by_uuid(const uuid_t uuid, char *zonename, size_t namelen)
3933 {
3934 	FILE *fp;
3935 	struct zoneent *ze;
3936 
3937 	/*
3938 	 * A small amount of subterfuge via casts is necessary here because
3939 	 * libuuid doesn't use const correctly, but we don't want to export
3940 	 * this brokenness to our clients.
3941 	 */
3942 	if (uuid_is_null(*(uuid_t *)&uuid))
3943 		return (Z_NO_ZONE);
3944 	if ((fp = setzoneent()) == NULL)
3945 		return (Z_NO_ZONE);
3946 	while ((ze = getzoneent_private(fp)) != NULL) {
3947 		if (uuid_compare(*(uuid_t *)&uuid, ze->zone_uuid) == 0)
3948 			break;
3949 		free(ze);
3950 	}
3951 	endzoneent(fp);
3952 	if (ze != NULL) {
3953 		(void) strlcpy(zonename, ze->zone_name, namelen);
3954 		free(ze);
3955 		return (Z_OK);
3956 	} else {
3957 		return (Z_NO_ZONE);
3958 	}
3959 }
3960 
3961 /*
3962  * Given a zone name, get its UUID.  Returns a "NULL" UUID value if the zone
3963  * exists but the file doesn't have a value set yet.  Returns an error if the
3964  * zone cannot be located.
3965  */
3966 int
3967 zonecfg_get_uuid(const char *zonename, uuid_t uuid)
3968 {
3969 	FILE *fp;
3970 	struct zoneent *ze;
3971 
3972 	if ((fp = setzoneent()) == NULL)
3973 		return (Z_NO_ZONE);
3974 	while ((ze = getzoneent_private(fp)) != NULL) {
3975 		if (strcmp(ze->zone_name, zonename) == 0)
3976 			break;
3977 		free(ze);
3978 	}
3979 	endzoneent(fp);
3980 	if (ze != NULL) {
3981 		uuid_copy(uuid, ze->zone_uuid);
3982 		free(ze);
3983 		return (Z_OK);
3984 	} else {
3985 		return (Z_NO_ZONE);
3986 	}
3987 }
3988 
3989 /*
3990  * File-system convenience functions.
3991  */
3992 boolean_t
3993 zonecfg_valid_fs_type(const char *type)
3994 {
3995 	/*
3996 	 * We already know which FS types don't work.
3997 	 */
3998 	if (strcmp(type, "proc") == 0 ||
3999 	    strcmp(type, "mntfs") == 0 ||
4000 	    strcmp(type, "autofs") == 0 ||
4001 	    strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 ||
4002 	    strcmp(type, "cachefs") == 0)
4003 		return (B_FALSE);
4004 	/*
4005 	 * The caller may do more detailed verification to make sure other
4006 	 * aspects of this filesystem type make sense.
4007 	 */
4008 	return (B_TRUE);
4009 }
4010 
4011 /*
4012  * Generally uninteresting rctl convenience functions.
4013  */
4014 
4015 int
4016 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
4017     rctlblk_t *rctlblk)
4018 {
4019 	unsigned long long ull;
4020 	char *endp;
4021 	rctl_priv_t priv;
4022 	rctl_qty_t limit;
4023 	uint_t action;
4024 
4025 	/* Get the privilege */
4026 	if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
4027 		priv = RCPRIV_BASIC;
4028 	} else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
4029 		priv = RCPRIV_PRIVILEGED;
4030 	} else {
4031 		/* Invalid privilege */
4032 		return (Z_INVAL);
4033 	}
4034 
4035 	/* deal with negative input; strtoull(3c) doesn't do what we want */
4036 	if (rctlval->zone_rctlval_limit[0] == '-')
4037 		return (Z_INVAL);
4038 	/* Get the limit */
4039 	errno = 0;
4040 	ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
4041 	if (errno != 0 || *endp != '\0') {
4042 		/* parse failed */
4043 		return (Z_INVAL);
4044 	}
4045 	limit = (rctl_qty_t)ull;
4046 
4047 	/* Get the action */
4048 	if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
4049 		action = RCTL_LOCAL_NOACTION;
4050 	} else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
4051 		action = RCTL_LOCAL_SIGNAL;
4052 	} else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
4053 		action = RCTL_LOCAL_DENY;
4054 	} else {
4055 		/* Invalid Action */
4056 		return (Z_INVAL);
4057 	}
4058 	rctlblk_set_local_action(rctlblk, action, 0);
4059 	rctlblk_set_privilege(rctlblk, priv);
4060 	rctlblk_set_value(rctlblk, limit);
4061 	return (Z_OK);
4062 }
4063 
4064 static int
4065 rctl_check(const char *rctlname, void *arg)
4066 {
4067 	const char *attrname = arg;
4068 
4069 	/*
4070 	 * Returning 1 here is our signal to zonecfg_is_rctl() that it is
4071 	 * indeed an rctl name recognized by the system.
4072 	 */
4073 	return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
4074 }
4075 
4076 boolean_t
4077 zonecfg_is_rctl(const char *name)
4078 {
4079 	return (rctl_walk(rctl_check, (void *)name) == 1);
4080 }
4081 
4082 boolean_t
4083 zonecfg_valid_rctlname(const char *name)
4084 {
4085 	const char *c;
4086 
4087 	if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
4088 		return (B_FALSE);
4089 	if (strlen(name) == sizeof ("zone.") - 1)
4090 		return (B_FALSE);
4091 	for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
4092 		if (!isalpha(*c) && *c != '-')
4093 			return (B_FALSE);
4094 	}
4095 	return (B_TRUE);
4096 }
4097 
4098 boolean_t
4099 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
4100 {
4101 	rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
4102 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
4103 
4104 	if (priv != RCPRIV_PRIVILEGED)
4105 		return (B_FALSE);
4106 	if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
4107 		return (B_FALSE);
4108 	return (B_TRUE);
4109 }
4110 
4111 boolean_t
4112 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
4113 {
4114 	rctlblk_t *current, *next;
4115 	rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
4116 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
4117 	uint_t global_flags;
4118 
4119 	if (!zonecfg_valid_rctlblk(rctlblk))
4120 		return (B_FALSE);
4121 	if (!zonecfg_valid_rctlname(name))
4122 		return (B_FALSE);
4123 
4124 	current = alloca(rctlblk_size());
4125 	if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
4126 		return (B_TRUE);	/* not an rctl on this system */
4127 	/*
4128 	 * Make sure the proposed value isn't greater than the current system
4129 	 * value.
4130 	 */
4131 	next = alloca(rctlblk_size());
4132 	while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
4133 		rctlblk_t *tmp;
4134 
4135 		if (getrctl(name, current, next, RCTL_NEXT) != 0)
4136 			return (B_FALSE);	/* shouldn't happen */
4137 		tmp = current;
4138 		current = next;
4139 		next = tmp;
4140 	}
4141 	if (limit > rctlblk_get_value(current))
4142 		return (B_FALSE);
4143 
4144 	/*
4145 	 * Make sure the proposed action is allowed.
4146 	 */
4147 	global_flags = rctlblk_get_global_flags(current);
4148 	if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
4149 	    action == RCTL_LOCAL_DENY)
4150 		return (B_FALSE);
4151 	if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
4152 	    action == RCTL_LOCAL_NOACTION)
4153 		return (B_FALSE);
4154 
4155 	return (B_TRUE);
4156 }
4157 
4158 /*
4159  * There is always a race condition between reading the initial copy of
4160  * a zones state and its state changing.  We address this by providing
4161  * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
4162  * When zonecfg_critical_enter is called, sets the state field to LOCKED
4163  * and aquires biglock. Biglock protects against other threads executing
4164  * critical_enter and the state field protects against state changes during
4165  * the critical period.
4166  *
4167  * If any state changes occur, zn_cb will set the failed field of the znotify
4168  * structure.  This will cause the critical_exit function to re-lock the
4169  * channel and return an error. Since evsnts may be delayed, the critical_exit
4170  * function "flushes" the queue by putting an event on the queue and waiting for
4171  * zn_cb to notify critical_exit that it received the ping event.
4172  */
4173 static const char *
4174 string_get_tok(const char *in, char delim, int num)
4175 {
4176 	int i = 0;
4177 
4178 	for (; i < num; in++) {
4179 		if (*in == delim)
4180 			i++;
4181 		if (*in == 0)
4182 			return (NULL);
4183 	}
4184 	return (in);
4185 }
4186 
4187 static boolean_t
4188 is_ping(sysevent_t *ev)
4189 {
4190 	if (strcmp(sysevent_get_subclass_name(ev),
4191 	    ZONE_EVENT_PING_SUBCLASS) == 0) {
4192 		return (B_TRUE);
4193 	} else {
4194 		return (B_FALSE);
4195 	}
4196 }
4197 
4198 static boolean_t
4199 is_my_ping(sysevent_t *ev)
4200 {
4201 	const char *sender;
4202 	char mypid[sizeof (pid_t) * 3 + 1];
4203 
4204 	(void) snprintf(mypid, sizeof (mypid), "%i", getpid());
4205 	sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
4206 	if (sender == NULL)
4207 		return (B_FALSE);
4208 	if (strcmp(sender, mypid) != 0)
4209 		return (B_FALSE);
4210 	return (B_TRUE);
4211 }
4212 
4213 static int
4214 do_callback(struct znotify *zevtchan, sysevent_t *ev)
4215 {
4216 	nvlist_t *l;
4217 	int zid;
4218 	char *zonename;
4219 	char *newstate;
4220 	char *oldstate;
4221 	int ret;
4222 	hrtime_t when;
4223 
4224 	if (strcmp(sysevent_get_subclass_name(ev),
4225 	    ZONE_EVENT_STATUS_SUBCLASS) == 0) {
4226 
4227 		if (sysevent_get_attr_list(ev, &l) != 0) {
4228 			if (errno == ENOMEM) {
4229 				zevtchan->zn_failure_count++;
4230 				return (EAGAIN);
4231 			}
4232 			return (0);
4233 		}
4234 		ret = 0;
4235 
4236 		if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
4237 		    (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
4238 		    == 0) &&
4239 		    (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
4240 		    == 0) &&
4241 		    (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
4242 		    (uint64_t *)&when) == 0) &&
4243 		    (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
4244 			ret = zevtchan->zn_callback(zonename, zid, newstate,
4245 			    oldstate, when, zevtchan->zn_private);
4246 		}
4247 
4248 		zevtchan->zn_failure_count = 0;
4249 		nvlist_free(l);
4250 		return (ret);
4251 	} else {
4252 		/*
4253 		 * We have received an event in an unknown subclass. Ignore.
4254 		 */
4255 		zevtchan->zn_failure_count = 0;
4256 		return (0);
4257 	}
4258 }
4259 
4260 static int
4261 zn_cb(sysevent_t *ev, void *p)
4262 {
4263 	struct znotify *zevtchan = p;
4264 	int error;
4265 
4266 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
4267 
4268 	if (is_ping(ev) && !is_my_ping(ev)) {
4269 		(void) pthread_mutex_unlock((&zevtchan->zn_mutex));
4270 		return (0);
4271 	}
4272 
4273 	if (zevtchan->zn_state == ZN_LOCKED) {
4274 		assert(!is_ping(ev));
4275 		zevtchan->zn_failed = B_TRUE;
4276 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
4277 		return (0);
4278 	}
4279 
4280 	if (zevtchan->zn_state == ZN_PING_INFLIGHT) {
4281 		if (is_ping(ev)) {
4282 			zevtchan->zn_state = ZN_PING_RECEIVED;
4283 			(void) pthread_cond_signal(&(zevtchan->zn_cond));
4284 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
4285 			return (0);
4286 		} else {
4287 			zevtchan->zn_failed = B_TRUE;
4288 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
4289 			return (0);
4290 		}
4291 	}
4292 
4293 	if (zevtchan->zn_state == ZN_UNLOCKED) {
4294 
4295 		error = do_callback(zevtchan, ev);
4296 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
4297 		/*
4298 		 * Every ENOMEM failure causes do_callback to increment
4299 		 * zn_failure_count and every success causes it to
4300 		 * set zn_failure_count to zero.  If we got EAGAIN,
4301 		 * we will sleep for zn_failure_count seconds and return
4302 		 * EAGAIN to gpec to try again.
4303 		 *
4304 		 * After 55 seconds, or 10 try's we give up and drop the
4305 		 * event.
4306 		 */
4307 		if (error == EAGAIN) {
4308 			if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) {
4309 				return (0);
4310 			}
4311 			(void) sleep(zevtchan->zn_failure_count);
4312 		}
4313 		return (error);
4314 	}
4315 
4316 	if (zevtchan->zn_state == ZN_PING_RECEIVED) {
4317 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
4318 		return (0);
4319 	}
4320 
4321 	abort();
4322 	return (0);
4323 }
4324 
4325 void
4326 zonecfg_notify_critical_enter(void *h)
4327 {
4328 	struct znotify *zevtchan = h;
4329 
4330 	(void) pthread_mutex_lock(&(zevtchan->zn_bigmutex));
4331 	zevtchan->zn_state = ZN_LOCKED;
4332 }
4333 
4334 int
4335 zonecfg_notify_critical_exit(void * h)
4336 {
4337 
4338 	struct znotify *zevtchan = h;
4339 
4340 	if (zevtchan->zn_state == ZN_UNLOCKED)
4341 		return (0);
4342 
4343 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
4344 	zevtchan->zn_state = ZN_PING_INFLIGHT;
4345 
4346 	(void) sysevent_evc_publish(zevtchan->zn_eventchan,
4347 	    ZONE_EVENT_STATUS_CLASS,
4348 	    ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER,
4349 	    zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP);
4350 
4351 	while (zevtchan->zn_state != ZN_PING_RECEIVED) {
4352 		(void) pthread_cond_wait(&(zevtchan->zn_cond),
4353 		    &(zevtchan->zn_mutex));
4354 	}
4355 
4356 	if (zevtchan->zn_failed == B_TRUE) {
4357 		zevtchan->zn_state = ZN_LOCKED;
4358 		zevtchan->zn_failed = B_FALSE;
4359 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
4360 		return (1);
4361 	}
4362 
4363 	zevtchan->zn_state = ZN_UNLOCKED;
4364 	(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
4365 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
4366 	return (0);
4367 }
4368 
4369 void
4370 zonecfg_notify_critical_abort(void *h)
4371 {
4372 	struct znotify *zevtchan = h;
4373 
4374 	zevtchan->zn_state = ZN_UNLOCKED;
4375 	zevtchan->zn_failed = B_FALSE;
4376 	/*
4377 	 * Don't do anything about zn_lock. If it is held, it could only be
4378 	 * held by zn_cb and it will be unlocked soon.
4379 	 */
4380 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
4381 }
4382 
4383 void *
4384 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
4385     const char *newstate, const char *oldstate, hrtime_t when, void *p),
4386     void *p)
4387 {
4388 	struct znotify *zevtchan;
4389 	int i = 1;
4390 	int r;
4391 
4392 	zevtchan = malloc(sizeof (struct znotify));
4393 
4394 	if (zevtchan == NULL)
4395 		return (NULL);
4396 
4397 	zevtchan->zn_private = p;
4398 	zevtchan->zn_callback = func;
4399 	zevtchan->zn_state = ZN_UNLOCKED;
4400 	zevtchan->zn_failed = B_FALSE;
4401 
4402 	if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL))
4403 		goto out3;
4404 	if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) {
4405 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
4406 		goto out3;
4407 	}
4408 	if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) {
4409 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
4410 		(void) pthread_cond_destroy(&(zevtchan->zn_cond));
4411 		goto out3;
4412 	}
4413 
4414 	if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan),
4415 	    0) != 0)
4416 		goto out2;
4417 
4418 	do {
4419 		/*
4420 		 * At 4 digits the subscriber ID gets too long and we have
4421 		 * no chance of successfully registering.
4422 		 */
4423 		if (i > 999)
4424 			goto out1;
4425 
4426 		(void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i",
4427 		    getpid() % 999999l, i);
4428 
4429 		r = sysevent_evc_subscribe(zevtchan->zn_eventchan,
4430 		    zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb,
4431 		    zevtchan, 0);
4432 
4433 		i++;
4434 
4435 	} while (r);
4436 
4437 	return (zevtchan);
4438 out1:
4439 	sysevent_evc_unbind(zevtchan->zn_eventchan);
4440 out2:
4441 	(void) pthread_mutex_destroy(&zevtchan->zn_mutex);
4442 	(void) pthread_cond_destroy(&zevtchan->zn_cond);
4443 	(void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex));
4444 out3:
4445 	free(zevtchan);
4446 
4447 	return (NULL);
4448 }
4449 
4450 void
4451 zonecfg_notify_unbind(void *handle)
4452 {
4453 
4454 	int ret;
4455 
4456 	sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan);
4457 	/*
4458 	 * Check that all evc threads have gone away. This should be
4459 	 * enforced by sysevent_evc_unbind.
4460 	 */
4461 	ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex);
4462 
4463 	if (ret)
4464 		abort();
4465 
4466 	(void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex);
4467 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex);
4468 	(void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond);
4469 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex);
4470 
4471 	free(handle);
4472 }
4473 
4474 static int
4475 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
4476 {
4477 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
4478 	int err;
4479 
4480 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL);
4481 	if ((err = newprop(newnode, DTD_ATTR_NAME,
4482 	    tabptr->zone_dataset_name)) != Z_OK)
4483 		return (err);
4484 	return (Z_OK);
4485 }
4486 
4487 int
4488 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
4489 {
4490 	int err;
4491 
4492 	if (tabptr == NULL)
4493 		return (Z_INVAL);
4494 
4495 	if ((err = operation_prep(handle)) != Z_OK)
4496 		return (err);
4497 
4498 	if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK)
4499 		return (err);
4500 
4501 	return (Z_OK);
4502 }
4503 
4504 static int
4505 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
4506 {
4507 	xmlNodePtr cur = handle->zone_dh_cur;
4508 
4509 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
4510 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
4511 			continue;
4512 
4513 		if (match_prop(cur, DTD_ATTR_NAME,
4514 		    tabptr->zone_dataset_name)) {
4515 			xmlUnlinkNode(cur);
4516 			xmlFreeNode(cur);
4517 			return (Z_OK);
4518 		}
4519 	}
4520 	return (Z_NO_RESOURCE_ID);
4521 }
4522 
4523 int
4524 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
4525 {
4526 	int err;
4527 
4528 	if (tabptr == NULL)
4529 		return (Z_INVAL);
4530 
4531 	if ((err = operation_prep(handle)) != Z_OK)
4532 		return (err);
4533 
4534 	if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK)
4535 		return (err);
4536 
4537 	return (Z_OK);
4538 }
4539 
4540 int
4541 zonecfg_modify_ds(
4542 	zone_dochandle_t handle,
4543 	struct zone_dstab *oldtabptr,
4544 	struct zone_dstab *newtabptr)
4545 {
4546 	int err;
4547 
4548 	if (oldtabptr == NULL || newtabptr == NULL)
4549 		return (Z_INVAL);
4550 
4551 	if ((err = operation_prep(handle)) != Z_OK)
4552 		return (err);
4553 
4554 	if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK)
4555 		return (err);
4556 
4557 	if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK)
4558 		return (err);
4559 
4560 	return (Z_OK);
4561 }
4562 
4563 int
4564 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
4565 {
4566 	xmlNodePtr cur, firstmatch;
4567 	int err;
4568 	char dataset[MAXNAMELEN];
4569 
4570 	if (tabptr == NULL)
4571 		return (Z_INVAL);
4572 
4573 	if ((err = operation_prep(handle)) != Z_OK)
4574 		return (err);
4575 
4576 	cur = handle->zone_dh_cur;
4577 	firstmatch = NULL;
4578 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
4579 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
4580 			continue;
4581 		if (strlen(tabptr->zone_dataset_name) > 0) {
4582 			if ((fetchprop(cur, DTD_ATTR_NAME, dataset,
4583 			    sizeof (dataset)) == Z_OK) &&
4584 			    (strcmp(tabptr->zone_dataset_name,
4585 			    dataset) == 0)) {
4586 				if (firstmatch == NULL)
4587 					firstmatch = cur;
4588 				else
4589 					return (Z_INSUFFICIENT_SPEC);
4590 			}
4591 		}
4592 	}
4593 	if (firstmatch == NULL)
4594 		return (Z_NO_RESOURCE_ID);
4595 
4596 	cur = firstmatch;
4597 
4598 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
4599 	    sizeof (tabptr->zone_dataset_name))) != Z_OK)
4600 		return (err);
4601 
4602 	return (Z_OK);
4603 }
4604 
4605 int
4606 zonecfg_setdsent(zone_dochandle_t handle)
4607 {
4608 	return (zonecfg_setent(handle));
4609 }
4610 
4611 int
4612 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
4613 {
4614 	xmlNodePtr cur;
4615 	int err;
4616 
4617 	if (handle == NULL)
4618 		return (Z_INVAL);
4619 
4620 	if ((cur = handle->zone_dh_cur) == NULL)
4621 		return (Z_NO_ENTRY);
4622 
4623 	for (; cur != NULL; cur = cur->next)
4624 		if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET))
4625 			break;
4626 	if (cur == NULL) {
4627 		handle->zone_dh_cur = handle->zone_dh_top;
4628 		return (Z_NO_ENTRY);
4629 	}
4630 
4631 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
4632 	    sizeof (tabptr->zone_dataset_name))) != Z_OK) {
4633 		handle->zone_dh_cur = handle->zone_dh_top;
4634 		return (err);
4635 	}
4636 
4637 	handle->zone_dh_cur = cur->next;
4638 	return (Z_OK);
4639 }
4640 
4641 int
4642 zonecfg_enddsent(zone_dochandle_t handle)
4643 {
4644 	return (zonecfg_endent(handle));
4645 }
4646 
4647 int
4648 zonecfg_setpkgent(zone_dochandle_t handle)
4649 {
4650 	return (zonecfg_setent(handle));
4651 }
4652 
4653 int
4654 zonecfg_getpkgent(zone_dochandle_t handle, struct zone_pkgtab *tabptr)
4655 {
4656 	xmlNodePtr cur;
4657 	int err;
4658 
4659 	if (handle == NULL)
4660 		return (Z_INVAL);
4661 
4662 	if ((cur = handle->zone_dh_cur) == NULL)
4663 		return (Z_NO_ENTRY);
4664 
4665 	for (; cur != NULL; cur = cur->next)
4666 		if (!xmlStrcmp(cur->name, DTD_ELEM_PACKAGE))
4667 			break;
4668 	if (cur == NULL) {
4669 		handle->zone_dh_cur = handle->zone_dh_top;
4670 		return (Z_NO_ENTRY);
4671 	}
4672 
4673 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_pkg_name,
4674 	    sizeof (tabptr->zone_pkg_name))) != Z_OK) {
4675 		handle->zone_dh_cur = handle->zone_dh_top;
4676 		return (err);
4677 	}
4678 
4679 	if ((err = fetchprop(cur, DTD_ATTR_VERSION, tabptr->zone_pkg_version,
4680 	    sizeof (tabptr->zone_pkg_version))) != Z_OK) {
4681 		handle->zone_dh_cur = handle->zone_dh_top;
4682 		return (err);
4683 	}
4684 
4685 	handle->zone_dh_cur = cur->next;
4686 	return (Z_OK);
4687 }
4688 
4689 int
4690 zonecfg_endpkgent(zone_dochandle_t handle)
4691 {
4692 	return (zonecfg_endent(handle));
4693 }
4694 
4695 int
4696 zonecfg_setpatchent(zone_dochandle_t handle)
4697 {
4698 	return (zonecfg_setent(handle));
4699 }
4700 
4701 int
4702 zonecfg_getpatchent(zone_dochandle_t handle, struct zone_patchtab *tabptr)
4703 {
4704 	xmlNodePtr cur;
4705 	int err;
4706 
4707 	if (handle == NULL)
4708 		return (Z_INVAL);
4709 
4710 	if ((cur = handle->zone_dh_cur) == NULL)
4711 		return (Z_NO_ENTRY);
4712 
4713 	for (; cur != NULL; cur = cur->next)
4714 		if (!xmlStrcmp(cur->name, DTD_ELEM_PATCH))
4715 			break;
4716 	if (cur == NULL) {
4717 		handle->zone_dh_cur = handle->zone_dh_top;
4718 		return (Z_NO_ENTRY);
4719 	}
4720 
4721 	if ((err = fetchprop(cur, DTD_ATTR_ID, tabptr->zone_patch_id,
4722 	    sizeof (tabptr->zone_patch_id))) != Z_OK) {
4723 		handle->zone_dh_cur = handle->zone_dh_top;
4724 		return (err);
4725 	}
4726 
4727 	handle->zone_dh_cur = cur->next;
4728 	return (Z_OK);
4729 }
4730 
4731 int
4732 zonecfg_endpatchent(zone_dochandle_t handle)
4733 {
4734 	return (zonecfg_endent(handle));
4735 }
4736 
4737 int
4738 zonecfg_setdevperment(zone_dochandle_t handle)
4739 {
4740 	return (zonecfg_setent(handle));
4741 }
4742 
4743 int
4744 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr)
4745 {
4746 	xmlNodePtr cur;
4747 	int err;
4748 	char buf[128];
4749 
4750 	tabptr->zone_devperm_acl = NULL;
4751 
4752 	if (handle == NULL)
4753 		return (Z_INVAL);
4754 
4755 	if ((cur = handle->zone_dh_cur) == NULL)
4756 		return (Z_NO_ENTRY);
4757 
4758 	for (; cur != NULL; cur = cur->next)
4759 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM))
4760 			break;
4761 	if (cur == NULL) {
4762 		handle->zone_dh_cur = handle->zone_dh_top;
4763 		return (Z_NO_ENTRY);
4764 	}
4765 
4766 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name,
4767 	    sizeof (tabptr->zone_devperm_name))) != Z_OK) {
4768 		handle->zone_dh_cur = handle->zone_dh_top;
4769 		return (err);
4770 	}
4771 
4772 	if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) {
4773 		handle->zone_dh_cur = handle->zone_dh_top;
4774 		return (err);
4775 	}
4776 	tabptr->zone_devperm_uid = (uid_t)atol(buf);
4777 
4778 	if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) {
4779 		handle->zone_dh_cur = handle->zone_dh_top;
4780 		return (err);
4781 	}
4782 	tabptr->zone_devperm_gid = (gid_t)atol(buf);
4783 
4784 	if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) {
4785 		handle->zone_dh_cur = handle->zone_dh_top;
4786 		return (err);
4787 	}
4788 	tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8);
4789 
4790 	if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL,
4791 	    &(tabptr->zone_devperm_acl))) != Z_OK) {
4792 		handle->zone_dh_cur = handle->zone_dh_top;
4793 		return (err);
4794 	}
4795 
4796 	handle->zone_dh_cur = cur->next;
4797 	return (Z_OK);
4798 }
4799 
4800 int
4801 zonecfg_enddevperment(zone_dochandle_t handle)
4802 {
4803 	return (zonecfg_endent(handle));
4804 }
4805 
4806 /*
4807  * Process a list of pkgs from an entry in the contents file, adding each pkg
4808  * name to the list of pkgs.
4809  *
4810  * It is possible for the pkg name to be preceeded by a special character
4811  * which indicates some bookkeeping information for pkging.  Check if the
4812  * first char is not an Alpha char.  If so, skip over it.
4813  */
4814 static int
4815 add_pkg_list(char *lastp, char ***plist, int *pcnt)
4816 {
4817 	char	*p;
4818 	int	pkg_cnt = *pcnt;
4819 	char	**pkgs = *plist;
4820 	int	res = Z_OK;
4821 
4822 	while ((p = strtok_r(NULL, " ", &lastp)) != NULL) {
4823 		char	**tmpp;
4824 		int	i;
4825 
4826 		/* skip over any special pkg bookkeeping char */
4827 		if (!isalpha(*p))
4828 			p++;
4829 
4830 		/* Check if the pkg is already in the list */
4831 		for (i = 0; i < pkg_cnt; i++) {
4832 			if (strcmp(p, pkgs[i]) == 0)
4833 				break;
4834 		}
4835 
4836 		if (i < pkg_cnt)
4837 			continue;
4838 
4839 		/* The pkg is not in the list; add it. */
4840 		if ((tmpp = (char **)realloc(pkgs,
4841 		    sizeof (char *) * (pkg_cnt + 1))) == NULL) {
4842 			res = Z_NOMEM;
4843 			break;
4844 		}
4845 		pkgs = tmpp;
4846 
4847 		if ((pkgs[pkg_cnt] = strdup(p)) == NULL) {
4848 			res = Z_NOMEM;
4849 			break;
4850 		}
4851 		pkg_cnt++;
4852 	}
4853 
4854 	*plist = pkgs;
4855 	*pcnt = pkg_cnt;
4856 
4857 	return (res);
4858 }
4859 
4860 /*
4861  * Process an entry from the contents file (type "directory") and if the
4862  * directory path is in the list of paths, add the associated list of pkgs
4863  * to the pkg list.  The input parameter "entry" will be broken up by
4864  * the parser within this function so its value will be modified when this
4865  * function exits.
4866  *
4867  * The entries we are looking for will look something like:
4868  *	/usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf ....
4869  */
4870 static int
4871 get_path_pkgs(char *entry, char **paths, int cnt, char ***pkgs, int *pkg_cnt)
4872 {
4873 	char	*f1;
4874 	char	*f2;
4875 	char	*lastp;
4876 	int	i;
4877 	int	res = Z_OK;
4878 
4879 	if ((f1 = strtok_r(entry, " ", &lastp)) == NULL ||
4880 	    (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0)
4881 		return (Z_OK);
4882 
4883 	/* Check if this directory entry is in the list of paths. */
4884 	for (i = 0; i < cnt; i++) {
4885 		if (fnmatch(paths[i], f1, FNM_PATHNAME) == 0) {
4886 			/*
4887 			 * We do want the pkgs for this path.  First, skip
4888 			 * over the next 4 fields in the entry so that we call
4889 			 * add_pkg_list starting with the pkg names.
4890 			 */
4891 			int j;
4892 			char	*nlp;
4893 
4894 			for (j = 0; j < 4 &&
4895 			    strtok_r(NULL, " ", &lastp) != NULL; j++)
4896 				;
4897 			/*
4898 			 * If there are < 4 fields this entry is corrupt,
4899 			 * just skip it.
4900 			 */
4901 			if (j < 4)
4902 				return (Z_OK);
4903 
4904 			/* strip newline from the line */
4905 			nlp = (lastp + strlen(lastp) - 1);
4906 			if (*nlp == '\n')
4907 				*nlp = '\0';
4908 
4909 			res = add_pkg_list(lastp, pkgs, pkg_cnt);
4910 			break;
4911 		}
4912 	}
4913 
4914 	return (res);
4915 }
4916 
4917 /*
4918  * Read an entry from a pkginfo or contents file.  Some of these lines can
4919  * either be arbitrarily long or be continued by a backslash at the end of
4920  * the line.  This function coalesces lines that are longer than the read
4921  * buffer, and lines that are continued, into one buffer which is returned.
4922  * The caller must free this memory.  NULL is returned when we hit EOF or
4923  * if we run out of memory (errno is set to ENOMEM).
4924  */
4925 static char *
4926 read_pkg_data(FILE *fp)
4927 {
4928 	char *start;
4929 	char *inp;
4930 	char *p;
4931 	int char_cnt = 0;
4932 
4933 	errno = 0;
4934 	if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) {
4935 		errno = ENOMEM;
4936 		return (NULL);
4937 	}
4938 
4939 	inp = start;
4940 	while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) {
4941 		int len;
4942 
4943 		len = strlen(inp);
4944 		if (inp[len - 1] == '\n' &&
4945 		    (len == 1 || inp[len - 2] != '\\')) {
4946 			char_cnt = len;
4947 			break;
4948 		}
4949 
4950 		if (inp[len - 2] == '\\')
4951 			char_cnt += len - 2;
4952 		else
4953 			char_cnt += PKGINFO_RD_LEN - 1;
4954 
4955 		if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) {
4956 			errno = ENOMEM;
4957 			break;
4958 		}
4959 
4960 		start = p;
4961 		inp = start + char_cnt;
4962 	}
4963 
4964 	if (errno == ENOMEM || (p == NULL && char_cnt == 0)) {
4965 		free(start);
4966 		start = NULL;
4967 	}
4968 
4969 	return (start);
4970 }
4971 
4972 static void
4973 free_ipd_pkgs(char **pkgs, int cnt)
4974 {
4975 	int i;
4976 
4977 	for (i = 0; i < cnt; i++)
4978 		free(pkgs[i]);
4979 	free(pkgs);
4980 }
4981 
4982 /*
4983  * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the
4984  * list of pkgs that deliver into those dirs.
4985  */
4986 static int
4987 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt)
4988 {
4989 	int	res;
4990 	struct zone_fstab fstab;
4991 	int	ipd_cnt = 0;
4992 	char	**ipds = NULL;
4993 	int	pkg_cnt = 0;
4994 	char	**pkgs = NULL;
4995 	int	i;
4996 
4997 	if ((res = zonecfg_setipdent(handle)) != Z_OK)
4998 		return (res);
4999 
5000 	while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
5001 		char	**p;
5002 		int	len;
5003 
5004 		if ((p = (char **)realloc(ipds,
5005 		    sizeof (char *) * (ipd_cnt + 2))) == NULL) {
5006 			res = Z_NOMEM;
5007 			break;
5008 		}
5009 		ipds = p;
5010 
5011 		if ((ipds[ipd_cnt] = strdup(fstab.zone_fs_dir)) == NULL) {
5012 			res = Z_NOMEM;
5013 			break;
5014 		}
5015 		ipd_cnt++;
5016 
5017 		len = strlen(fstab.zone_fs_dir) + 3;
5018 		if ((ipds[ipd_cnt] = malloc(len)) == NULL) {
5019 			res = Z_NOMEM;
5020 			break;
5021 		}
5022 
5023 		(void) snprintf(ipds[ipd_cnt], len, "%s/*", fstab.zone_fs_dir);
5024 		ipd_cnt++;
5025 	}
5026 
5027 	(void) zonecfg_endipdent(handle);
5028 
5029 	if (res != Z_OK) {
5030 		for (i = 0; i < ipd_cnt; i++)
5031 			free(ipds[i]);
5032 		free(ipds);
5033 		return (res);
5034 	}
5035 
5036 	/* We only have to process the contents file if we have ipds. */
5037 	if (ipd_cnt > 0) {
5038 		FILE	*fp;
5039 
5040 		if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) {
5041 			char	*buf;
5042 
5043 			while ((buf = read_pkg_data(fp)) != NULL) {
5044 				res = get_path_pkgs(buf, ipds, ipd_cnt, &pkgs,
5045 				    &pkg_cnt);
5046 				free(buf);
5047 				if (res != Z_OK)
5048 					break;
5049 			}
5050 
5051 			(void) fclose(fp);
5052 		}
5053 	}
5054 
5055 	for (i = 0; i < ipd_cnt; i++)
5056 		free(ipds[i]);
5057 	free(ipds);
5058 
5059 	if (res != Z_OK) {
5060 		free_ipd_pkgs(pkgs, pkg_cnt);
5061 	} else {
5062 		*pkg_list = pkgs;
5063 		*cnt = pkg_cnt;
5064 	}
5065 
5066 	return (res);
5067 }
5068 
5069 /*
5070  * Return true if pkg_name is in the list of pkgs that deliver into an
5071  * inherited pkg directory for the zone.
5072  */
5073 static boolean_t
5074 dir_pkg(char *pkg_name, char **pkg_list, int cnt)
5075 {
5076 	int i;
5077 
5078 	for (i = 0; i < cnt; i++) {
5079 		if (strcmp(pkg_name, pkg_list[i]) == 0)
5080 			return (B_TRUE);
5081 	}
5082 
5083 	return (B_FALSE);
5084 }
5085 
5086 /*
5087  * Start by adding the patch to the sw inventory on the handle.
5088  *
5089  * The info parameter will be the portion of the PATCH_INFO_ entry following
5090  * the '='.  For example:
5091  * Installed: Wed Dec  7 07:13:51 PST 2005 From: mum Obsoletes: 120777-03 \
5092  *	121087-02 119108-07 Requires: 119575-02 119255-06 Incompatibles:
5093  *
5094  * A backed out patch will have an info line of "backed out\n".  We should
5095  * skip these patches.
5096  *
5097  * We also want to add the Obsolete and Incompatible patches to the
5098  * sw inventory description of this patch.
5099  */
5100 static int
5101 add_patch(zone_dochandle_t handle, char *patch, char *info)
5102 {
5103 	xmlNodePtr	node;
5104 	xmlNodePtr	cur;
5105 	int		err;
5106 	char		*p;
5107 	char		*lastp;
5108 	boolean_t	add_info = B_FALSE;
5109 	boolean_t	obsolete;
5110 
5111 	if (strcmp(info, "backed out\n") == 0)
5112 		return (Z_OK);
5113 
5114 	if ((err = operation_prep(handle)) != Z_OK)
5115 		return (err);
5116 
5117 	cur = handle->zone_dh_cur;
5118 	node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL);
5119 	if ((err = newprop(node, DTD_ATTR_ID, patch)) != Z_OK)
5120 		return (err);
5121 
5122 	/*
5123 	 * Start with the first token.  This will probably be "Installed:".
5124 	 * If we can't tokenize this entry, just return.
5125 	 */
5126 	if ((p = strtok_r(info, " ", &lastp)) == NULL)
5127 		return (Z_OK);
5128 
5129 	do {
5130 		xmlNodePtr new_node;
5131 		char	*nlp;
5132 
5133 		if (strcmp(p, "Installed:") == 0 ||
5134 		    strcmp(p, "Requires:") == 0 ||
5135 		    strcmp(p, "From:") == 0) {
5136 			add_info = B_FALSE;
5137 			continue;
5138 		} else if (strcmp(p, "Obsoletes:") == 0) {
5139 			obsolete = B_TRUE;
5140 			add_info = B_TRUE;
5141 			continue;
5142 		} else if (strcmp(p, "Incompatibles:") == 0) {
5143 			obsolete = B_FALSE;
5144 			add_info = B_TRUE;
5145 			continue;
5146 		}
5147 
5148 		if (!add_info)
5149 			continue;
5150 
5151 		/* strip newline from last patch in the line */
5152 		nlp = (p + strlen(p) - 1);
5153 		if (*nlp == '\n')
5154 			*nlp = '\0';
5155 
5156 		if (obsolete)
5157 			new_node = xmlNewTextChild(node, NULL,
5158 			    DTD_ELEM_OBSOLETES, NULL);
5159 		else
5160 			new_node = xmlNewTextChild(node, NULL,
5161 			    DTD_ELEM_INCOMPATIBLE, NULL);
5162 
5163 		if ((err = newprop(new_node, DTD_ATTR_ID, p)) != Z_OK)
5164 			return (err);
5165 
5166 	} while ((p = strtok_r(NULL, " ", &lastp)) != NULL);
5167 
5168 	return (Z_OK);
5169 }
5170 
5171 static boolean_t
5172 unique_patch(zone_dochandle_t handle, char *patch)
5173 {
5174 	xmlNodePtr	cur;
5175 	char		id[MAXNAMELEN];
5176 
5177 	cur = xmlDocGetRootElement(handle->zone_dh_doc);
5178 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
5179 		if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) {
5180 			if (fetchprop(cur, DTD_ATTR_ID, id, sizeof (id))
5181 			    != Z_OK)
5182 				continue;
5183 
5184 			if (strcmp(patch, id) == 0)
5185 				return (B_FALSE);
5186 		}
5187 	}
5188 
5189 	return (B_TRUE);
5190 }
5191 
5192 /*
5193  * Add the unique patches associated with this pkg to the sw inventory on the
5194  * handle.
5195  *
5196  * We are processing entries of the form:
5197  * PATCH_INFO_121454-02=Installed: Wed Dec  7 07:13:51 PST 2005 From: mum \
5198  *	Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \
5199  *	119255-06 Incompatibles:
5200  *
5201  */
5202 static int
5203 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop)
5204 {
5205 	int i;
5206 	int res = Z_OK;
5207 
5208 	for (i = 0; i < infop->zpi_patch_cnt; i++) {
5209 		char *p, *ep;
5210 
5211 		if (strlen(infop->zpi_patchinfo[i]) < (sizeof (PATCHINFO) - 1))
5212 			continue;
5213 
5214 		/* Skip over "PATCH_INFO_" to get the patch id. */
5215 		p = infop->zpi_patchinfo[i] + sizeof (PATCHINFO) - 1;
5216 		if ((ep = strchr(p, '=')) == NULL)
5217 			continue;
5218 
5219 		*ep = '\0';
5220 		if (unique_patch(handle, p))
5221 			if ((res = add_patch(handle, p, ep + 1)) != Z_OK)
5222 				break;
5223 	}
5224 
5225 	return (res);
5226 }
5227 
5228 /*
5229  * Add the pkg to the sw inventory on the handle.
5230  */
5231 static int
5232 add_pkg(zone_dochandle_t handle, char *name, char *version)
5233 {
5234 	xmlNodePtr newnode;
5235 	xmlNodePtr cur;
5236 	int err;
5237 
5238 	if ((err = operation_prep(handle)) != Z_OK)
5239 		return (err);
5240 
5241 	cur = handle->zone_dh_cur;
5242 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL);
5243 	if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK)
5244 		return (err);
5245 	if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK)
5246 		return (err);
5247 	return (Z_OK);
5248 }
5249 
5250 static void
5251 free_pkginfo(struct zone_pkginfo *infop)
5252 {
5253 	free(infop->zpi_version);
5254 	if (infop->zpi_patch_cnt > 0) {
5255 		int i;
5256 
5257 		for (i = 0; i < infop->zpi_patch_cnt; i++)
5258 			free(infop->zpi_patchinfo[i]);
5259 		free(infop->zpi_patchinfo);
5260 	}
5261 }
5262 
5263 /*
5264  * Read the pkginfo file and populate the structure with the data we need
5265  * from this pkg for a sw inventory.
5266  */
5267 static int
5268 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop)
5269 {
5270 	FILE	*fp;
5271 	char	*buf;
5272 	int	err = 0;
5273 
5274 	infop->zpi_all_zones = B_FALSE;
5275 	infop->zpi_this_zone = B_FALSE;
5276 	infop->zpi_version = NULL;
5277 	infop->zpi_patch_cnt = 0;
5278 	infop->zpi_patchinfo = NULL;
5279 
5280 	if ((fp = fopen(pkginfo, "r")) == NULL)
5281 		return (errno);
5282 
5283 	while ((buf = read_pkg_data(fp)) != NULL) {
5284 		if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) {
5285 			int len;
5286 
5287 			if ((infop->zpi_version =
5288 			    strdup(buf + sizeof (VERSION) - 1)) == NULL) {
5289 				err = ENOMEM;
5290 				break;
5291 			}
5292 
5293 			/* remove trailing newline */
5294 			len = strlen(infop->zpi_version);
5295 			*(infop->zpi_version + len - 1) = 0;
5296 
5297 		} else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) {
5298 			infop->zpi_all_zones = B_TRUE;
5299 
5300 		} else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) {
5301 			infop->zpi_this_zone = B_TRUE;
5302 
5303 		} else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1)
5304 		    == 0) {
5305 			char **p;
5306 
5307 			if ((p = (char **)realloc(infop->zpi_patchinfo,
5308 			    sizeof (char *) * (infop->zpi_patch_cnt + 1)))
5309 			    == NULL) {
5310 				err = ENOMEM;
5311 				break;
5312 			}
5313 			infop->zpi_patchinfo = p;
5314 
5315 			if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] =
5316 			    strdup(buf)) == NULL) {
5317 				err = ENOMEM;
5318 				break;
5319 			}
5320 			infop->zpi_patch_cnt++;
5321 		}
5322 
5323 		free(buf);
5324 	}
5325 
5326 	free(buf);
5327 
5328 	if (errno == ENOMEM) {
5329 		err = ENOMEM;
5330 		/* Clean up anything we did manage to allocate. */
5331 		free_pkginfo(infop);
5332 	}
5333 
5334 	(void) fclose(fp);
5335 
5336 	return (err);
5337 }
5338 
5339 /*
5340  * Take a software inventory of the global zone.  We need to get the set of
5341  * packages and patches that are on the global zone that the specified
5342  * non-global zone depends on.  The packages we need in the inventory are:
5343  *
5344  * - skip the package if SUNW_PKG_THISZONE is 'true'
5345  * otherwise,
5346  * - add the package if
5347  * a) SUNW_PKG_ALLZONES is 'true',
5348  * or
5349  * b) any file delivered by the package is in a file system that is inherited
5350  * from the global zone.
5351  * If the zone does not inherit any file systems (whole root)
5352  * then (b) will be skipped.
5353  *
5354  * For each of the packages that is being added to the inventory, we will also
5355  * add all of the associated, unique patches to the inventory.
5356  */
5357 static int
5358 zonecfg_sw_inventory(zone_dochandle_t handle)
5359 {
5360 	char		pkginfo[MAXPATHLEN];
5361 	int		res;
5362 	struct dirent	*dp;
5363 	DIR		*dirp;
5364 	struct stat	buf;
5365 	struct zone_pkginfo	info;
5366 	int		pkg_cnt = 0;
5367 	char		**pkgs = NULL;
5368 
5369 	if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK)
5370 		return (res);
5371 
5372 	if ((dirp = opendir(PKG_PATH)) == NULL) {
5373 		free_ipd_pkgs(pkgs, pkg_cnt);
5374 		return (Z_OK);
5375 	}
5376 
5377 	while ((dp = readdir(dirp)) != (struct dirent *)0) {
5378 		if (strcmp(dp->d_name, ".") == 0 ||
5379 		    strcmp(dp->d_name, "..") == 0)
5380 			continue;
5381 
5382 		(void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo",
5383 		    PKG_PATH, dp->d_name);
5384 
5385 		if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode))
5386 			continue;
5387 
5388 		if (get_pkginfo(pkginfo, &info) != 0) {
5389 			res = Z_NOMEM;
5390 			break;
5391 		}
5392 
5393 		if (!info.zpi_this_zone &&
5394 		    (info.zpi_all_zones ||
5395 		    dir_pkg(dp->d_name, pkgs, pkg_cnt))) {
5396 			if ((res = add_pkg(handle, dp->d_name,
5397 			    info.zpi_version)) == Z_OK) {
5398 				if (info.zpi_patch_cnt > 0)
5399 					res = add_patches(handle, &info);
5400 			}
5401 		}
5402 
5403 		free_pkginfo(&info);
5404 
5405 		if (res != Z_OK)
5406 			break;
5407 	}
5408 
5409 	(void) closedir(dirp);
5410 
5411 	free_ipd_pkgs(pkgs, pkg_cnt);
5412 
5413 	if (res == Z_OK)
5414 		handle->zone_dh_sw_inv = B_TRUE;
5415 
5416 	return (res);
5417 }
5418 
5419 /*
5420  * zonecfg_devwalk call-back function used during detach to generate the
5421  * dev info in the manifest.
5422  */
5423 static int
5424 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
5425     const char *acl, void *hdl)
5426 {
5427 	zone_dochandle_t handle = (zone_dochandle_t)hdl;
5428 	xmlNodePtr newnode;
5429 	xmlNodePtr cur;
5430 	int err;
5431 	char buf[128];
5432 
5433 	if ((err = operation_prep(handle)) != Z_OK)
5434 		return (err);
5435 
5436 	cur = handle->zone_dh_cur;
5437 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
5438 	if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
5439 		return (err);
5440 	(void) snprintf(buf, sizeof (buf), "%lu", uid);
5441 	if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
5442 		return (err);
5443 	(void) snprintf(buf, sizeof (buf), "%lu", gid);
5444 	if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
5445 		return (err);
5446 	(void) snprintf(buf, sizeof (buf), "%o", mode);
5447 	if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
5448 		return (err);
5449 	if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
5450 		return (err);
5451 	return (Z_OK);
5452 }
5453 
5454 /*
5455  * Get the information required to support detaching a zone.  This is
5456  * called on the source system when detaching (the detaching parameter should
5457  * be set to true) and on the destination system before attaching (the
5458  * detaching parameter should be false).
5459  *
5460  * For native Solaris zones, the detach/attach process involves validating
5461  * that the software on the global zone can support the zone when we attach.
5462  * To do this we take a software inventory of the global zone.  We also
5463  * have to keep track of the device configuration so that we can properly
5464  * recreate it on the destination.
5465  */
5466 int
5467 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching)
5468 {
5469 	int		res;
5470 
5471 	if ((res = zonecfg_sw_inventory(handle)) != Z_OK)
5472 		return (res);
5473 
5474 	if (detaching)
5475 		res = zonecfg_devwalk(handle, get_detach_dev_entry, handle);
5476 
5477 	return (res);
5478 }
5479