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