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