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