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