xref: /illumos-gate/usr/src/lib/libzonecfg/common/libzonecfg.c (revision 8f73539958be1bc23745fa29e1409be440461957)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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 
47 #include <arpa/inet.h>
48 #include <netdb.h>
49 
50 #include <priv.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 <libzonecfg.h>
59 #include "zonecfg_impl.h"
60 
61 
62 #define	_PATH_TMPFILE	"/zonecfg.XXXXXX"
63 #define	ZONE_CB_RETRY_COUNT		10
64 #define	ZONE_EVENT_PING_SUBCLASS	"ping"
65 #define	ZONE_EVENT_PING_PUBLISHER	"solaris"
66 
67 /* Hard-code the DTD element/attribute/entity names just once, here. */
68 #define	DTD_ELEM_ATTR		(const xmlChar *) "attr"
69 #define	DTD_ELEM_COMMENT	(const xmlChar *) "comment"
70 #define	DTD_ELEM_DEVICE		(const xmlChar *) "device"
71 #define	DTD_ELEM_FS		(const xmlChar *) "filesystem"
72 #define	DTD_ELEM_FSOPTION	(const xmlChar *) "fsoption"
73 #define	DTD_ELEM_IPD		(const xmlChar *) "inherited-pkg-dir"
74 #define	DTD_ELEM_NET		(const xmlChar *) "network"
75 #define	DTD_ELEM_RCTL		(const xmlChar *) "rctl"
76 #define	DTD_ELEM_RCTLVALUE	(const xmlChar *) "rctl-value"
77 #define	DTD_ELEM_ZONE		(const xmlChar *) "zone"
78 #define	DTD_ELEM_DATASET	(const xmlChar *) "dataset"
79 
80 #define	DTD_ATTR_ACTION		(const xmlChar *) "action"
81 #define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
82 #define	DTD_ATTR_AUTOBOOT	(const xmlChar *) "autoboot"
83 #define	DTD_ATTR_DIR		(const xmlChar *) "directory"
84 #define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
85 #define	DTD_ATTR_MATCH		(const xmlChar *) "match"
86 #define	DTD_ATTR_NAME		(const xmlChar *) "name"
87 #define	DTD_ATTR_PHYSICAL	(const xmlChar *) "physical"
88 #define	DTD_ATTR_POOL		(const xmlChar *) "pool"
89 #define	DTD_ATTR_PRIV		(const xmlChar *) "priv"
90 #define	DTD_ATTR_RAW		(const xmlChar *) "raw"
91 #define	DTD_ATTR_SPECIAL	(const xmlChar *) "special"
92 #define	DTD_ATTR_TYPE		(const xmlChar *) "type"
93 #define	DTD_ATTR_VALUE		(const xmlChar *) "value"
94 #define	DTD_ATTR_ZONEPATH	(const xmlChar *) "zonepath"
95 
96 #define	DTD_ENTITY_BOOLEAN	"boolean"
97 #define	DTD_ENTITY_DEVPATH	"devpath"
98 #define	DTD_ENTITY_DRIVER	"driver"
99 #define	DTD_ENTITY_DRVMIN	"drv_min"
100 #define	DTD_ENTITY_FALSE	"false"
101 #define	DTD_ENTITY_INT		"int"
102 #define	DTD_ENTITY_STRING	"string"
103 #define	DTD_ENTITY_TRUE		"true"
104 #define	DTD_ENTITY_UINT		"uint"
105 
106 #define	DTD_ENTITY_BOOL_LEN	6	/* "false" */
107 
108 struct zone_dochandle {
109 	char		*zone_dh_rootdir;
110 	xmlDocPtr	zone_dh_doc;
111 	xmlNodePtr	zone_dh_cur;
112 	xmlNodePtr	zone_dh_top;
113 	boolean_t	zone_dh_newzone;
114 	boolean_t	zone_dh_snapshot;
115 	char		zone_dh_delete_name[ZONENAME_MAX];
116 };
117 
118 struct znotify {
119 	void * zn_private;
120 	evchan_t *zn_eventchan;
121 	int (*zn_callback)(const  char *zonename, zoneid_t zid,
122 	    const char *newstate, const char *oldstate, hrtime_t when, void *p);
123 	pthread_mutex_t zn_mutex;
124 	pthread_cond_t zn_cond;
125 	pthread_mutex_t zn_bigmutex;
126 	volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
127 	    ZN_PING_RECEIVED} zn_state;
128 	char zn_subscriber_id[MAX_SUBID_LEN];
129 	volatile boolean_t zn_failed;
130 	int zn_failure_count;
131 };
132 
133 char *zonecfg_root = "";
134 
135 /*
136  * For functions which return int, which is most of the functions herein,
137  * the return values should be from the Z_foo set defined in <libzonecfg.h>.
138  * In some instances, we take pains mapping some libc errno values to Z_foo
139  * values from this set.
140  */
141 
142 /*
143  * Set the root (/) path for all zonecfg configuration files.  This is a
144  * private interface used by Live Upgrade extensions to access zone
145  * configuration inside mounted alternate boot environments.
146  */
147 void
148 zonecfg_set_root(const char *rootpath)
149 {
150 	if (*zonecfg_root != '\0')
151 		free(zonecfg_root);
152 	if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
153 	    (zonecfg_root = strdup(rootpath)) == NULL)
154 		zonecfg_root = "";
155 }
156 
157 const char *
158 zonecfg_get_root(void)
159 {
160 	return (zonecfg_root);
161 }
162 
163 boolean_t
164 zonecfg_in_alt_root(void)
165 {
166 	return (*zonecfg_root != '\0');
167 }
168 
169 /*
170  * Callers of the _file_path() functions are expected to have the second
171  * parameter be a (char foo[MAXPATHLEN]).
172  */
173 
174 static boolean_t
175 config_file_path(const char *zonename, char *answer)
176 {
177 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
178 	    ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
179 }
180 
181 static boolean_t
182 snap_file_path(const char *zonename, char *answer)
183 {
184 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
185 	    zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
186 }
187 
188 /*ARGSUSED*/
189 static void
190 zonecfg_error_func(void *ctx, const char *msg, ...)
191 {
192 	/*
193 	 * This function does nothing by design.  Its purpose is to prevent
194 	 * libxml from dumping unwanted messages to stdout/stderr.
195 	 */
196 }
197 
198 zone_dochandle_t
199 zonecfg_init_handle(void)
200 {
201 	zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
202 	if (handle == NULL) {
203 		errno = Z_NOMEM;
204 		return (NULL);
205 	}
206 
207 	/* generic libxml initialization */
208 	xmlLineNumbersDefault(1);
209 	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
210 	xmlDoValidityCheckingDefaultValue = 1;
211 	(void) xmlKeepBlanksDefault(0);
212 	xmlGetWarningsDefaultValue = 0;
213 	xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
214 
215 	return (handle);
216 }
217 
218 int
219 zonecfg_check_handle(zone_dochandle_t handle)
220 {
221 	if (handle == NULL || handle->zone_dh_doc == NULL)
222 		return (Z_BAD_HANDLE);
223 	return (Z_OK);
224 }
225 
226 void
227 zonecfg_fini_handle(zone_dochandle_t handle)
228 {
229 	if (zonecfg_check_handle(handle) == Z_OK)
230 		xmlFreeDoc(handle->zone_dh_doc);
231 	if (handle != NULL)
232 		free(handle);
233 }
234 
235 static int
236 zonecfg_destroy_impl(char *filename)
237 {
238 	if (unlink(filename) == -1) {
239 		if (errno == EACCES)
240 			return (Z_ACCES);
241 		if (errno == ENOENT)
242 			return (Z_NO_ZONE);
243 		return (Z_MISC_FS);
244 	}
245 	return (Z_OK);
246 }
247 
248 int
249 zonecfg_destroy(const char *zonename, boolean_t force)
250 {
251 	char path[MAXPATHLEN];
252 	struct zoneent ze;
253 	int err, state_err;
254 	zone_state_t state;
255 
256 	if (!config_file_path(zonename, path))
257 		return (Z_MISC_FS);
258 
259 	state_err = zone_get_state((char *)zonename, &state);
260 	err = access(path, W_OK);
261 
262 	/*
263 	 * If there is no file, and no index entry, reliably indicate that no
264 	 * such zone exists.
265 	 */
266 	if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
267 		return (Z_NO_ZONE);
268 
269 	/*
270 	 * Handle any other filesystem related errors (except if the XML
271 	 * file is missing, which we treat silently), unless we're forcing,
272 	 * in which case we plow on.
273 	 */
274 	if (err == -1 && errno != ENOENT) {
275 		if (errno == EACCES)
276 			return (Z_ACCES);
277 		else if (!force)
278 			return (Z_MISC_FS);
279 	}
280 
281 	if (state > ZONE_STATE_INSTALLED)
282 		return (Z_BAD_ZONE_STATE);
283 
284 	if (!force && state > ZONE_STATE_CONFIGURED)
285 		return (Z_BAD_ZONE_STATE);
286 
287 	/*
288 	 * Index deletion succeeds even if the entry doesn't exist.  So this
289 	 * will fail only if we've had some more severe problem.
290 	 */
291 	bzero(&ze, sizeof (ze));
292 	(void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
293 	if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
294 		if (!force)
295 			return (err);
296 
297 	err = zonecfg_destroy_impl(path);
298 
299 	/*
300 	 * Treat failure to find the XML file silently, since, well, it's
301 	 * gone, and with the index file cleaned up, we're done.
302 	 */
303 	if (err == Z_OK || err == Z_NO_ZONE)
304 		return (Z_OK);
305 	return (err);
306 }
307 
308 int
309 zonecfg_destroy_snapshot(const char *zonename)
310 {
311 	char path[MAXPATHLEN];
312 
313 	if (!snap_file_path(zonename, path))
314 		return (Z_MISC_FS);
315 	return (zonecfg_destroy_impl(path));
316 }
317 
318 static int
319 getroot(zone_dochandle_t handle, xmlNodePtr *root)
320 {
321 	if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
322 		return (Z_BAD_HANDLE);
323 
324 	*root = xmlDocGetRootElement(handle->zone_dh_doc);
325 
326 	if (*root == NULL)
327 		return (Z_EMPTY_DOCUMENT);
328 
329 	if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
330 		return (Z_WRONG_DOC_TYPE);
331 
332 	return (Z_OK);
333 }
334 
335 static int
336 operation_prep(zone_dochandle_t handle)
337 {
338 	xmlNodePtr root;
339 	int err;
340 
341 	if ((err = getroot(handle, &root)) != 0)
342 		return (err);
343 
344 	handle->zone_dh_cur = root;
345 	handle->zone_dh_top = root;
346 	return (Z_OK);
347 }
348 
349 static int
350 getrootattr(zone_dochandle_t handle, const xmlChar *propname,
351     char *propval, size_t propsize)
352 {
353 	xmlNodePtr root;
354 	xmlChar *property;
355 	size_t srcsize;
356 	int err;
357 
358 	if ((err = getroot(handle, &root)) != 0)
359 		return (err);
360 
361 	if ((property = xmlGetProp(root, propname)) == NULL)
362 		return (Z_BAD_PROPERTY);
363 	srcsize = strlcpy(propval, (char *)property, propsize);
364 	xmlFree(property);
365 	if (srcsize >= propsize)
366 		return (Z_TOO_BIG);
367 	return (Z_OK);
368 }
369 
370 static int
371 setrootattr(zone_dochandle_t handle, const xmlChar *propname,
372     const char *propval)
373 {
374 	int err;
375 	xmlNodePtr root;
376 
377 	if (propval == NULL)
378 		return (Z_INVAL);
379 
380 	if ((err = getroot(handle, &root)) != Z_OK)
381 		return (err);
382 
383 	if (xmlSetProp(root, propname, (const xmlChar *) propval) == NULL)
384 		return (Z_INVAL);
385 	return (Z_OK);
386 }
387 
388 static void
389 addcomment(zone_dochandle_t handle, const char *comment)
390 {
391 	xmlNodePtr node;
392 	node = xmlNewComment((xmlChar *) comment);
393 
394 	if (node != NULL)
395 		(void) xmlAddPrevSibling(handle->zone_dh_top, node);
396 }
397 
398 static void
399 stripcomments(zone_dochandle_t handle)
400 {
401 	xmlDocPtr top;
402 	xmlNodePtr child, next;
403 
404 	top = handle->zone_dh_doc;
405 	for (child = top->xmlChildrenNode; child != NULL; child = next) {
406 		next = child->next;
407 		if (child->name == NULL)
408 			continue;
409 		if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
410 			next = child->next;
411 			xmlUnlinkNode(child);
412 			xmlFreeNode(child);
413 		}
414 	}
415 }
416 
417 static int
418 zonecfg_get_handle_impl(const char *zonename, const char *filename,
419     zone_dochandle_t handle)
420 {
421 	xmlValidCtxtPtr cvp;
422 	struct stat statbuf;
423 	int valid;
424 
425 	if (zonename == NULL)
426 		return (Z_NO_ZONE);
427 	if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
428 		/* distinguish file not found vs. found but not parsed */
429 		if (stat(filename, &statbuf) == 0)
430 			return (Z_INVALID_DOCUMENT);
431 		return (Z_NO_ZONE);
432 	}
433 	if ((cvp = xmlNewValidCtxt()) == NULL)
434 		return (Z_NOMEM);
435 	cvp->error = zonecfg_error_func;
436 	cvp->warning = zonecfg_error_func;
437 	valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
438 	xmlFreeValidCtxt(cvp);
439 	if (valid == 0)
440 		return (Z_INVALID_DOCUMENT);
441 
442 	/* delete any comments such as inherited Sun copyright / ident str */
443 	stripcomments(handle);
444 	return (Z_OK);
445 }
446 
447 int
448 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
449 {
450 	char path[MAXPATHLEN];
451 
452 	if (!config_file_path(zonename, path))
453 		return (Z_MISC_FS);
454 	handle->zone_dh_newzone = B_FALSE;
455 
456 	return (zonecfg_get_handle_impl(zonename, path, handle));
457 }
458 
459 int
460 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
461 {
462 	char path[MAXPATHLEN];
463 
464 	if (!snap_file_path(zonename, path))
465 		return (Z_MISC_FS);
466 	handle->zone_dh_newzone = B_FALSE;
467 	return (zonecfg_get_handle_impl(zonename, path, handle));
468 }
469 
470 int
471 zonecfg_get_template_handle(const char *template, const char *zonename,
472     zone_dochandle_t handle)
473 {
474 	char path[MAXPATHLEN];
475 	int err;
476 
477 	if (!config_file_path(template, path))
478 		return (Z_MISC_FS);
479 
480 	if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
481 		return (err);
482 	handle->zone_dh_newzone = B_TRUE;
483 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
484 }
485 
486 static boolean_t
487 is_renaming(zone_dochandle_t handle)
488 {
489 	if (handle->zone_dh_newzone)
490 		return (B_FALSE);
491 	if (strlen(handle->zone_dh_delete_name) > 0)
492 		return (B_TRUE);
493 	return (B_FALSE);
494 }
495 
496 static boolean_t
497 is_new(zone_dochandle_t handle)
498 {
499 	return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
500 }
501 
502 static boolean_t
503 is_snapshot(zone_dochandle_t handle)
504 {
505 	return (handle->zone_dh_snapshot);
506 }
507 
508 /*
509  * It would be great to be able to use libc's ctype(3c) macros, but we
510  * can't, as they are locale sensitive, and it would break our limited thread
511  * safety if this routine had to change the app locale on the fly.
512  */
513 int
514 zonecfg_validate_zonename(const char *zone)
515 {
516 	int i;
517 
518 	if (strcmp(zone, GLOBAL_ZONENAME) == 0)
519 		return (Z_BOGUS_ZONE_NAME);
520 
521 	if (strlen(zone) >= ZONENAME_MAX)
522 		return (Z_BOGUS_ZONE_NAME);
523 
524 	if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
525 	    (zone[0] >= 'A' && zone[0] <= 'Z') ||
526 	    (zone[0] >= '0' && zone[0] <= '9')))
527 		return (Z_BOGUS_ZONE_NAME);
528 
529 	for (i = 1; zone[i] != '\0'; i++) {
530 		if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
531 		    (zone[i] >= 'A' && zone[i] <= 'Z') ||
532 		    (zone[i] >= '0' && zone[i] <= '9') ||
533 		    (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
534 			return (Z_BOGUS_ZONE_NAME);
535 	}
536 
537 	return (Z_OK);
538 }
539 
540 /*
541  * Changing the zone name requires us to track both the old and new
542  * name of the zone until commit time.
543  */
544 int
545 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
546 {
547 	return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
548 }
549 
550 int
551 zonecfg_set_name(zone_dochandle_t handle, char *name)
552 {
553 	zone_state_t state;
554 	char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
555 	int err;
556 
557 	if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
558 	    sizeof (curname))) != Z_OK)
559 		return (err);
560 
561 	if (strcmp(name, curname) == 0)
562 		return (Z_OK);
563 
564 	/*
565 	 * Switching zone names to one beginning with SUNW is not permitted.
566 	 */
567 	if (strncmp(name, "SUNW", 4) == 0)
568 		return (Z_BOGUS_ZONE_NAME);
569 
570 	if ((err = zonecfg_validate_zonename(name)) != Z_OK)
571 		return (err);
572 
573 	/*
574 	 * Setting the name back to the original name (effectively a revert of
575 	 * the name) is fine.  But if we carry on, we'll falsely identify the
576 	 * name as "in use," so special case here.
577 	 */
578 	if (strcmp(name, handle->zone_dh_delete_name) == 0) {
579 		err = setrootattr(handle, DTD_ATTR_NAME, name);
580 		handle->zone_dh_delete_name[0] = '\0';
581 		return (err);
582 	}
583 
584 	/* Check to see if new name chosen is already in use */
585 	if (zone_get_state(name, &state) != Z_NO_ZONE)
586 		return (Z_NAME_IN_USE);
587 
588 	/*
589 	 * If this isn't already "new" or in a renaming transition, then
590 	 * we're initiating a rename here; so stash the "delete name"
591 	 * (i.e. the name of the zone we'll be removing) for the rename.
592 	 */
593 	(void) strlcpy(old_delname, handle->zone_dh_delete_name,
594 	    sizeof (old_delname));
595 	if (!is_new(handle) && !is_renaming(handle)) {
596 		/*
597 		 * Name change is allowed only when the zone we're altering
598 		 * is not ready or running.
599 		 */
600 		err = zone_get_state(curname, &state);
601 		if (err == Z_OK) {
602 			if (state > ZONE_STATE_INSTALLED)
603 				return (Z_BAD_ZONE_STATE);
604 		} else if (err != Z_NO_ZONE) {
605 			return (err);
606 		}
607 
608 		(void) strlcpy(handle->zone_dh_delete_name, curname,
609 		    sizeof (handle->zone_dh_delete_name));
610 		assert(is_renaming(handle));
611 	} else if (is_renaming(handle)) {
612 		err = zone_get_state(handle->zone_dh_delete_name, &state);
613 		if (err == Z_OK) {
614 			if (state > ZONE_STATE_INSTALLED)
615 				return (Z_BAD_ZONE_STATE);
616 		} else if (err != Z_NO_ZONE) {
617 			return (err);
618 		}
619 	}
620 
621 	if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
622 		/*
623 		 * Restore the deletename to whatever it was at the
624 		 * top of the routine, since we've had a failure.
625 		 */
626 		(void) strlcpy(handle->zone_dh_delete_name, old_delname,
627 		    sizeof (handle->zone_dh_delete_name));
628 		return (err);
629 	}
630 
631 	return (Z_OK);
632 }
633 
634 int
635 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
636 {
637 	size_t len;
638 
639 	if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize)
640 		return (Z_TOO_BIG);
641 	return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len,
642 	    pathsize - len));
643 }
644 
645 int
646 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
647 {
648 	return (setrootattr(handle, DTD_ATTR_ZONEPATH, zonepath));
649 }
650 
651 int
652 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
653 {
654 	char autobootstr[DTD_ENTITY_BOOL_LEN];
655 	int ret;
656 
657 	if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
658 	    sizeof (autobootstr))) != Z_OK)
659 		return (ret);
660 
661 	if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
662 		*autoboot = B_TRUE;
663 	else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
664 		*autoboot = B_FALSE;
665 	else
666 		ret = Z_BAD_PROPERTY;
667 	return (ret);
668 }
669 
670 int
671 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
672 {
673 	return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
674 	    autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
675 }
676 
677 int
678 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
679 {
680 	return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
681 }
682 
683 int
684 zonecfg_set_pool(zone_dochandle_t handle, char *pool)
685 {
686 	return (setrootattr(handle, DTD_ATTR_POOL, pool));
687 }
688 
689 /*
690  * /etc/zones/index caches a vital piece of information which is also
691  * in the <zonename>.xml file: the path to the zone.  This is for performance,
692  * since we need to walk all zonepath's in order to be able to detect conflicts
693  * (see crosscheck_zonepaths() in the zoneadm command).
694  *
695  * An additional complexity is that when doing a rename, we'd like the entire
696  * index update operation (rename, and potential state changes) to be atomic.
697  * In general, the operation of this function should succeed or fail as
698  * a unit.
699  */
700 int
701 zonecfg_refresh_index_file(zone_dochandle_t handle)
702 {
703 	char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
704 	struct zoneent ze;
705 	int err;
706 	int opcode;
707 	char *zn;
708 
709 	bzero(&ze, sizeof (ze));
710 	ze.zone_state = -1;	/* Preserve existing state in index */
711 
712 	if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
713 		return (err);
714 	(void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
715 
716 	if ((err = zonecfg_get_zonepath(handle, zonepath,
717 	    sizeof (zonepath))) != Z_OK)
718 		return (err);
719 	(void) strlcpy(ze.zone_path, zonepath, sizeof (ze.zone_path));
720 
721 	if (is_renaming(handle)) {
722 		opcode = PZE_MODIFY;
723 		(void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
724 		    sizeof (ze.zone_name));
725 		(void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
726 	} else if (is_new(handle)) {
727 		FILE *cookie;
728 		/*
729 		 * Be tolerant of the zone already existing in the index file,
730 		 * since we might be forcibly overwriting an existing
731 		 * configuration with a new one (for example 'create -F'
732 		 * in zonecfg).
733 		 */
734 		opcode = PZE_ADD;
735 		cookie = setzoneent();
736 		while ((zn = getzoneent(cookie)) != NULL) {
737 			if (strcmp(zn, name) == 0) {
738 				opcode = PZE_MODIFY;
739 				free(zn);
740 				break;
741 			}
742 			free(zn);
743 		}
744 		endzoneent(cookie);
745 		ze.zone_state = ZONE_STATE_CONFIGURED;
746 	} else {
747 		opcode = PZE_MODIFY;
748 	}
749 
750 	if ((err = putzoneent(&ze, opcode)) != Z_OK)
751 		return (err);
752 
753 	return (Z_OK);
754 }
755 
756 /*
757  * The goal of this routine is to cause the index file update and the
758  * document save to happen as an atomic operation.  We do the document
759  * first, saving a backup copy using a hard link; if that succeeds, we go
760  * on to the index.  If that fails, we roll the document back into place.
761  *
762  * Strategy:
763  *
764  * New zone 'foo' configuration:
765  * 	Create tmpfile (zonecfg.xxxxxx)
766  * 	Write XML to tmpfile
767  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
768  * 	Add entry to index file
769  * 	If it fails, delete foo.xml, leaving nothing behind.
770  *
771  * Save existing zone 'foo':
772  * 	Make backup of foo.xml -> .backup
773  * 	Create tmpfile (zonecfg.xxxxxx)
774  * 	Write XML to tmpfile
775  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
776  * 	Modify index file as needed
777  * 	If it fails, recover from .backup -> foo.xml
778  *
779  * Rename 'foo' to 'bar':
780  * 	Create tmpfile (zonecfg.xxxxxx)
781  * 	Write XML to tmpfile
782  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
783  * 	Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
784  * 	If it fails, delete bar.xml; foo.xml is left behind.
785  */
786 static int
787 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
788 {
789 	char tmpfile[MAXPATHLEN];
790 	char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
791 	int tmpfd, err;
792 	xmlValidCtxt cvp = { NULL };
793 	boolean_t backup;
794 
795 	(void) strlcpy(tmpfile, filename, sizeof (tmpfile));
796 	(void) dirname(tmpfile);
797 	(void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
798 
799 	tmpfd = mkstemp(tmpfile);
800 	if (tmpfd == -1) {
801 		(void) unlink(tmpfile);
802 		return (Z_TEMP_FILE);
803 	}
804 	(void) close(tmpfd);
805 
806 	cvp.error = zonecfg_error_func;
807 	cvp.warning = zonecfg_error_func;
808 
809 	/*
810 	 * We do a final validation of the document-- but the library has
811 	 * malfunctioned if it fails to validate, so it's an assert.
812 	 */
813 	assert(xmlValidateDocument(&cvp, handle->zone_dh_doc) != 0);
814 
815 	if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
816 		goto err;
817 
818 	(void) chmod(tmpfile, 0644);
819 
820 	/*
821 	 * In the event we are doing a standard save, hard link a copy of the
822 	 * original file in .backup.<pid>.filename so we can restore it if
823 	 * something goes wrong.
824 	 */
825 	if (!is_new(handle) && !is_renaming(handle)) {
826 		backup = B_TRUE;
827 
828 		(void) strlcpy(bakdir, filename, sizeof (bakdir));
829 		(void) strlcpy(bakbase, filename, sizeof (bakbase));
830 		(void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
831 		    dirname(bakdir), getpid(), basename(bakbase));
832 
833 		if (link(filename, bakfile) == -1) {
834 			err = errno;
835 			(void) unlink(tmpfile);
836 			if (errno == EACCES)
837 				return (Z_ACCES);
838 			return (Z_MISC_FS);
839 		}
840 	}
841 
842 	/*
843 	 * Move the new document over top of the old.
844 	 * i.e.:   zonecfg.XXXXXX  ->  myzone.xml
845 	 */
846 	if (rename(tmpfile, filename) == -1) {
847 		err = errno;
848 		(void) unlink(tmpfile);
849 		if (backup)
850 			(void) unlink(bakfile);
851 		if (err == EACCES)
852 			return (Z_ACCES);
853 		return (Z_MISC_FS);
854 	}
855 
856 	/*
857 	 * If this is a snapshot, we're done-- don't add an index entry.
858 	 */
859 	if (is_snapshot(handle))
860 		return (Z_OK);
861 
862 	/* now update the index file to reflect whatever we just did */
863 	if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
864 		if (backup) {
865 			/*
866 			 * Try to restore from our backup.
867 			 */
868 			(void) unlink(filename);
869 			(void) rename(bakfile, filename);
870 		} else {
871 			/*
872 			 * Either the zone is new, in which case we can delete
873 			 * new.xml, or we're doing a rename, so ditto.
874 			 */
875 			assert(is_new(handle) || is_renaming(handle));
876 			(void) unlink(filename);
877 		}
878 		return (Z_UPDATING_INDEX);
879 	}
880 
881 	if (backup)
882 		(void) unlink(bakfile);
883 
884 	return (Z_OK);
885 
886 err:
887 	(void) unlink(tmpfile);
888 	return (Z_SAVING_FILE);
889 }
890 
891 int
892 zonecfg_save(zone_dochandle_t handle)
893 {
894 	char zname[ZONENAME_MAX], path[MAXPATHLEN];
895 	char delpath[MAXPATHLEN];
896 	int err = Z_SAVING_FILE;
897 
898 	if (zonecfg_check_handle(handle) != Z_OK)
899 		return (Z_BAD_HANDLE);
900 
901 	/*
902 	 * We don't support saving snapshots at this time.
903 	 */
904 	if (handle->zone_dh_snapshot)
905 		return (Z_INVAL);
906 
907 	if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
908 		return (err);
909 
910 	if (!config_file_path(zname, path))
911 		return (Z_MISC_FS);
912 
913 	addcomment(handle, "\n    DO NOT EDIT THIS "
914 	    "FILE.  Use zonecfg(1M) instead.\n");
915 
916 	err = zonecfg_save_impl(handle, path);
917 
918 	stripcomments(handle);
919 
920 	if (err != Z_OK)
921 		return (err);
922 
923 	handle->zone_dh_newzone = B_FALSE;
924 
925 	if (is_renaming(handle)) {
926 		if (config_file_path(handle->zone_dh_delete_name, delpath))
927 			(void) unlink(delpath);
928 		handle->zone_dh_delete_name[0] = '\0';
929 	}
930 
931 	return (Z_OK);
932 }
933 
934 /*
935  * Special case: if access(2) fails with ENOENT, then try again using
936  * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
937  * work around the case of a config file which has not been created yet:
938  * the user will need access to the directory so use that as a heuristic.
939  */
940 
941 int
942 zonecfg_access(const char *zonename, int amode)
943 {
944 	char path[MAXPATHLEN];
945 
946 	if (!config_file_path(zonename, path))
947 		return (Z_INVAL);
948 	if (access(path, amode) == 0)
949 		return (Z_OK);
950 	if (errno == ENOENT) {
951 		if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
952 		    ZONE_CONFIG_ROOT) >= sizeof (path))
953 			return (Z_INVAL);
954 		if (access(path, amode) == 0)
955 			return (Z_OK);
956 	}
957 	if (errno == EACCES)
958 		return (Z_ACCES);
959 	if (errno == EINVAL)
960 		return (Z_INVAL);
961 	return (Z_MISC_FS);
962 }
963 
964 int
965 zonecfg_create_snapshot(const char *zonename)
966 {
967 	zone_dochandle_t handle;
968 	char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
969 	int error = Z_OK, res;
970 
971 	if ((handle = zonecfg_init_handle()) == NULL) {
972 		return (Z_NOMEM);
973 	}
974 
975 	handle->zone_dh_newzone = B_TRUE;
976 	handle->zone_dh_snapshot = B_TRUE;
977 
978 	if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
979 		goto out;
980 	if ((error = operation_prep(handle)) != Z_OK)
981 		goto out;
982 	error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
983 	if (error != Z_OK)
984 		goto out;
985 	if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
986 		error = Z_RESOLVED_PATH;
987 		goto out;
988 	}
989 	/*
990 	 * If the resolved path is not the same as the original path, then
991 	 * save the resolved path in the snapshot, thus preventing any
992 	 * potential problems down the line when zoneadmd goes to unmount
993 	 * file systems and depends on initial string matches with resolved
994 	 * paths.
995 	 */
996 	rpath[res] = '\0';
997 	if (strcmp(zonepath, rpath) != 0) {
998 		if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
999 			goto out;
1000 	}
1001 	if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1002 	    ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1003 		error = Z_MISC_FS;
1004 		goto out;
1005 	}
1006 	if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1007 		error = Z_MISC_FS;
1008 		goto out;
1009 	}
1010 
1011 	if (!snap_file_path(zonename, path)) {
1012 		error = Z_MISC_FS;
1013 		goto out;
1014 	}
1015 
1016 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1017 	    "It is a snapshot of running zone state.\n");
1018 
1019 	error = zonecfg_save_impl(handle, path);
1020 
1021 	stripcomments(handle);
1022 
1023 out:
1024 	zonecfg_fini_handle(handle);
1025 	return (error);
1026 }
1027 
1028 static int
1029 newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
1030 {
1031 	xmlAttrPtr newattr;
1032 
1033 	newattr = xmlNewProp(node, attrname, (xmlChar *)src);
1034 	if (newattr == NULL) {
1035 		xmlUnlinkNode(node);
1036 		xmlFreeNode(node);
1037 		return (Z_BAD_PROPERTY);
1038 	}
1039 	return (Z_OK);
1040 }
1041 
1042 static int
1043 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1044 {
1045 	xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
1046 	zone_fsopt_t *ptr;
1047 	int err;
1048 
1049 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
1050 	if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
1051 	    tabptr->zone_fs_special)) != Z_OK)
1052 		return (err);
1053 	if (tabptr->zone_fs_raw[0] != '\0' &&
1054 	    (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
1055 		return (err);
1056 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1057 		return (err);
1058 	if ((err = newprop(newnode, DTD_ATTR_TYPE,
1059 	    tabptr->zone_fs_type)) != Z_OK)
1060 		return (err);
1061 	if (tabptr->zone_fs_options != NULL) {
1062 		for (ptr = tabptr->zone_fs_options; ptr != NULL;
1063 		    ptr = ptr->zone_fsopt_next) {
1064 			options_node = xmlNewTextChild(newnode, NULL,
1065 			    DTD_ELEM_FSOPTION, NULL);
1066 			if ((err = newprop(options_node, DTD_ATTR_NAME,
1067 			    ptr->zone_fsopt_opt)) != Z_OK)
1068 				return (err);
1069 		}
1070 	}
1071 	return (Z_OK);
1072 }
1073 
1074 int
1075 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1076 {
1077 	int err;
1078 
1079 	if (tabptr == NULL)
1080 		return (Z_INVAL);
1081 
1082 	if ((err = operation_prep(handle)) != Z_OK)
1083 		return (err);
1084 
1085 	if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
1086 		return (err);
1087 
1088 	return (Z_OK);
1089 }
1090 
1091 static int
1092 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1093 {
1094 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
1095 	int err;
1096 
1097 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL);
1098 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1099 		return (err);
1100 	return (Z_OK);
1101 }
1102 
1103 int
1104 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
1105 {
1106 	int err;
1107 
1108 	if (tabptr == NULL)
1109 		return (Z_INVAL);
1110 
1111 	if ((err = operation_prep(handle)) != Z_OK)
1112 		return (err);
1113 
1114 	if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK)
1115 		return (err);
1116 
1117 	return (Z_OK);
1118 }
1119 
1120 int
1121 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
1122 {
1123 	zone_fsopt_t *last, *old, *new;
1124 
1125 	last = tabptr->zone_fs_options;
1126 	for (old = last; old != NULL; old = old->zone_fsopt_next)
1127 		last = old;	/* walk to the end of the list */
1128 	new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
1129 	if (new == NULL)
1130 		return (Z_NOMEM);
1131 	(void) strlcpy(new->zone_fsopt_opt, option,
1132 	    sizeof (new->zone_fsopt_opt));
1133 	new->zone_fsopt_next = NULL;
1134 	if (last == NULL)
1135 		tabptr->zone_fs_options = new;
1136 	else
1137 		last->zone_fsopt_next = new;
1138 	return (Z_OK);
1139 }
1140 
1141 int
1142 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
1143 {
1144 	zone_fsopt_t *last, *this, *next;
1145 
1146 	last = tabptr->zone_fs_options;
1147 	for (this = last; this != NULL; this = this->zone_fsopt_next) {
1148 		if (strcmp(this->zone_fsopt_opt, option) == 0) {
1149 			next = this->zone_fsopt_next;
1150 			if (this == tabptr->zone_fs_options)
1151 				tabptr->zone_fs_options = next;
1152 			else
1153 				last->zone_fsopt_next = next;
1154 			free(this);
1155 			return (Z_OK);
1156 		} else
1157 			last = this;
1158 	}
1159 	return (Z_NO_PROPERTY_ID);
1160 }
1161 
1162 void
1163 zonecfg_free_fs_option_list(zone_fsopt_t *list)
1164 {
1165 	zone_fsopt_t *this, *next;
1166 
1167 	for (this = list; this != NULL; this = next) {
1168 		next = this->zone_fsopt_next;
1169 		free(this);
1170 	}
1171 }
1172 
1173 void
1174 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
1175 {
1176 	if (valtab == NULL)
1177 		return;
1178 	zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
1179 	free(valtab);
1180 }
1181 
1182 static boolean_t
1183 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
1184 {
1185 	xmlChar *gotten_prop;
1186 	int prop_result;
1187 
1188 	gotten_prop = xmlGetProp(cur, attr);
1189 	if (gotten_prop == NULL)	/* shouldn't happen */
1190 		return (B_FALSE);
1191 	prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
1192 	xmlFree(gotten_prop);
1193 	return ((prop_result == 0));
1194 }
1195 
1196 static int
1197 zonecfg_delete_filesystem_core(zone_dochandle_t handle,
1198     struct zone_fstab *tabptr)
1199 {
1200 	xmlNodePtr cur = handle->zone_dh_cur;
1201 	boolean_t dir_match, spec_match, raw_match, type_match;
1202 
1203 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1204 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1205 			continue;
1206 		dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
1207 		spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
1208 		    tabptr->zone_fs_special);
1209 		raw_match = match_prop(cur, DTD_ATTR_RAW,
1210 		    tabptr->zone_fs_raw);
1211 		type_match = match_prop(cur, DTD_ATTR_TYPE,
1212 		    tabptr->zone_fs_type);
1213 		if (dir_match && spec_match && raw_match && type_match) {
1214 			xmlUnlinkNode(cur);
1215 			xmlFreeNode(cur);
1216 			return (Z_OK);
1217 		}
1218 	}
1219 	return (Z_NO_RESOURCE_ID);
1220 }
1221 
1222 int
1223 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1224 {
1225 	int err;
1226 
1227 	if (tabptr == NULL)
1228 		return (Z_INVAL);
1229 
1230 	if ((err = operation_prep(handle)) != Z_OK)
1231 		return (err);
1232 
1233 	if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
1234 		return (err);
1235 
1236 	return (Z_OK);
1237 }
1238 
1239 int
1240 zonecfg_modify_filesystem(
1241 	zone_dochandle_t handle,
1242 	struct zone_fstab *oldtabptr,
1243 	struct zone_fstab *newtabptr)
1244 {
1245 	int err;
1246 
1247 	if (oldtabptr == NULL || newtabptr == NULL)
1248 		return (Z_INVAL);
1249 
1250 	if ((err = operation_prep(handle)) != Z_OK)
1251 		return (err);
1252 
1253 	if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
1254 		return (err);
1255 
1256 	if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
1257 		return (err);
1258 
1259 	return (Z_OK);
1260 }
1261 
1262 static int
1263 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1264 {
1265 	xmlNodePtr cur = handle->zone_dh_cur;
1266 
1267 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1268 		if (xmlStrcmp(cur->name, DTD_ELEM_IPD))
1269 			continue;
1270 		if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) {
1271 			xmlUnlinkNode(cur);
1272 			xmlFreeNode(cur);
1273 			return (Z_OK);
1274 		}
1275 	}
1276 	return (Z_NO_RESOURCE_ID);
1277 }
1278 
1279 int
1280 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
1281 {
1282 	int err;
1283 
1284 	if (tabptr == NULL)
1285 		return (Z_INVAL);
1286 
1287 	if ((err = operation_prep(handle)) != Z_OK)
1288 		return (err);
1289 
1290 	if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK)
1291 		return (err);
1292 
1293 	return (Z_OK);
1294 }
1295 
1296 int
1297 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr,
1298     struct zone_fstab *newtabptr)
1299 {
1300 	int err;
1301 
1302 	if (oldtabptr == NULL || newtabptr == NULL)
1303 		return (Z_INVAL);
1304 
1305 	if ((err = operation_prep(handle)) != Z_OK)
1306 		return (err);
1307 
1308 	if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK)
1309 		return (err);
1310 
1311 	if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK)
1312 		return (err);
1313 
1314 	return (Z_OK);
1315 }
1316 
1317 static int
1318 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
1319 {
1320 	xmlChar *property;
1321 	size_t srcsize;
1322 
1323 	if ((property = xmlGetProp(cur, propname)) == NULL)
1324 		return (Z_BAD_PROPERTY);
1325 	srcsize = strlcpy(dst, (char *)property, dstsize);
1326 	xmlFree(property);
1327 	if (srcsize >= dstsize)
1328 		return (Z_TOO_BIG);
1329 	return (Z_OK);
1330 }
1331 
1332 int
1333 zonecfg_lookup_filesystem(
1334 	zone_dochandle_t handle,
1335 	struct zone_fstab *tabptr)
1336 {
1337 	xmlNodePtr cur, options, firstmatch;
1338 	int err;
1339 	char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
1340 	char type[FSTYPSZ];
1341 	char options_str[MAX_MNTOPT_STR];
1342 
1343 	if (tabptr == NULL)
1344 		return (Z_INVAL);
1345 
1346 	if ((err = operation_prep(handle)) != Z_OK)
1347 		return (err);
1348 
1349 	/*
1350 	 * Walk the list of children looking for matches on any properties
1351 	 * specified in the fstab parameter.  If more than one resource
1352 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1353 	 * Z_NO_RESOURCE_ID.
1354 	 */
1355 	cur = handle->zone_dh_cur;
1356 	firstmatch = NULL;
1357 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1358 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1359 			continue;
1360 		if (strlen(tabptr->zone_fs_dir) > 0) {
1361 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1362 			    sizeof (dirname)) == Z_OK) &&
1363 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1364 				if (firstmatch == NULL)
1365 					firstmatch = cur;
1366 				else
1367 					return (Z_INSUFFICIENT_SPEC);
1368 			}
1369 		}
1370 		if (strlen(tabptr->zone_fs_special) > 0) {
1371 			if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
1372 			    sizeof (special)) == Z_OK)) {
1373 				if (strcmp(tabptr->zone_fs_special,
1374 				    special) == 0) {
1375 					if (firstmatch == NULL)
1376 						firstmatch = cur;
1377 					else if (firstmatch != cur)
1378 						return (Z_INSUFFICIENT_SPEC);
1379 				} else {
1380 					/*
1381 					 * If another property matched but this
1382 					 * one doesn't then reset firstmatch.
1383 					 */
1384 					if (firstmatch == cur)
1385 						firstmatch = NULL;
1386 				}
1387 			}
1388 		}
1389 		if (strlen(tabptr->zone_fs_raw) > 0) {
1390 			if ((fetchprop(cur, DTD_ATTR_RAW, raw,
1391 			    sizeof (raw)) == Z_OK)) {
1392 				if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
1393 					if (firstmatch == NULL)
1394 						firstmatch = cur;
1395 					else if (firstmatch != cur)
1396 						return (Z_INSUFFICIENT_SPEC);
1397 				} else {
1398 					/*
1399 					 * If another property matched but this
1400 					 * one doesn't then reset firstmatch.
1401 					 */
1402 					if (firstmatch == cur)
1403 						firstmatch = NULL;
1404 				}
1405 			}
1406 		}
1407 		if (strlen(tabptr->zone_fs_type) > 0) {
1408 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
1409 			    sizeof (type)) == Z_OK)) {
1410 				if (strcmp(tabptr->zone_fs_type, type) == 0) {
1411 					if (firstmatch == NULL)
1412 						firstmatch = cur;
1413 					else if (firstmatch != cur)
1414 						return (Z_INSUFFICIENT_SPEC);
1415 				} else {
1416 					/*
1417 					 * If another property matched but this
1418 					 * one doesn't then reset firstmatch.
1419 					 */
1420 					if (firstmatch == cur)
1421 						firstmatch = NULL;
1422 				}
1423 			}
1424 		}
1425 	}
1426 
1427 	if (firstmatch == NULL)
1428 		return (Z_NO_RESOURCE_ID);
1429 
1430 	cur = firstmatch;
1431 
1432 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1433 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
1434 		return (err);
1435 
1436 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
1437 	    sizeof (tabptr->zone_fs_special))) != Z_OK)
1438 		return (err);
1439 
1440 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
1441 	    sizeof (tabptr->zone_fs_raw))) != Z_OK)
1442 		return (err);
1443 
1444 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
1445 	    sizeof (tabptr->zone_fs_type))) != Z_OK)
1446 		return (err);
1447 
1448 	/* options are optional */
1449 	tabptr->zone_fs_options = NULL;
1450 	for (options = cur->xmlChildrenNode; options != NULL;
1451 	    options = options->next) {
1452 		if ((fetchprop(options, DTD_ATTR_NAME, options_str,
1453 		    sizeof (options_str)) != Z_OK))
1454 			break;
1455 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
1456 			break;
1457 	}
1458 	return (Z_OK);
1459 }
1460 
1461 int
1462 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
1463 {
1464 	xmlNodePtr cur, match;
1465 	int err;
1466 	char dirname[MAXPATHLEN];
1467 
1468 	if (tabptr == NULL)
1469 		return (Z_INVAL);
1470 
1471 	if ((err = operation_prep(handle)) != Z_OK)
1472 		return (err);
1473 
1474 	/*
1475 	 * General algorithm:
1476 	 * Walk the list of children looking for matches on any properties
1477 	 * specified in the fstab parameter.  If more than one resource
1478 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1479 	 * Z_NO_RESOURCE_ID.
1480 	 */
1481 	cur = handle->zone_dh_cur;
1482 	match = NULL;
1483 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1484 		if (xmlStrcmp(cur->name, DTD_ELEM_IPD))
1485 			continue;
1486 		if (strlen(tabptr->zone_fs_dir) > 0) {
1487 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1488 			    sizeof (dirname)) == Z_OK) &&
1489 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1490 				if (match == NULL)
1491 					match = cur;
1492 				else
1493 					return (Z_INSUFFICIENT_SPEC);
1494 			}
1495 		}
1496 	}
1497 
1498 	if (match == NULL)
1499 		return (Z_NO_RESOURCE_ID);
1500 
1501 	cur = match;
1502 
1503 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1504 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
1505 		return (err);
1506 
1507 	return (Z_OK);
1508 }
1509 
1510 /*
1511  * Compare two IP addresses in string form.  Allow for the possibility that
1512  * one might have "/<prefix-length>" at the end: allow a match on just the
1513  * IP address (or host name) part.
1514  */
1515 
1516 boolean_t
1517 zonecfg_same_net_address(char *a1, char *a2)
1518 {
1519 	char *slashp, *slashp1, *slashp2;
1520 	int result;
1521 
1522 	if (strcmp(a1, a2) == 0)
1523 		return (B_TRUE);
1524 
1525 	/*
1526 	 * If neither has a slash or both do, they need to match to be
1527 	 * considered the same, but they did not match above, so fail.
1528 	 */
1529 	slashp1 = strchr(a1, '/');
1530 	slashp2 = strchr(a2, '/');
1531 	if ((slashp1 == NULL && slashp2 == NULL) ||
1532 	    (slashp1 != NULL && slashp2 != NULL))
1533 		return (B_FALSE);
1534 
1535 	/*
1536 	 * Only one had a slash: pick that one, zero out the slash, compare
1537 	 * the "address only" strings, restore the slash, and return the
1538 	 * result of the comparison.
1539 	 */
1540 	slashp = (slashp1 == NULL) ? slashp2 : slashp1;
1541 	*slashp = '\0';
1542 	result = strcmp(a1, a2);
1543 	*slashp = '/';
1544 	return ((result == 0));
1545 }
1546 
1547 int
1548 zonecfg_valid_net_address(char *address, struct lifreq *lifr)
1549 {
1550 	struct sockaddr_in *sin4;
1551 	struct sockaddr_in6 *sin6;
1552 	struct addrinfo hints, *result;
1553 	char *slashp = strchr(address, '/');
1554 
1555 	bzero(lifr, sizeof (struct lifreq));
1556 	sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
1557 	sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
1558 	if (slashp != NULL)
1559 		*slashp = '\0';
1560 	if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
1561 		sin4->sin_family = AF_INET;
1562 	} else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
1563 		if (slashp == NULL)
1564 			return (Z_IPV6_ADDR_PREFIX_LEN);
1565 		sin6->sin6_family = AF_INET6;
1566 	} else {
1567 		/* "address" may be a host name */
1568 		(void) memset(&hints, 0, sizeof (hints));
1569 		hints.ai_family = PF_INET;
1570 		if (getaddrinfo(address, NULL, &hints, &result) != 0)
1571 			return (Z_BOGUS_ADDRESS);
1572 		sin4->sin_family = result->ai_family;
1573 
1574 		(void) memcpy(&sin4->sin_addr,
1575 		    /* LINTED E_BAD_PTR_CAST_ALIGN */
1576 		    &((struct sockaddr_in *)result->ai_addr)->sin_addr,
1577 		    sizeof (struct in_addr));
1578 
1579 		freeaddrinfo(result);
1580 	}
1581 	return (Z_OK);
1582 }
1583 
1584 int
1585 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1586 {
1587 	xmlNodePtr cur, firstmatch;
1588 	int err;
1589 	char address[INET6_ADDRSTRLEN], physical[LIFNAMSIZ];
1590 
1591 	if (tabptr == NULL)
1592 		return (Z_INVAL);
1593 
1594 	if ((err = operation_prep(handle)) != Z_OK)
1595 		return (err);
1596 
1597 	cur = handle->zone_dh_cur;
1598 	firstmatch = NULL;
1599 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1600 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
1601 			continue;
1602 		if (strlen(tabptr->zone_nwif_physical) > 0) {
1603 			if ((fetchprop(cur, DTD_ATTR_PHYSICAL, physical,
1604 			    sizeof (physical)) == Z_OK) &&
1605 			    (strcmp(tabptr->zone_nwif_physical,
1606 			    physical) == 0)) {
1607 				if (firstmatch == NULL)
1608 					firstmatch = cur;
1609 				else
1610 					return (Z_INSUFFICIENT_SPEC);
1611 			}
1612 		}
1613 		if (strlen(tabptr->zone_nwif_address) > 0) {
1614 			if ((fetchprop(cur, DTD_ATTR_ADDRESS, address,
1615 			    sizeof (address)) == Z_OK)) {
1616 				if (zonecfg_same_net_address(
1617 				    tabptr->zone_nwif_address, address)) {
1618 					if (firstmatch == NULL)
1619 						firstmatch = cur;
1620 					else if (firstmatch != cur)
1621 						return (Z_INSUFFICIENT_SPEC);
1622 				} else {
1623 					/*
1624 					 * If another property matched but this
1625 					 * one doesn't then reset firstmatch.
1626 					 */
1627 					if (firstmatch == cur)
1628 						firstmatch = NULL;
1629 				}
1630 			}
1631 		}
1632 	}
1633 	if (firstmatch == NULL)
1634 		return (Z_NO_RESOURCE_ID);
1635 
1636 	cur = firstmatch;
1637 
1638 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
1639 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK)
1640 		return (err);
1641 
1642 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
1643 	    sizeof (tabptr->zone_nwif_address))) != Z_OK)
1644 		return (err);
1645 
1646 	return (Z_OK);
1647 }
1648 
1649 static int
1650 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1651 {
1652 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
1653 	int err;
1654 
1655 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
1656 	if ((err = newprop(newnode, DTD_ATTR_ADDRESS,
1657 	    tabptr->zone_nwif_address)) != Z_OK)
1658 		return (err);
1659 	if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
1660 	    tabptr->zone_nwif_physical)) != Z_OK)
1661 		return (err);
1662 	return (Z_OK);
1663 }
1664 
1665 int
1666 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1667 {
1668 	int err;
1669 
1670 	if (tabptr == NULL)
1671 		return (Z_INVAL);
1672 
1673 	if ((err = operation_prep(handle)) != Z_OK)
1674 		return (err);
1675 
1676 	if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
1677 		return (err);
1678 
1679 	return (Z_OK);
1680 }
1681 
1682 static int
1683 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1684 {
1685 	xmlNodePtr cur = handle->zone_dh_cur;
1686 	boolean_t addr_match, phys_match;
1687 
1688 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1689 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
1690 			continue;
1691 
1692 		addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
1693 		    tabptr->zone_nwif_address);
1694 		phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
1695 		    tabptr->zone_nwif_physical);
1696 
1697 		if (addr_match && phys_match) {
1698 			xmlUnlinkNode(cur);
1699 			xmlFreeNode(cur);
1700 			return (Z_OK);
1701 		}
1702 	}
1703 	return (Z_NO_RESOURCE_ID);
1704 }
1705 
1706 int
1707 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1708 {
1709 	int err;
1710 
1711 	if (tabptr == NULL)
1712 		return (Z_INVAL);
1713 
1714 	if ((err = operation_prep(handle)) != Z_OK)
1715 		return (err);
1716 
1717 	if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
1718 		return (err);
1719 
1720 	return (Z_OK);
1721 }
1722 
1723 int
1724 zonecfg_modify_nwif(
1725 	zone_dochandle_t handle,
1726 	struct zone_nwiftab *oldtabptr,
1727 	struct zone_nwiftab *newtabptr)
1728 {
1729 	int err;
1730 
1731 	if (oldtabptr == NULL || newtabptr == NULL)
1732 		return (Z_INVAL);
1733 
1734 	if ((err = operation_prep(handle)) != Z_OK)
1735 		return (err);
1736 
1737 	if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
1738 		return (err);
1739 
1740 	if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
1741 		return (err);
1742 
1743 	return (Z_OK);
1744 }
1745 
1746 int
1747 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
1748 {
1749 	xmlNodePtr cur, firstmatch;
1750 	int err;
1751 	char match[MAXPATHLEN];
1752 
1753 	if (tabptr == NULL)
1754 		return (Z_INVAL);
1755 
1756 	if ((err = operation_prep(handle)) != Z_OK)
1757 		return (err);
1758 
1759 	cur = handle->zone_dh_cur;
1760 	firstmatch = NULL;
1761 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1762 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
1763 			continue;
1764 		if (strlen(tabptr->zone_dev_match) == 0)
1765 			continue;
1766 
1767 		if ((fetchprop(cur, DTD_ATTR_MATCH, match,
1768 		    sizeof (match)) == Z_OK)) {
1769 			if (strcmp(tabptr->zone_dev_match,
1770 			    match) == 0) {
1771 				if (firstmatch == NULL)
1772 					firstmatch = cur;
1773 				else if (firstmatch != cur)
1774 					return (Z_INSUFFICIENT_SPEC);
1775 			} else {
1776 				/*
1777 				 * If another property matched but this
1778 				 * one doesn't then reset firstmatch.
1779 				 */
1780 				if (firstmatch == cur)
1781 					firstmatch = NULL;
1782 			}
1783 		}
1784 	}
1785 	if (firstmatch == NULL)
1786 		return (Z_NO_RESOURCE_ID);
1787 
1788 	cur = firstmatch;
1789 
1790 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
1791 	    sizeof (tabptr->zone_dev_match))) != Z_OK)
1792 		return (err);
1793 
1794 	return (Z_OK);
1795 }
1796 
1797 static int
1798 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
1799 {
1800 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
1801 	int err;
1802 
1803 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
1804 
1805 	if ((err = newprop(newnode, DTD_ATTR_MATCH,
1806 	    tabptr->zone_dev_match)) != Z_OK)
1807 		return (err);
1808 
1809 	return (Z_OK);
1810 }
1811 
1812 int
1813 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
1814 {
1815 	int err;
1816 
1817 	if (tabptr == NULL)
1818 		return (Z_INVAL);
1819 
1820 	if ((err = operation_prep(handle)) != Z_OK)
1821 		return (err);
1822 
1823 	if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
1824 		return (err);
1825 
1826 	return (Z_OK);
1827 }
1828 
1829 static int
1830 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
1831 {
1832 	xmlNodePtr cur = handle->zone_dh_cur;
1833 	int match_match;
1834 
1835 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1836 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
1837 			continue;
1838 
1839 		match_match = match_prop(cur, DTD_ATTR_MATCH,
1840 		    tabptr->zone_dev_match);
1841 
1842 		if (match_match) {
1843 			xmlUnlinkNode(cur);
1844 			xmlFreeNode(cur);
1845 			return (Z_OK);
1846 		}
1847 	}
1848 	return (Z_NO_RESOURCE_ID);
1849 }
1850 
1851 int
1852 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
1853 {
1854 	int err;
1855 
1856 	if (tabptr == NULL)
1857 		return (Z_INVAL);
1858 
1859 	if ((err = operation_prep(handle)) != Z_OK)
1860 		return (err);
1861 
1862 	if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
1863 		return (err);
1864 
1865 	return (Z_OK);
1866 }
1867 
1868 int
1869 zonecfg_modify_dev(
1870 	zone_dochandle_t handle,
1871 	struct zone_devtab *oldtabptr,
1872 	struct zone_devtab *newtabptr)
1873 {
1874 	int err;
1875 
1876 	if (oldtabptr == NULL || newtabptr == NULL)
1877 		return (Z_INVAL);
1878 
1879 	if ((err = operation_prep(handle)) != Z_OK)
1880 		return (err);
1881 
1882 	if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
1883 		return (err);
1884 
1885 	if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
1886 		return (err);
1887 
1888 	return (Z_OK);
1889 }
1890 
1891 /*
1892  * This is the set of devices which must be present in every zone.  Users
1893  * can augment this list with additional device rules in their zone
1894  * configuration, but at present cannot remove any of the this set of
1895  * standard devices.  All matching is done by /dev pathname (the "/dev"
1896  * part is implicit.  Try to keep rules which match a large number of
1897  * devices (like the pts rule) first.
1898  */
1899 static const char *standard_devs[] = {
1900 	"pts/*",
1901 	"ptmx",
1902 	"random",
1903 	"urandom",
1904 	"poll",
1905 	"pool",
1906 	"kstat",
1907 	"zero",
1908 	"null",
1909 	"crypto",
1910 	"cryptoadm",
1911 	"ticots",
1912 	"ticotsord",
1913 	"ticlts",
1914 	"lo0",
1915 	"lo1",
1916 	"lo2",
1917 	"lo3",
1918 	"sad/user",
1919 	"tty",
1920 	"logindmux",
1921 	"log",
1922 	"conslog",
1923 	"arp",
1924 	"tcp",
1925 	"tcp6",
1926 	"udp",
1927 	"udp6",
1928 	"sysevent",
1929 #ifdef __sparc
1930 	"openprom",
1931 #endif
1932 	"cpu/self/cpuid",
1933 	"dtrace/helper",
1934 	"zfs",
1935 	NULL
1936 };
1937 
1938 /*
1939  * This function finds everything mounted under a zone's rootpath.
1940  * This returns the number of mounts under rootpath, or -1 on error.
1941  * callback is called once per mount found with the first argument
1942  * pointing to the  mount point.
1943  *
1944  * If the callback function returns non-zero zonecfg_find_mounts
1945  * aborts with an error.
1946  */
1947 
1948 int
1949 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *),
1950     void *priv) {
1951 	FILE *mnttab;
1952 	struct mnttab m;
1953 	size_t l;
1954 	int rv = 0;
1955 
1956 	assert(rootpath != NULL);
1957 
1958 	l = strlen(rootpath);
1959 
1960 	mnttab = fopen("/etc/mnttab", "r");
1961 
1962 	if (mnttab == NULL)
1963 		return (-1);
1964 
1965 	if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0)  {
1966 		rv = -1;
1967 		goto out;
1968 	}
1969 
1970 	while (!getmntent(mnttab, &m)) {
1971 		if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
1972 		    (m.mnt_mountp[l] == '/')) {
1973 			rv++;
1974 			if (callback == NULL)
1975 				continue;
1976 			if (callback(m.mnt_mountp, priv)) {
1977 				rv = -1;
1978 				goto out;
1979 
1980 			}
1981 		}
1982 	}
1983 
1984 out:
1985 	(void) fclose(mnttab);
1986 	return (rv);
1987 }
1988 
1989 /*
1990  * This routine is used to determine if a given device should appear in the
1991  * zone represented by 'handle'.  First it consults the list of "standard"
1992  * zone devices.  Then it scans the user-supplied device entries.
1993  */
1994 int
1995 zonecfg_match_dev(zone_dochandle_t handle, char *devpath,
1996     struct zone_devtab *out_match)
1997 {
1998 	int err;
1999 	boolean_t found = B_FALSE;
2000 	char match[MAXPATHLEN];
2001 	const char **stdmatch;
2002 	xmlNodePtr cur;
2003 
2004 	if (handle == NULL || devpath == NULL)
2005 		return (Z_INVAL);
2006 
2007 	/*
2008 	 * Check the "standard" devices which we require to be present.
2009 	 */
2010 	for (stdmatch = &standard_devs[0]; *stdmatch != NULL; stdmatch++) {
2011 		/*
2012 		 * fnmatch gives us simple but powerful shell-style matching.
2013 		 */
2014 		if (fnmatch(*stdmatch, devpath, FNM_PATHNAME) == 0) {
2015 			if (!out_match)
2016 				return (Z_OK);
2017 			(void) snprintf(out_match->zone_dev_match,
2018 			    sizeof (out_match->zone_dev_match),
2019 			    "/dev/%s", *stdmatch);
2020 			return (Z_OK);
2021 		}
2022 	}
2023 
2024 	/*
2025 	 * We got no hits in the set of standard devices.  On to the user
2026 	 * supplied ones.
2027 	 */
2028 	if ((err = operation_prep(handle)) != Z_OK) {
2029 		handle->zone_dh_cur = NULL;
2030 		return (err);
2031 	}
2032 
2033 	cur = handle->zone_dh_cur;
2034 	cur = cur->xmlChildrenNode;
2035 	if (cur == NULL)
2036 		return (Z_NO_ENTRY);
2037 	handle->zone_dh_cur = cur;
2038 
2039 	for (; cur != NULL; cur = cur->next) {
2040 		char *m;
2041 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE) != 0)
2042 			continue;
2043 		if ((err = fetchprop(cur, DTD_ATTR_MATCH, match,
2044 		    sizeof (match))) != Z_OK) {
2045 			handle->zone_dh_cur = handle->zone_dh_top;
2046 			return (err);
2047 		}
2048 		m = match;
2049 		/*
2050 		 * fnmatch gives us simple but powerful shell-style matching;
2051 		 * but first, we need to strip out /dev/ from the matching rule.
2052 		 */
2053 		if (strncmp(m, "/dev/", 5) == 0)
2054 			m += 5;
2055 
2056 		if (fnmatch(m, devpath, FNM_PATHNAME) == 0) {
2057 			found = B_TRUE;
2058 			break;
2059 		}
2060 	}
2061 
2062 	if (!found)
2063 		return (Z_NO_ENTRY);
2064 
2065 	if (!out_match)
2066 		return (Z_OK);
2067 
2068 	(void) strlcpy(out_match->zone_dev_match, match,
2069 	    sizeof (out_match->zone_dev_match));
2070 	return (Z_OK);
2071 }
2072 
2073 int
2074 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2075 {
2076 	xmlNodePtr cur, firstmatch;
2077 	int err;
2078 	char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
2079 
2080 	if (tabptr == NULL)
2081 		return (Z_INVAL);
2082 
2083 	if ((err = operation_prep(handle)) != Z_OK)
2084 		return (err);
2085 
2086 	cur = handle->zone_dh_cur;
2087 	firstmatch = NULL;
2088 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2089 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
2090 			continue;
2091 		if (strlen(tabptr->zone_attr_name) > 0) {
2092 			if ((fetchprop(cur, DTD_ATTR_NAME, name,
2093 			    sizeof (name)) == Z_OK) &&
2094 			    (strcmp(tabptr->zone_attr_name, name) == 0)) {
2095 				if (firstmatch == NULL)
2096 					firstmatch = cur;
2097 				else
2098 					return (Z_INSUFFICIENT_SPEC);
2099 			}
2100 		}
2101 		if (strlen(tabptr->zone_attr_type) > 0) {
2102 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
2103 			    sizeof (type)) == Z_OK)) {
2104 				if (strcmp(tabptr->zone_attr_type, type) == 0) {
2105 					if (firstmatch == NULL)
2106 						firstmatch = cur;
2107 					else if (firstmatch != cur)
2108 						return (Z_INSUFFICIENT_SPEC);
2109 				} else {
2110 					/*
2111 					 * If another property matched but this
2112 					 * one doesn't then reset firstmatch.
2113 					 */
2114 					if (firstmatch == cur)
2115 						firstmatch = NULL;
2116 				}
2117 			}
2118 		}
2119 		if (strlen(tabptr->zone_attr_value) > 0) {
2120 			if ((fetchprop(cur, DTD_ATTR_VALUE, value,
2121 			    sizeof (value)) == Z_OK)) {
2122 				if (strcmp(tabptr->zone_attr_value, value) ==
2123 				    0) {
2124 					if (firstmatch == NULL)
2125 						firstmatch = cur;
2126 					else if (firstmatch != cur)
2127 						return (Z_INSUFFICIENT_SPEC);
2128 				} else {
2129 					/*
2130 					 * If another property matched but this
2131 					 * one doesn't then reset firstmatch.
2132 					 */
2133 					if (firstmatch == cur)
2134 						firstmatch = NULL;
2135 				}
2136 			}
2137 		}
2138 	}
2139 	if (firstmatch == NULL)
2140 		return (Z_NO_RESOURCE_ID);
2141 
2142 	cur = firstmatch;
2143 
2144 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
2145 	    sizeof (tabptr->zone_attr_name))) != Z_OK)
2146 		return (err);
2147 
2148 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
2149 	    sizeof (tabptr->zone_attr_type))) != Z_OK)
2150 		return (err);
2151 
2152 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
2153 	    sizeof (tabptr->zone_attr_value))) != Z_OK)
2154 		return (err);
2155 
2156 	return (Z_OK);
2157 }
2158 
2159 static int
2160 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2161 {
2162 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2163 	int err;
2164 
2165 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
2166 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
2167 	if (err != Z_OK)
2168 		return (err);
2169 	err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
2170 	if (err != Z_OK)
2171 		return (err);
2172 	err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
2173 	if (err != Z_OK)
2174 		return (err);
2175 	return (Z_OK);
2176 }
2177 
2178 int
2179 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *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_add_attr_core(handle, tabptr)) != Z_OK)
2190 		return (err);
2191 
2192 	return (Z_OK);
2193 }
2194 
2195 static int
2196 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2197 {
2198 	xmlNodePtr cur = handle->zone_dh_cur;
2199 	int name_match, type_match, value_match;
2200 
2201 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2202 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
2203 			continue;
2204 
2205 		name_match = match_prop(cur, DTD_ATTR_NAME,
2206 		    tabptr->zone_attr_name);
2207 		type_match = match_prop(cur, DTD_ATTR_TYPE,
2208 		    tabptr->zone_attr_type);
2209 		value_match = match_prop(cur, DTD_ATTR_VALUE,
2210 		    tabptr->zone_attr_value);
2211 
2212 		if (name_match && type_match && value_match) {
2213 			xmlUnlinkNode(cur);
2214 			xmlFreeNode(cur);
2215 			return (Z_OK);
2216 		}
2217 	}
2218 	return (Z_NO_RESOURCE_ID);
2219 }
2220 
2221 int
2222 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2223 {
2224 	int err;
2225 
2226 	if (tabptr == NULL)
2227 		return (Z_INVAL);
2228 
2229 	if ((err = operation_prep(handle)) != Z_OK)
2230 		return (err);
2231 
2232 	if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
2233 		return (err);
2234 
2235 	return (Z_OK);
2236 }
2237 
2238 int
2239 zonecfg_modify_attr(
2240 	zone_dochandle_t handle,
2241 	struct zone_attrtab *oldtabptr,
2242 	struct zone_attrtab *newtabptr)
2243 {
2244 	int err;
2245 
2246 	if (oldtabptr == NULL || newtabptr == NULL)
2247 		return (Z_INVAL);
2248 
2249 	if ((err = operation_prep(handle)) != Z_OK)
2250 		return (err);
2251 
2252 	if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK)
2253 		return (err);
2254 
2255 	if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK)
2256 		return (err);
2257 
2258 	return (Z_OK);
2259 }
2260 
2261 int
2262 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value)
2263 {
2264 	if (attr == NULL)
2265 		return (Z_INVAL);
2266 
2267 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0)
2268 		return (Z_INVAL);
2269 
2270 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) {
2271 		*value = B_TRUE;
2272 		return (Z_OK);
2273 	}
2274 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) {
2275 		*value = B_FALSE;
2276 		return (Z_OK);
2277 	}
2278 	return (Z_INVAL);
2279 }
2280 
2281 int
2282 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value)
2283 {
2284 	long long result;
2285 	char *endptr;
2286 
2287 	if (attr == NULL)
2288 		return (Z_INVAL);
2289 
2290 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0)
2291 		return (Z_INVAL);
2292 
2293 	errno = 0;
2294 	result = strtoll(attr->zone_attr_value, &endptr, 10);
2295 	if (errno != 0 || *endptr != '\0')
2296 		return (Z_INVAL);
2297 	*value = result;
2298 	return (Z_OK);
2299 }
2300 
2301 int
2302 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value,
2303     size_t val_sz)
2304 {
2305 	if (attr == NULL)
2306 		return (Z_INVAL);
2307 
2308 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0)
2309 		return (Z_INVAL);
2310 
2311 	if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz)
2312 		return (Z_TOO_BIG);
2313 	return (Z_OK);
2314 }
2315 
2316 int
2317 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value)
2318 {
2319 	unsigned long long result;
2320 	long long neg_result;
2321 	char *endptr;
2322 
2323 	if (attr == NULL)
2324 		return (Z_INVAL);
2325 
2326 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0)
2327 		return (Z_INVAL);
2328 
2329 	errno = 0;
2330 	result = strtoull(attr->zone_attr_value, &endptr, 10);
2331 	if (errno != 0 || *endptr != '\0')
2332 		return (Z_INVAL);
2333 	errno = 0;
2334 	neg_result = strtoll(attr->zone_attr_value, &endptr, 10);
2335 	/*
2336 	 * Incredibly, strtoull("<negative number>", ...) will not fail but
2337 	 * return whatever (negative) number cast as a u_longlong_t, so we
2338 	 * need to look for this here.
2339 	 */
2340 	if (errno == 0 && neg_result < 0)
2341 		return (Z_INVAL);
2342 	*value = result;
2343 	return (Z_OK);
2344 }
2345 
2346 int
2347 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2348 {
2349 	xmlNodePtr cur, val;
2350 	char savedname[MAXNAMELEN];
2351 	struct zone_rctlvaltab *valptr;
2352 	int err;
2353 
2354 	if (tabptr->zone_rctl_name == NULL ||
2355 	    strlen(tabptr->zone_rctl_name) == 0)
2356 		return (Z_INVAL);
2357 
2358 	if ((err = operation_prep(handle)) != Z_OK)
2359 		return (err);
2360 
2361 	cur = handle->zone_dh_cur;
2362 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2363 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
2364 			continue;
2365 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
2366 		    sizeof (savedname)) == Z_OK) &&
2367 		    (strcmp(savedname, tabptr->zone_rctl_name) == 0)) {
2368 			tabptr->zone_rctl_valptr = NULL;
2369 			for (val = cur->xmlChildrenNode; val != NULL;
2370 			    val = val->next) {
2371 				valptr = (struct zone_rctlvaltab *)malloc(
2372 				    sizeof (struct zone_rctlvaltab));
2373 				if (valptr == NULL)
2374 					return (Z_NOMEM);
2375 				if ((fetchprop(val, DTD_ATTR_PRIV,
2376 				    valptr->zone_rctlval_priv,
2377 				    sizeof (valptr->zone_rctlval_priv)) !=
2378 				    Z_OK))
2379 					break;
2380 				if ((fetchprop(val, DTD_ATTR_LIMIT,
2381 				    valptr->zone_rctlval_limit,
2382 				    sizeof (valptr->zone_rctlval_limit)) !=
2383 				    Z_OK))
2384 					break;
2385 				if ((fetchprop(val, DTD_ATTR_ACTION,
2386 				    valptr->zone_rctlval_action,
2387 				    sizeof (valptr->zone_rctlval_action)) !=
2388 				    Z_OK))
2389 					break;
2390 				if (zonecfg_add_rctl_value(tabptr, valptr) !=
2391 				    Z_OK)
2392 					break;
2393 			}
2394 			return (Z_OK);
2395 		}
2396 	}
2397 	return (Z_NO_RESOURCE_ID);
2398 }
2399 
2400 static int
2401 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2402 {
2403 	xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
2404 	struct zone_rctlvaltab *valptr;
2405 	int err;
2406 
2407 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL);
2408 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name);
2409 	if (err != Z_OK)
2410 		return (err);
2411 	for (valptr = tabptr->zone_rctl_valptr; valptr != NULL;
2412 	    valptr = valptr->zone_rctlval_next) {
2413 		valnode = xmlNewTextChild(newnode, NULL,
2414 		    DTD_ELEM_RCTLVALUE, NULL);
2415 		err = newprop(valnode, DTD_ATTR_PRIV,
2416 		    valptr->zone_rctlval_priv);
2417 		if (err != Z_OK)
2418 			return (err);
2419 		err = newprop(valnode, DTD_ATTR_LIMIT,
2420 		    valptr->zone_rctlval_limit);
2421 		if (err != Z_OK)
2422 			return (err);
2423 		err = newprop(valnode, DTD_ATTR_ACTION,
2424 		    valptr->zone_rctlval_action);
2425 		if (err != Z_OK)
2426 			return (err);
2427 	}
2428 	return (Z_OK);
2429 }
2430 
2431 int
2432 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2433 {
2434 	int err;
2435 
2436 	if (tabptr == NULL || tabptr->zone_rctl_name == NULL)
2437 		return (Z_INVAL);
2438 
2439 	if ((err = operation_prep(handle)) != Z_OK)
2440 		return (err);
2441 
2442 	if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK)
2443 		return (err);
2444 
2445 	return (Z_OK);
2446 }
2447 
2448 static int
2449 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2450 {
2451 	xmlNodePtr cur = handle->zone_dh_cur;
2452 	xmlChar *savedname;
2453 	int name_result;
2454 
2455 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2456 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
2457 			continue;
2458 
2459 		savedname = xmlGetProp(cur, DTD_ATTR_NAME);
2460 		if (savedname == NULL)	/* shouldn't happen */
2461 			continue;
2462 		name_result = xmlStrcmp(savedname,
2463 		    (const xmlChar *) tabptr->zone_rctl_name);
2464 		xmlFree(savedname);
2465 
2466 		if (name_result == 0) {
2467 			xmlUnlinkNode(cur);
2468 			xmlFreeNode(cur);
2469 			return (Z_OK);
2470 		}
2471 	}
2472 	return (Z_NO_RESOURCE_ID);
2473 }
2474 
2475 int
2476 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2477 {
2478 	int err;
2479 
2480 	if (tabptr == NULL || tabptr->zone_rctl_name == NULL)
2481 		return (Z_INVAL);
2482 
2483 	if ((err = operation_prep(handle)) != Z_OK)
2484 		return (err);
2485 
2486 	if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK)
2487 		return (err);
2488 
2489 	return (Z_OK);
2490 }
2491 
2492 int
2493 zonecfg_modify_rctl(
2494 	zone_dochandle_t handle,
2495 	struct zone_rctltab *oldtabptr,
2496 	struct zone_rctltab *newtabptr)
2497 {
2498 	int err;
2499 
2500 	if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL ||
2501 	    newtabptr == NULL || newtabptr->zone_rctl_name == NULL)
2502 		return (Z_INVAL);
2503 
2504 	if ((err = operation_prep(handle)) != Z_OK)
2505 		return (err);
2506 
2507 	if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK)
2508 		return (err);
2509 
2510 	if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK)
2511 		return (err);
2512 
2513 	return (Z_OK);
2514 }
2515 
2516 int
2517 zonecfg_add_rctl_value(
2518 	struct zone_rctltab *tabptr,
2519 	struct zone_rctlvaltab *valtabptr)
2520 {
2521 	struct zone_rctlvaltab *last, *old, *new;
2522 	rctlblk_t *rctlblk = alloca(rctlblk_size());
2523 
2524 	last = tabptr->zone_rctl_valptr;
2525 	for (old = last; old != NULL; old = old->zone_rctlval_next)
2526 		last = old;	/* walk to the end of the list */
2527 	new = valtabptr;	/* alloc'd by caller */
2528 	new->zone_rctlval_next = NULL;
2529 	if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK)
2530 		return (Z_INVAL);
2531 	if (!zonecfg_valid_rctlblk(rctlblk))
2532 		return (Z_INVAL);
2533 	if (last == NULL)
2534 		tabptr->zone_rctl_valptr = new;
2535 	else
2536 		last->zone_rctlval_next = new;
2537 	return (Z_OK);
2538 }
2539 
2540 int
2541 zonecfg_remove_rctl_value(
2542 	struct zone_rctltab *tabptr,
2543 	struct zone_rctlvaltab *valtabptr)
2544 {
2545 	struct zone_rctlvaltab *last, *this, *next;
2546 
2547 	last = tabptr->zone_rctl_valptr;
2548 	for (this = last; this != NULL; this = this->zone_rctlval_next) {
2549 		if (strcmp(this->zone_rctlval_priv,
2550 		    valtabptr->zone_rctlval_priv) == 0 &&
2551 		    strcmp(this->zone_rctlval_limit,
2552 		    valtabptr->zone_rctlval_limit) == 0 &&
2553 		    strcmp(this->zone_rctlval_action,
2554 		    valtabptr->zone_rctlval_action) == 0) {
2555 			next = this->zone_rctlval_next;
2556 			if (this == tabptr->zone_rctl_valptr)
2557 				tabptr->zone_rctl_valptr = next;
2558 			else
2559 				last->zone_rctlval_next = next;
2560 			free(this);
2561 			return (Z_OK);
2562 		} else
2563 			last = this;
2564 	}
2565 	return (Z_NO_PROPERTY_ID);
2566 }
2567 
2568 char *
2569 zonecfg_strerror(int errnum)
2570 {
2571 	switch (errnum) {
2572 	case Z_OK:
2573 		return (dgettext(TEXT_DOMAIN, "OK"));
2574 	case Z_EMPTY_DOCUMENT:
2575 		return (dgettext(TEXT_DOMAIN, "Empty document"));
2576 	case Z_WRONG_DOC_TYPE:
2577 		return (dgettext(TEXT_DOMAIN, "Wrong document type"));
2578 	case Z_BAD_PROPERTY:
2579 		return (dgettext(TEXT_DOMAIN, "Bad document property"));
2580 	case Z_TEMP_FILE:
2581 		return (dgettext(TEXT_DOMAIN,
2582 		    "Problem creating temporary file"));
2583 	case Z_SAVING_FILE:
2584 		return (dgettext(TEXT_DOMAIN, "Problem saving file"));
2585 	case Z_NO_ENTRY:
2586 		return (dgettext(TEXT_DOMAIN, "No such entry"));
2587 	case Z_BOGUS_ZONE_NAME:
2588 		return (dgettext(TEXT_DOMAIN, "Bogus zone name"));
2589 	case Z_REQD_RESOURCE_MISSING:
2590 		return (dgettext(TEXT_DOMAIN, "Required resource missing"));
2591 	case Z_REQD_PROPERTY_MISSING:
2592 		return (dgettext(TEXT_DOMAIN, "Required property missing"));
2593 	case Z_BAD_HANDLE:
2594 		return (dgettext(TEXT_DOMAIN, "Bad handle"));
2595 	case Z_NOMEM:
2596 		return (dgettext(TEXT_DOMAIN, "Out of memory"));
2597 	case Z_INVAL:
2598 		return (dgettext(TEXT_DOMAIN, "Invalid argument"));
2599 	case Z_ACCES:
2600 		return (dgettext(TEXT_DOMAIN, "Permission denied"));
2601 	case Z_TOO_BIG:
2602 		return (dgettext(TEXT_DOMAIN, "Argument list too long"));
2603 	case Z_MISC_FS:
2604 		return (dgettext(TEXT_DOMAIN,
2605 		    "Miscellaneous file system error"));
2606 	case Z_NO_ZONE:
2607 		return (dgettext(TEXT_DOMAIN, "No such zone configured"));
2608 	case Z_NO_RESOURCE_TYPE:
2609 		return (dgettext(TEXT_DOMAIN, "No such resource type"));
2610 	case Z_NO_RESOURCE_ID:
2611 		return (dgettext(TEXT_DOMAIN, "No such resource with that id"));
2612 	case Z_NO_PROPERTY_TYPE:
2613 		return (dgettext(TEXT_DOMAIN, "No such property type"));
2614 	case Z_NO_PROPERTY_ID:
2615 		return (dgettext(TEXT_DOMAIN, "No such property with that id"));
2616 	case Z_BAD_ZONE_STATE:
2617 		return (dgettext(TEXT_DOMAIN,
2618 		    "Zone state is invalid for the requested operation"));
2619 	case Z_INVALID_DOCUMENT:
2620 		return (dgettext(TEXT_DOMAIN, "Invalid document"));
2621 	case Z_NAME_IN_USE:
2622 		return (dgettext(TEXT_DOMAIN, "Zone name already in use"));
2623 	case Z_NO_SUCH_ID:
2624 		return (dgettext(TEXT_DOMAIN, "No such zone ID"));
2625 	case Z_UPDATING_INDEX:
2626 		return (dgettext(TEXT_DOMAIN, "Problem updating index file"));
2627 	case Z_LOCKING_FILE:
2628 		return (dgettext(TEXT_DOMAIN, "Locking index file"));
2629 	case Z_UNLOCKING_FILE:
2630 		return (dgettext(TEXT_DOMAIN, "Unlocking index file"));
2631 	case Z_INSUFFICIENT_SPEC:
2632 		return (dgettext(TEXT_DOMAIN, "Insufficient specification"));
2633 	case Z_RESOLVED_PATH:
2634 		return (dgettext(TEXT_DOMAIN, "Resolved path mismatch"));
2635 	case Z_IPV6_ADDR_PREFIX_LEN:
2636 		return (dgettext(TEXT_DOMAIN,
2637 		    "IPv6 address missing required prefix length"));
2638 	case Z_BOGUS_ADDRESS:
2639 		return (dgettext(TEXT_DOMAIN,
2640 		    "Neither an IPv4 nor an IPv6 address nor a host name"));
2641 	default:
2642 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
2643 	}
2644 }
2645 
2646 /*
2647  * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
2648  * same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
2649  */
2650 
2651 static int
2652 zonecfg_setent(zone_dochandle_t handle)
2653 {
2654 	xmlNodePtr cur;
2655 	int err;
2656 
2657 	if (handle == NULL)
2658 		return (Z_INVAL);
2659 
2660 	if ((err = operation_prep(handle)) != Z_OK) {
2661 		handle->zone_dh_cur = NULL;
2662 		return (err);
2663 	}
2664 	cur = handle->zone_dh_cur;
2665 	cur = cur->xmlChildrenNode;
2666 	handle->zone_dh_cur = cur;
2667 	return (Z_OK);
2668 }
2669 
2670 static int
2671 zonecfg_endent(zone_dochandle_t handle)
2672 {
2673 	if (handle == NULL)
2674 		return (Z_INVAL);
2675 
2676 	handle->zone_dh_cur = handle->zone_dh_top;
2677 	return (Z_OK);
2678 }
2679 
2680 int
2681 zonecfg_setfsent(zone_dochandle_t handle)
2682 {
2683 	return (zonecfg_setent(handle));
2684 }
2685 
2686 int
2687 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr)
2688 {
2689 	xmlNodePtr cur, options;
2690 	char options_str[MAX_MNTOPT_STR];
2691 	int err;
2692 
2693 	if (handle == NULL)
2694 		return (Z_INVAL);
2695 
2696 	if ((cur = handle->zone_dh_cur) == NULL)
2697 		return (Z_NO_ENTRY);
2698 
2699 	for (; cur != NULL; cur = cur->next)
2700 		if (!xmlStrcmp(cur->name, DTD_ELEM_FS))
2701 			break;
2702 	if (cur == NULL) {
2703 		handle->zone_dh_cur = handle->zone_dh_top;
2704 		return (Z_NO_ENTRY);
2705 	}
2706 
2707 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
2708 	    sizeof (tabptr->zone_fs_special))) != Z_OK) {
2709 		handle->zone_dh_cur = handle->zone_dh_top;
2710 		return (err);
2711 	}
2712 
2713 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
2714 	    sizeof (tabptr->zone_fs_raw))) != Z_OK) {
2715 		handle->zone_dh_cur = handle->zone_dh_top;
2716 		return (err);
2717 	}
2718 
2719 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
2720 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
2721 		handle->zone_dh_cur = handle->zone_dh_top;
2722 		return (err);
2723 	}
2724 
2725 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
2726 	    sizeof (tabptr->zone_fs_type))) != Z_OK) {
2727 		handle->zone_dh_cur = handle->zone_dh_top;
2728 		return (err);
2729 	}
2730 
2731 	/* OK for options to be NULL */
2732 	tabptr->zone_fs_options = NULL;
2733 	for (options = cur->xmlChildrenNode; options != NULL;
2734 	    options = options->next) {
2735 		if (fetchprop(options, DTD_ATTR_NAME, options_str,
2736 		    sizeof (options_str)) != Z_OK)
2737 			break;
2738 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
2739 			break;
2740 	}
2741 
2742 	handle->zone_dh_cur = cur->next;
2743 	return (Z_OK);
2744 }
2745 
2746 int
2747 zonecfg_endfsent(zone_dochandle_t handle)
2748 {
2749 	return (zonecfg_endent(handle));
2750 }
2751 
2752 int
2753 zonecfg_setipdent(zone_dochandle_t handle)
2754 {
2755 	return (zonecfg_setent(handle));
2756 }
2757 
2758 int
2759 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr)
2760 {
2761 	xmlNodePtr cur;
2762 	int err;
2763 
2764 	if (handle == NULL)
2765 		return (Z_INVAL);
2766 
2767 	if ((cur = handle->zone_dh_cur) == NULL)
2768 		return (Z_NO_ENTRY);
2769 
2770 	for (; cur != NULL; cur = cur->next)
2771 		if (!xmlStrcmp(cur->name, DTD_ELEM_IPD))
2772 			break;
2773 	if (cur == NULL) {
2774 		handle->zone_dh_cur = handle->zone_dh_top;
2775 		return (Z_NO_ENTRY);
2776 	}
2777 
2778 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
2779 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
2780 		handle->zone_dh_cur = handle->zone_dh_top;
2781 		return (err);
2782 	}
2783 
2784 	handle->zone_dh_cur = cur->next;
2785 	return (Z_OK);
2786 }
2787 
2788 int
2789 zonecfg_endipdent(zone_dochandle_t handle)
2790 {
2791 	return (zonecfg_endent(handle));
2792 }
2793 
2794 int
2795 zonecfg_setnwifent(zone_dochandle_t handle)
2796 {
2797 	return (zonecfg_setent(handle));
2798 }
2799 
2800 int
2801 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2802 {
2803 	xmlNodePtr cur;
2804 	int err;
2805 
2806 	if (handle == NULL)
2807 		return (Z_INVAL);
2808 
2809 	if ((cur = handle->zone_dh_cur) == NULL)
2810 		return (Z_NO_ENTRY);
2811 
2812 	for (; cur != NULL; cur = cur->next)
2813 		if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
2814 			break;
2815 	if (cur == NULL) {
2816 		handle->zone_dh_cur = handle->zone_dh_top;
2817 		return (Z_NO_ENTRY);
2818 	}
2819 
2820 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2821 	    sizeof (tabptr->zone_nwif_address))) != Z_OK) {
2822 		handle->zone_dh_cur = handle->zone_dh_top;
2823 		return (err);
2824 	}
2825 
2826 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2827 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
2828 		handle->zone_dh_cur = handle->zone_dh_top;
2829 		return (err);
2830 	}
2831 
2832 	handle->zone_dh_cur = cur->next;
2833 	return (Z_OK);
2834 }
2835 
2836 int
2837 zonecfg_endnwifent(zone_dochandle_t handle)
2838 {
2839 	return (zonecfg_endent(handle));
2840 }
2841 
2842 int
2843 zonecfg_setdevent(zone_dochandle_t handle)
2844 {
2845 	return (zonecfg_setent(handle));
2846 }
2847 
2848 int
2849 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
2850 {
2851 	xmlNodePtr cur;
2852 	int err;
2853 
2854 	if (handle == NULL)
2855 		return (Z_INVAL);
2856 
2857 	if ((cur = handle->zone_dh_cur) == NULL)
2858 		return (Z_NO_ENTRY);
2859 
2860 	for (; cur != NULL; cur = cur->next)
2861 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2862 			break;
2863 	if (cur == NULL) {
2864 		handle->zone_dh_cur = handle->zone_dh_top;
2865 		return (Z_NO_ENTRY);
2866 	}
2867 
2868 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2869 	    sizeof (tabptr->zone_dev_match))) != Z_OK) {
2870 		handle->zone_dh_cur = handle->zone_dh_top;
2871 		return (err);
2872 	}
2873 
2874 	handle->zone_dh_cur = cur->next;
2875 	return (Z_OK);
2876 }
2877 
2878 int
2879 zonecfg_enddevent(zone_dochandle_t handle)
2880 {
2881 	return (zonecfg_endent(handle));
2882 }
2883 
2884 int
2885 zonecfg_setrctlent(zone_dochandle_t handle)
2886 {
2887 	return (zonecfg_setent(handle));
2888 }
2889 
2890 int
2891 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2892 {
2893 	xmlNodePtr cur, val;
2894 	struct zone_rctlvaltab *valptr;
2895 	int err;
2896 
2897 	if (handle == NULL)
2898 		return (Z_INVAL);
2899 
2900 	if ((cur = handle->zone_dh_cur) == NULL)
2901 		return (Z_NO_ENTRY);
2902 
2903 	for (; cur != NULL; cur = cur->next)
2904 		if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL))
2905 			break;
2906 	if (cur == NULL) {
2907 		handle->zone_dh_cur = handle->zone_dh_top;
2908 		return (Z_NO_ENTRY);
2909 	}
2910 
2911 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name,
2912 	    sizeof (tabptr->zone_rctl_name))) != Z_OK) {
2913 		handle->zone_dh_cur = handle->zone_dh_top;
2914 		return (err);
2915 	}
2916 
2917 	tabptr->zone_rctl_valptr = NULL;
2918 	for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
2919 		valptr = (struct zone_rctlvaltab *)malloc(
2920 		    sizeof (struct zone_rctlvaltab));
2921 		if (valptr == NULL)
2922 			return (Z_NOMEM);
2923 		if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv,
2924 		    sizeof (valptr->zone_rctlval_priv)) != Z_OK)
2925 			break;
2926 		if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit,
2927 		    sizeof (valptr->zone_rctlval_limit)) != Z_OK)
2928 			break;
2929 		if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action,
2930 		    sizeof (valptr->zone_rctlval_action)) != Z_OK)
2931 			break;
2932 		if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK)
2933 			break;
2934 	}
2935 
2936 	handle->zone_dh_cur = cur->next;
2937 	return (Z_OK);
2938 }
2939 
2940 int
2941 zonecfg_endrctlent(zone_dochandle_t handle)
2942 {
2943 	return (zonecfg_endent(handle));
2944 }
2945 
2946 int
2947 zonecfg_setattrent(zone_dochandle_t handle)
2948 {
2949 	return (zonecfg_setent(handle));
2950 }
2951 
2952 int
2953 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2954 {
2955 	xmlNodePtr cur;
2956 	int err;
2957 
2958 	if (handle == NULL)
2959 		return (Z_INVAL);
2960 
2961 	if ((cur = handle->zone_dh_cur) == NULL)
2962 		return (Z_NO_ENTRY);
2963 
2964 	for (; cur != NULL; cur = cur->next)
2965 		if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR))
2966 			break;
2967 	if (cur == NULL) {
2968 		handle->zone_dh_cur = handle->zone_dh_top;
2969 		return (Z_NO_ENTRY);
2970 	}
2971 
2972 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
2973 	    sizeof (tabptr->zone_attr_name))) != Z_OK) {
2974 		handle->zone_dh_cur = handle->zone_dh_top;
2975 		return (err);
2976 	}
2977 
2978 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
2979 	    sizeof (tabptr->zone_attr_type))) != Z_OK) {
2980 		handle->zone_dh_cur = handle->zone_dh_top;
2981 		return (err);
2982 	}
2983 
2984 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
2985 	    sizeof (tabptr->zone_attr_value))) != Z_OK) {
2986 		handle->zone_dh_cur = handle->zone_dh_top;
2987 		return (err);
2988 	}
2989 
2990 	handle->zone_dh_cur = cur->next;
2991 	return (Z_OK);
2992 }
2993 
2994 int
2995 zonecfg_endattrent(zone_dochandle_t handle)
2996 {
2997 	return (zonecfg_endent(handle));
2998 }
2999 
3000 /* This will ultimately be configurable. */
3001 static const char *priv_list[] = {
3002 	PRIV_FILE_CHOWN,
3003 	PRIV_FILE_CHOWN_SELF,
3004 	PRIV_FILE_DAC_EXECUTE,
3005 	PRIV_FILE_DAC_READ,
3006 	PRIV_FILE_DAC_SEARCH,
3007 	PRIV_FILE_DAC_WRITE,
3008 	PRIV_FILE_OWNER,
3009 	PRIV_FILE_SETID,
3010 	PRIV_IPC_DAC_READ,
3011 	PRIV_IPC_DAC_WRITE,
3012 	PRIV_IPC_OWNER,
3013 	PRIV_NET_ICMPACCESS,
3014 	PRIV_NET_PRIVADDR,
3015 	PRIV_PROC_CHROOT,
3016 	PRIV_SYS_AUDIT,
3017 	PRIV_PROC_AUDIT,
3018 	PRIV_PROC_OWNER,
3019 	PRIV_PROC_SETID,
3020 	PRIV_PROC_TASKID,
3021 	PRIV_SYS_ACCT,
3022 	PRIV_SYS_ADMIN,
3023 	PRIV_SYS_MOUNT,
3024 	PRIV_SYS_NFS,
3025 	PRIV_SYS_RESOURCE,
3026 	PRIV_CONTRACT_EVENT,
3027 	PRIV_CONTRACT_OBSERVER,
3028 	NULL
3029 };
3030 
3031 int
3032 zonecfg_get_privset(priv_set_t *privs)
3033 {
3034 	const char **strp;
3035 	priv_set_t *basic = priv_str_to_set("basic", ",", NULL);
3036 
3037 	if (basic == NULL)
3038 		return (Z_INVAL);
3039 
3040 	priv_union(basic, privs);
3041 	priv_freeset(basic);
3042 
3043 	for (strp = priv_list; *strp != NULL; strp++) {
3044 		if (priv_addset(privs, *strp) != 0) {
3045 			return (Z_INVAL);
3046 		}
3047 	}
3048 	return (Z_OK);
3049 }
3050 
3051 int
3052 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
3053 {
3054 	zone_dochandle_t handle;
3055 	boolean_t found = B_FALSE;
3056 	struct zoneent *ze;
3057 	FILE *cookie;
3058 	int err;
3059 	char *cp;
3060 
3061 	if (zone_name == NULL)
3062 		return (Z_INVAL);
3063 
3064 	(void) strlcpy(zonepath, zonecfg_root, rp_sz);
3065 	cp = zonepath + strlen(zonepath);
3066 	while (cp > zonepath && cp[-1] == '/')
3067 		*--cp = '\0';
3068 
3069 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
3070 		if (zonepath[0] == '\0')
3071 			(void) strlcpy(zonepath, "/", rp_sz);
3072 		return (Z_OK);
3073 	}
3074 
3075 	/*
3076 	 * First check the index file.  Because older versions did not have
3077 	 * a copy of the zone path, allow for it to be zero length, in which
3078 	 * case we ignore this result and fall back to the XML files.
3079 	 */
3080 	cookie = setzoneent();
3081 	while ((ze = getzoneent_private(cookie)) != NULL) {
3082 		if (strcmp(ze->zone_name, zone_name) == 0) {
3083 			found = B_TRUE;
3084 			if (ze->zone_path[0] != '\0')
3085 				(void) strlcpy(cp, ze->zone_path,
3086 				    rp_sz - (cp - zonepath));
3087 		}
3088 		free(ze);
3089 		if (found)
3090 			break;
3091 	}
3092 	endzoneent(cookie);
3093 	if (found && *cp != '\0')
3094 		return (Z_OK);
3095 
3096 	/* Fall back to the XML files. */
3097 	if ((handle = zonecfg_init_handle()) == NULL)
3098 		return (Z_NOMEM);
3099 
3100 	/*
3101 	 * Check the snapshot first: if a zone is running, its zonepath
3102 	 * may have changed.
3103 	 */
3104 	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
3105 		if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK)
3106 			return (err);
3107 	}
3108 	err = zonecfg_get_zonepath(handle, zonepath, rp_sz);
3109 	zonecfg_fini_handle(handle);
3110 	return (err);
3111 }
3112 
3113 int
3114 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz)
3115 {
3116 	int err;
3117 
3118 	/* This function makes sense for non-global zones only. */
3119 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
3120 		return (Z_BOGUS_ZONE_NAME);
3121 	if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK)
3122 		return (err);
3123 	if (strlcat(rootpath, "/root", rp_sz) >= rp_sz)
3124 		return (Z_TOO_BIG);
3125 	return (Z_OK);
3126 }
3127 
3128 static zone_state_t
3129 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state)
3130 {
3131 	char zoneroot[MAXPATHLEN];
3132 	size_t zlen;
3133 
3134 	assert(kernel_state <= ZONE_MAX_STATE);
3135 	switch (kernel_state) {
3136 		case ZONE_IS_UNINITIALIZED:
3137 			return (ZONE_STATE_READY);
3138 		case ZONE_IS_READY:
3139 			/*
3140 			 * If the zone's root is mounted on $ZONEPATH/lu, then
3141 			 * it's a mounted scratch zone.
3142 			 */
3143 			if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
3144 			    sizeof (zoneroot)) >= 0) {
3145 				zlen = strlen(zoneroot);
3146 				if (zlen > 3 &&
3147 				    strcmp(zoneroot + zlen - 3, "/lu") == 0)
3148 					return (ZONE_STATE_MOUNTED);
3149 			}
3150 			return (ZONE_STATE_READY);
3151 		case ZONE_IS_BOOTING:
3152 		case ZONE_IS_RUNNING:
3153 			return (ZONE_STATE_RUNNING);
3154 		case ZONE_IS_SHUTTING_DOWN:
3155 		case ZONE_IS_EMPTY:
3156 			return (ZONE_STATE_SHUTTING_DOWN);
3157 		case ZONE_IS_DOWN:
3158 		case ZONE_IS_DYING:
3159 		case ZONE_IS_DEAD:
3160 		default:
3161 			return (ZONE_STATE_DOWN);
3162 	}
3163 	/* NOTREACHED */
3164 }
3165 
3166 int
3167 zone_get_state(char *zone_name, zone_state_t *state_num)
3168 {
3169 	zone_status_t status;
3170 	zoneid_t zone_id;
3171 	struct zoneent *ze;
3172 	boolean_t found = B_FALSE;
3173 	FILE *cookie;
3174 	char kernzone[ZONENAME_MAX];
3175 	FILE *fp;
3176 
3177 	if (zone_name == NULL)
3178 		return (Z_INVAL);
3179 
3180 	/*
3181 	 * If we're looking at an alternate root, then we need to query the
3182 	 * kernel using the scratch zone name.
3183 	 */
3184 	zone_id = -1;
3185 	if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
3186 		if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
3187 			if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
3188 			    kernzone, sizeof (kernzone)) == 0)
3189 				zone_id = getzoneidbyname(kernzone);
3190 			zonecfg_close_scratch(fp);
3191 		}
3192 	} else {
3193 		zone_id = getzoneidbyname(zone_name);
3194 	}
3195 
3196 	/* check to see if zone is running */
3197 	if (zone_id != -1 &&
3198 	    zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
3199 	    sizeof (status)) >= 0) {
3200 		*state_num = kernel_state_to_user_state(zone_id, status);
3201 		return (Z_OK);
3202 	}
3203 
3204 	cookie = setzoneent();
3205 	while ((ze = getzoneent_private(cookie)) != NULL) {
3206 		if (strcmp(ze->zone_name, zone_name) == 0) {
3207 			found = B_TRUE;
3208 			*state_num = ze->zone_state;
3209 		}
3210 		free(ze);
3211 		if (found)
3212 			break;
3213 	}
3214 	endzoneent(cookie);
3215 	return ((found) ? Z_OK : Z_NO_ZONE);
3216 }
3217 
3218 int
3219 zone_set_state(char *zone, zone_state_t state)
3220 {
3221 	struct zoneent ze;
3222 
3223 	if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
3224 	    state != ZONE_STATE_INCOMPLETE)
3225 		return (Z_INVAL);
3226 
3227 	bzero(&ze, sizeof (ze));
3228 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
3229 	ze.zone_state = state;
3230 	(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
3231 	return (putzoneent(&ze, PZE_MODIFY));
3232 }
3233 
3234 /*
3235  * Get id (if any) for specified zone.  There are four possible outcomes:
3236  * - If the string corresponds to the numeric id of an active (booted)
3237  *   zone, sets *zip to the zone id and returns 0.
3238  * - If the string corresponds to the name of an active (booted) zone,
3239  *   sets *zip to the zone id and returns 0.
3240  * - If the string is a name in the configuration but is not booted,
3241  *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
3242  * - Otherwise, leaves *zip unchanged and returns -1.
3243  *
3244  * This function acts as an auxiliary filter on the function of the same
3245  * name in libc; the linker binds to this version if libzonecfg exists,
3246  * and the libc version if it doesn't.  Any changes to this version of
3247  * the function should probably be reflected in the libc version as well.
3248  */
3249 int
3250 zone_get_id(const char *str, zoneid_t *zip)
3251 {
3252 	zone_dochandle_t hdl;
3253 	zoneid_t zoneid;
3254 	char *cp;
3255 	int err;
3256 
3257 	/* first try looking for active zone by id */
3258 	errno = 0;
3259 	zoneid = (zoneid_t)strtol(str, &cp, 0);
3260 	if (errno == 0 && cp != str && *cp == '\0' &&
3261 	    getzonenamebyid(zoneid, NULL, 0) != -1) {
3262 		*zip = zoneid;
3263 		return (0);
3264 	}
3265 
3266 	/* then look for active zone by name */
3267 	if ((zoneid = getzoneidbyname(str)) != -1) {
3268 		*zip = zoneid;
3269 		return (0);
3270 	}
3271 
3272 	/* if in global zone, try looking up name in configuration database */
3273 	if (getzoneid() != GLOBAL_ZONEID ||
3274 	    (hdl = zonecfg_init_handle()) == NULL)
3275 		return (-1);
3276 
3277 	if (zonecfg_get_handle(str, hdl) == Z_OK) {
3278 		/* zone exists but isn't active */
3279 		*zip = ZONE_ID_UNDEFINED;
3280 		err = 0;
3281 	} else {
3282 		err = -1;
3283 	}
3284 
3285 	zonecfg_fini_handle(hdl);
3286 	return (err);
3287 }
3288 
3289 char *
3290 zone_state_str(zone_state_t state_num)
3291 {
3292 	switch (state_num) {
3293 	case ZONE_STATE_CONFIGURED:
3294 		return (ZONE_STATE_STR_CONFIGURED);
3295 	case ZONE_STATE_INCOMPLETE:
3296 		return (ZONE_STATE_STR_INCOMPLETE);
3297 	case ZONE_STATE_INSTALLED:
3298 		return (ZONE_STATE_STR_INSTALLED);
3299 	case ZONE_STATE_READY:
3300 		return (ZONE_STATE_STR_READY);
3301 	case ZONE_STATE_MOUNTED:
3302 		return (ZONE_STATE_STR_MOUNTED);
3303 	case ZONE_STATE_RUNNING:
3304 		return (ZONE_STATE_STR_RUNNING);
3305 	case ZONE_STATE_SHUTTING_DOWN:
3306 		return (ZONE_STATE_STR_SHUTTING_DOWN);
3307 	case ZONE_STATE_DOWN:
3308 		return (ZONE_STATE_STR_DOWN);
3309 	default:
3310 		return ("unknown");
3311 	}
3312 }
3313 
3314 /*
3315  * Given a UUID value, find an associated zone name.  This is intended to be
3316  * used by callers who set up some 'default' name (corresponding to the
3317  * expected name for the zone) in the zonename buffer, and thus the function
3318  * doesn't touch this buffer on failure.
3319  */
3320 int
3321 zonecfg_get_name_by_uuid(const uuid_t uuid, char *zonename, size_t namelen)
3322 {
3323 	FILE *fp;
3324 	struct zoneent *ze;
3325 
3326 	/*
3327 	 * A small amount of subterfuge via casts is necessary here because
3328 	 * libuuid doesn't use const correctly, but we don't want to export
3329 	 * this brokenness to our clients.
3330 	 */
3331 	if (uuid_is_null(*(uuid_t *)&uuid))
3332 		return (Z_NO_ZONE);
3333 	if ((fp = setzoneent()) == NULL)
3334 		return (Z_NO_ZONE);
3335 	while ((ze = getzoneent_private(fp)) != NULL) {
3336 		if (uuid_compare(*(uuid_t *)&uuid, ze->zone_uuid) == 0)
3337 			break;
3338 		free(ze);
3339 	}
3340 	endzoneent(fp);
3341 	if (ze != NULL) {
3342 		(void) strlcpy(zonename, ze->zone_name, namelen);
3343 		free(ze);
3344 		return (Z_OK);
3345 	} else {
3346 		return (Z_NO_ZONE);
3347 	}
3348 }
3349 
3350 /*
3351  * Given a zone name, get its UUID.  Returns a "NULL" UUID value if the zone
3352  * exists but the file doesn't have a value set yet.  Returns an error if the
3353  * zone cannot be located.
3354  */
3355 int
3356 zonecfg_get_uuid(const char *zonename, uuid_t uuid)
3357 {
3358 	FILE *fp;
3359 	struct zoneent *ze;
3360 
3361 	if ((fp = setzoneent()) == NULL)
3362 		return (Z_NO_ZONE);
3363 	while ((ze = getzoneent_private(fp)) != NULL) {
3364 		if (strcmp(ze->zone_name, zonename) == 0)
3365 			break;
3366 		free(ze);
3367 	}
3368 	endzoneent(fp);
3369 	if (ze != NULL) {
3370 		uuid_copy(uuid, ze->zone_uuid);
3371 		free(ze);
3372 		return (Z_OK);
3373 	} else {
3374 		return (Z_NO_ZONE);
3375 	}
3376 }
3377 
3378 /*
3379  * File-system convenience functions.
3380  */
3381 boolean_t
3382 zonecfg_valid_fs_type(const char *type)
3383 {
3384 	/*
3385 	 * We already know which FS types don't work.
3386 	 */
3387 	if (strcmp(type, "proc") == 0 ||
3388 	    strcmp(type, "mntfs") == 0 ||
3389 	    strcmp(type, "autofs") == 0 ||
3390 	    strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 ||
3391 	    strcmp(type, "cachefs") == 0)
3392 		return (B_FALSE);
3393 	/*
3394 	 * The caller may do more detailed verification to make sure other
3395 	 * aspects of this filesystem type make sense.
3396 	 */
3397 	return (B_TRUE);
3398 }
3399 
3400 /*
3401  * Generally uninteresting rctl convenience functions.
3402  */
3403 
3404 int
3405 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
3406     rctlblk_t *rctlblk)
3407 {
3408 	unsigned long long ull;
3409 	char *endp;
3410 	rctl_priv_t priv;
3411 	rctl_qty_t limit;
3412 	uint_t action;
3413 
3414 	/* Get the privilege */
3415 	if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
3416 		priv = RCPRIV_BASIC;
3417 	} else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
3418 		priv = RCPRIV_PRIVILEGED;
3419 	} else {
3420 		/* Invalid privilege */
3421 		return (Z_INVAL);
3422 	}
3423 
3424 	/* deal with negative input; strtoull(3c) doesn't do what we want */
3425 	if (rctlval->zone_rctlval_limit[0] == '-')
3426 		return (Z_INVAL);
3427 	/* Get the limit */
3428 	errno = 0;
3429 	ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
3430 	if (errno != 0 || *endp != '\0') {
3431 		/* parse failed */
3432 		return (Z_INVAL);
3433 	}
3434 	limit = (rctl_qty_t)ull;
3435 
3436 	/* Get the action */
3437 	if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
3438 		action = RCTL_LOCAL_NOACTION;
3439 	} else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
3440 		action = RCTL_LOCAL_SIGNAL;
3441 	} else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
3442 		action = RCTL_LOCAL_DENY;
3443 	} else {
3444 		/* Invalid Action */
3445 		return (Z_INVAL);
3446 	}
3447 	rctlblk_set_local_action(rctlblk, action, 0);
3448 	rctlblk_set_privilege(rctlblk, priv);
3449 	rctlblk_set_value(rctlblk, limit);
3450 	return (Z_OK);
3451 }
3452 
3453 static int
3454 rctl_check(const char *rctlname, void *arg)
3455 {
3456 	const char *attrname = arg;
3457 
3458 	/*
3459 	 * Returning 1 here is our signal to zonecfg_is_rctl() that it is
3460 	 * indeed an rctl name recognized by the system.
3461 	 */
3462 	return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
3463 }
3464 
3465 boolean_t
3466 zonecfg_is_rctl(const char *name)
3467 {
3468 	return (rctl_walk(rctl_check, (void *)name) == 1);
3469 }
3470 
3471 boolean_t
3472 zonecfg_valid_rctlname(const char *name)
3473 {
3474 	const char *c;
3475 
3476 	if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
3477 		return (B_FALSE);
3478 	if (strlen(name) == sizeof ("zone.") - 1)
3479 		return (B_FALSE);
3480 	for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
3481 		if (!isalpha(*c) && *c != '-')
3482 			return (B_FALSE);
3483 	}
3484 	return (B_TRUE);
3485 }
3486 
3487 boolean_t
3488 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
3489 {
3490 	rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
3491 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
3492 
3493 	if (priv != RCPRIV_PRIVILEGED)
3494 		return (B_FALSE);
3495 	if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
3496 		return (B_FALSE);
3497 	return (B_TRUE);
3498 }
3499 
3500 boolean_t
3501 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
3502 {
3503 	rctlblk_t *current, *next;
3504 	rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
3505 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
3506 	uint_t global_flags;
3507 
3508 	if (!zonecfg_valid_rctlblk(rctlblk))
3509 		return (B_FALSE);
3510 	if (!zonecfg_valid_rctlname(name))
3511 		return (B_FALSE);
3512 
3513 	current = alloca(rctlblk_size());
3514 	if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
3515 		return (B_TRUE);	/* not an rctl on this system */
3516 	/*
3517 	 * Make sure the proposed value isn't greater than the current system
3518 	 * value.
3519 	 */
3520 	next = alloca(rctlblk_size());
3521 	while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
3522 		rctlblk_t *tmp;
3523 
3524 		if (getrctl(name, current, next, RCTL_NEXT) != 0)
3525 			return (B_FALSE);	/* shouldn't happen */
3526 		tmp = current;
3527 		current = next;
3528 		next = tmp;
3529 	}
3530 	if (limit > rctlblk_get_value(current))
3531 		return (B_FALSE);
3532 
3533 	/*
3534 	 * Make sure the proposed action is allowed.
3535 	 */
3536 	global_flags = rctlblk_get_global_flags(current);
3537 	if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
3538 	    action == RCTL_LOCAL_DENY)
3539 		return (B_FALSE);
3540 	if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
3541 	    action == RCTL_LOCAL_NOACTION)
3542 		return (B_FALSE);
3543 
3544 	return (B_TRUE);
3545 }
3546 
3547 /*
3548  * There is always a race condition between reading the initial copy of
3549  * a zones state and its state changing.  We address this by providing
3550  * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
3551  * When zonecfg_critical_enter is called, sets the state field to LOCKED
3552  * and aquires biglock. Biglock protects against other threads executing
3553  * critical_enter and the state field protects against state changes during
3554  * the critical period.
3555  *
3556  * If any state changes occur, zn_cb will set the failed field of the znotify
3557  * structure.  This will cause the critical_exit function to re-lock the
3558  * channel and return an error. Since evsnts may be delayed, the critical_exit
3559  * function "flushes" the queue by putting an event on the queue and waiting for
3560  * zn_cb to notify critical_exit that it received the ping event.
3561  */
3562 static const char *
3563 string_get_tok(const char *in, char delim, int num)
3564 {
3565 	int i = 0;
3566 
3567 	for (; i < num; in++) {
3568 		if (*in == delim)
3569 			i++;
3570 		if (*in == 0)
3571 			return (NULL);
3572 	}
3573 	return (in);
3574 }
3575 
3576 static boolean_t
3577 is_ping(sysevent_t *ev)
3578 {
3579 	if (strcmp(sysevent_get_subclass_name(ev),
3580 		ZONE_EVENT_PING_SUBCLASS) == 0) {
3581 		return (B_TRUE);
3582 	} else {
3583 		return (B_FALSE);
3584 	}
3585 }
3586 
3587 static boolean_t
3588 is_my_ping(sysevent_t *ev)
3589 {
3590 	const char *sender;
3591 	char mypid[sizeof (pid_t) * 3 + 1];
3592 
3593 	(void) snprintf(mypid, sizeof (mypid), "%i", getpid());
3594 	sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
3595 	if (sender == NULL)
3596 		return (B_FALSE);
3597 	if (strcmp(sender, mypid) != 0)
3598 		return (B_FALSE);
3599 	return (B_TRUE);
3600 }
3601 
3602 static int
3603 do_callback(struct znotify *zevtchan, sysevent_t *ev)
3604 {
3605 	nvlist_t *l;
3606 	int zid;
3607 	char *zonename;
3608 	char *newstate;
3609 	char *oldstate;
3610 	int ret;
3611 	hrtime_t when;
3612 
3613 	if (strcmp(sysevent_get_subclass_name(ev),
3614 	    ZONE_EVENT_STATUS_SUBCLASS) == 0) {
3615 
3616 		if (sysevent_get_attr_list(ev, &l) != 0) {
3617 			if (errno == ENOMEM) {
3618 				zevtchan->zn_failure_count++;
3619 				return (EAGAIN);
3620 			}
3621 			return (0);
3622 		}
3623 		ret = 0;
3624 
3625 		if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
3626 		    (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
3627 			== 0) &&
3628 		    (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
3629 			== 0) &&
3630 		    (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
3631 			    (uint64_t *)&when) == 0) &&
3632 		    (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
3633 			ret = zevtchan->zn_callback(zonename, zid, newstate,
3634 			    oldstate, when, zevtchan->zn_private);
3635 		}
3636 
3637 		zevtchan->zn_failure_count = 0;
3638 		nvlist_free(l);
3639 		return (ret);
3640 	} else {
3641 		/*
3642 		 * We have received an event in an unknown subclass. Ignore.
3643 		 */
3644 		zevtchan->zn_failure_count = 0;
3645 		return (0);
3646 	}
3647 }
3648 
3649 static int
3650 zn_cb(sysevent_t *ev, void *p)
3651 {
3652 	struct znotify *zevtchan = p;
3653 	int error;
3654 
3655 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
3656 
3657 	if (is_ping(ev) && !is_my_ping(ev)) {
3658 		(void) pthread_mutex_unlock((&zevtchan->zn_mutex));
3659 		return (0);
3660 	}
3661 
3662 	if (zevtchan->zn_state == ZN_LOCKED) {
3663 		assert(!is_ping(ev));
3664 		zevtchan->zn_failed = B_TRUE;
3665 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
3666 		return (0);
3667 	}
3668 
3669 	if (zevtchan->zn_state == ZN_PING_INFLIGHT) {
3670 		if (is_ping(ev)) {
3671 			zevtchan->zn_state = ZN_PING_RECEIVED;
3672 			(void) pthread_cond_signal(&(zevtchan->zn_cond));
3673 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
3674 			return (0);
3675 		} else {
3676 			zevtchan->zn_failed = B_TRUE;
3677 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
3678 			return (0);
3679 		}
3680 	}
3681 
3682 	if (zevtchan->zn_state == ZN_UNLOCKED) {
3683 
3684 		error = do_callback(zevtchan, ev);
3685 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
3686 		/*
3687 		 * Every ENOMEM failure causes do_callback to increment
3688 		 * zn_failure_count and every success causes it to
3689 		 * set zn_failure_count to zero.  If we got EAGAIN,
3690 		 * we will sleep for zn_failure_count seconds and return
3691 		 * EAGAIN to gpec to try again.
3692 		 *
3693 		 * After 55 seconds, or 10 try's we give up and drop the
3694 		 * event.
3695 		 */
3696 		if (error == EAGAIN) {
3697 			if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) {
3698 				return (0);
3699 			}
3700 			(void) sleep(zevtchan->zn_failure_count);
3701 		}
3702 		return (error);
3703 	}
3704 
3705 	if (zevtchan->zn_state == ZN_PING_RECEIVED) {
3706 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
3707 		return (0);
3708 	}
3709 
3710 	abort();
3711 	return (0);
3712 }
3713 
3714 void
3715 zonecfg_notify_critical_enter(void *h)
3716 {
3717 	struct znotify *zevtchan = h;
3718 
3719 	(void) pthread_mutex_lock(&(zevtchan->zn_bigmutex));
3720 	zevtchan->zn_state = ZN_LOCKED;
3721 }
3722 
3723 int
3724 zonecfg_notify_critical_exit(void * h)
3725 {
3726 
3727 	struct znotify *zevtchan = h;
3728 
3729 	if (zevtchan->zn_state == ZN_UNLOCKED)
3730 		return (0);
3731 
3732 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
3733 	zevtchan->zn_state = ZN_PING_INFLIGHT;
3734 
3735 	sysevent_evc_publish(zevtchan->zn_eventchan, ZONE_EVENT_STATUS_CLASS,
3736 	    ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER,
3737 	    zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP);
3738 
3739 	while (zevtchan->zn_state != ZN_PING_RECEIVED) {
3740 		(void) pthread_cond_wait(&(zevtchan->zn_cond),
3741 		    &(zevtchan->zn_mutex));
3742 	}
3743 
3744 	if (zevtchan->zn_failed == B_TRUE) {
3745 		zevtchan->zn_state = ZN_LOCKED;
3746 		zevtchan->zn_failed = B_FALSE;
3747 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
3748 		return (1);
3749 	}
3750 
3751 	zevtchan->zn_state = ZN_UNLOCKED;
3752 	(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
3753 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
3754 	return (0);
3755 }
3756 
3757 void
3758 zonecfg_notify_critical_abort(void *h)
3759 {
3760 	struct znotify *zevtchan = h;
3761 
3762 	zevtchan->zn_state = ZN_UNLOCKED;
3763 	zevtchan->zn_failed = B_FALSE;
3764 	/*
3765 	 * Don't do anything about zn_lock. If it is held, it could only be
3766 	 * held by zn_cb and it will be unlocked soon.
3767 	 */
3768 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
3769 }
3770 
3771 void *
3772 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
3773     const char *newstate, const char *oldstate, hrtime_t when, void *p),
3774     void *p)
3775 {
3776 	struct znotify *zevtchan;
3777 	int i = 1;
3778 	int r;
3779 
3780 	zevtchan = malloc(sizeof (struct znotify));
3781 
3782 	if (zevtchan == NULL)
3783 		return (NULL);
3784 
3785 	zevtchan->zn_private = p;
3786 	zevtchan->zn_callback = func;
3787 	zevtchan->zn_state = ZN_UNLOCKED;
3788 	zevtchan->zn_failed = B_FALSE;
3789 
3790 	if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL))
3791 		goto out2;
3792 	if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) {
3793 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
3794 		goto out2;
3795 	}
3796 	if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) {
3797 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
3798 		(void) pthread_cond_destroy(&(zevtchan->zn_cond));
3799 		goto out2;
3800 	}
3801 
3802 	if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan),
3803 		0) != 0)
3804 		goto out2;
3805 
3806 	do {
3807 		/*
3808 		 * At 4 digits the subscriber ID gets too long and we have
3809 		 * no chance of successfully registering.
3810 		 */
3811 		if (i > 999)
3812 			goto out;
3813 
3814 		(void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i",
3815 		    getpid() % 999999l, i);
3816 
3817 		r = sysevent_evc_subscribe(zevtchan->zn_eventchan,
3818 		    zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb,
3819 		    zevtchan, 0);
3820 
3821 		i++;
3822 
3823 	} while (r);
3824 
3825 	return (zevtchan);
3826 out:
3827 	sysevent_evc_unbind(zevtchan->zn_eventchan);
3828 	(void) pthread_mutex_destroy(&zevtchan->zn_mutex);
3829 	(void) pthread_cond_destroy(&zevtchan->zn_cond);
3830 	(void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex));
3831 out2:
3832 	free(zevtchan);
3833 
3834 	return (NULL);
3835 }
3836 
3837 void
3838 zonecfg_notify_unbind(void *handle)
3839 {
3840 
3841 	int ret;
3842 
3843 	sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan);
3844 	/*
3845 	 * Check that all evc threads have gone away. This should be
3846 	 * enforced by sysevent_evc_unbind.
3847 	 */
3848 	ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex);
3849 
3850 	if (ret)
3851 		abort();
3852 
3853 	(void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex);
3854 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex);
3855 	(void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond);
3856 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex);
3857 
3858 	free(handle);
3859 }
3860 
3861 static int
3862 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
3863 {
3864 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
3865 	int err;
3866 
3867 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL);
3868 	if ((err = newprop(newnode, DTD_ATTR_NAME,
3869 	    tabptr->zone_dataset_name)) != Z_OK)
3870 		return (err);
3871 	return (Z_OK);
3872 }
3873 
3874 int
3875 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
3876 {
3877 	int err;
3878 
3879 	if (tabptr == NULL)
3880 		return (Z_INVAL);
3881 
3882 	if ((err = operation_prep(handle)) != Z_OK)
3883 		return (err);
3884 
3885 	if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK)
3886 		return (err);
3887 
3888 	return (Z_OK);
3889 }
3890 
3891 static int
3892 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
3893 {
3894 	xmlNodePtr cur = handle->zone_dh_cur;
3895 
3896 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3897 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
3898 			continue;
3899 
3900 		if (match_prop(cur, DTD_ATTR_NAME,
3901 		    tabptr->zone_dataset_name)) {
3902 			xmlUnlinkNode(cur);
3903 			xmlFreeNode(cur);
3904 			return (Z_OK);
3905 		}
3906 	}
3907 	return (Z_NO_RESOURCE_ID);
3908 }
3909 
3910 int
3911 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
3912 {
3913 	int err;
3914 
3915 	if (tabptr == NULL)
3916 		return (Z_INVAL);
3917 
3918 	if ((err = operation_prep(handle)) != Z_OK)
3919 		return (err);
3920 
3921 	if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK)
3922 		return (err);
3923 
3924 	return (Z_OK);
3925 }
3926 
3927 int
3928 zonecfg_modify_ds(
3929 	zone_dochandle_t handle,
3930 	struct zone_dstab *oldtabptr,
3931 	struct zone_dstab *newtabptr)
3932 {
3933 	int err;
3934 
3935 	if (oldtabptr == NULL || newtabptr == NULL)
3936 		return (Z_INVAL);
3937 
3938 	if ((err = operation_prep(handle)) != Z_OK)
3939 		return (err);
3940 
3941 	if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK)
3942 		return (err);
3943 
3944 	if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK)
3945 		return (err);
3946 
3947 	return (Z_OK);
3948 }
3949 
3950 int
3951 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
3952 {
3953 	xmlNodePtr cur, firstmatch;
3954 	int err;
3955 	char dataset[MAXNAMELEN];
3956 
3957 	if (tabptr == NULL)
3958 		return (Z_INVAL);
3959 
3960 	if ((err = operation_prep(handle)) != Z_OK)
3961 		return (err);
3962 
3963 	cur = handle->zone_dh_cur;
3964 	firstmatch = NULL;
3965 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3966 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
3967 			continue;
3968 		if (strlen(tabptr->zone_dataset_name) > 0) {
3969 			if ((fetchprop(cur, DTD_ATTR_NAME, dataset,
3970 			    sizeof (dataset)) == Z_OK) &&
3971 			    (strcmp(tabptr->zone_dataset_name,
3972 			    dataset) == 0)) {
3973 				if (firstmatch == NULL)
3974 					firstmatch = cur;
3975 				else
3976 					return (Z_INSUFFICIENT_SPEC);
3977 			}
3978 		}
3979 	}
3980 	if (firstmatch == NULL)
3981 		return (Z_NO_RESOURCE_ID);
3982 
3983 	cur = firstmatch;
3984 
3985 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
3986 	    sizeof (tabptr->zone_dataset_name))) != Z_OK)
3987 		return (err);
3988 
3989 	return (Z_OK);
3990 }
3991 
3992 int
3993 zonecfg_setdsent(zone_dochandle_t handle)
3994 {
3995 	return (zonecfg_setent(handle));
3996 }
3997 
3998 int
3999 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
4000 {
4001 	xmlNodePtr cur;
4002 	int err;
4003 
4004 	if (handle == NULL)
4005 		return (Z_INVAL);
4006 
4007 	if ((cur = handle->zone_dh_cur) == NULL)
4008 		return (Z_NO_ENTRY);
4009 
4010 	for (; cur != NULL; cur = cur->next)
4011 		if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET))
4012 			break;
4013 	if (cur == NULL) {
4014 		handle->zone_dh_cur = handle->zone_dh_top;
4015 		return (Z_NO_ENTRY);
4016 	}
4017 
4018 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
4019 	    sizeof (tabptr->zone_dataset_name))) != Z_OK) {
4020 		handle->zone_dh_cur = handle->zone_dh_top;
4021 		return (err);
4022 	}
4023 
4024 	handle->zone_dh_cur = cur->next;
4025 	return (Z_OK);
4026 }
4027 
4028 int
4029 zonecfg_enddsent(zone_dochandle_t handle)
4030 {
4031 	return (zonecfg_endent(handle));
4032 }
4033