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