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