17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ee519a1fSgjelinek  * Common Development and Distribution License (the "License").
6ee519a1fSgjelinek  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21ffbafc53Scomay 
227c478bd9Sstevel@tonic-gate /*
235e74f94dSGary Mills  * Copyright 2014 Gary Mills
24a20ee416SGlenn Faden  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25*7bae76cdSJohn Levon  * Copyright (c) 2018, Joyent, Inc.
26bd93c05dSAlexander Eremin  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
29cf8f45c7Sdstaff #include <libsysevent.h>
30cf8f45c7Sdstaff #include <pthread.h>
31cf8f45c7Sdstaff #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <errno.h>
337c478bd9Sstevel@tonic-gate #include <fnmatch.h>
347c478bd9Sstevel@tonic-gate #include <strings.h>
357c478bd9Sstevel@tonic-gate #include <unistd.h>
367c478bd9Sstevel@tonic-gate #include <assert.h>
377c478bd9Sstevel@tonic-gate #include <libgen.h>
387c478bd9Sstevel@tonic-gate #include <libintl.h>
397c478bd9Sstevel@tonic-gate #include <alloca.h>
407c478bd9Sstevel@tonic-gate #include <ctype.h>
419acbbeafSnn #include <sys/acl.h>
429acbbeafSnn #include <sys/stat.h>
439acbbeafSnn #include <sys/brand.h>
447c478bd9Sstevel@tonic-gate #include <sys/mntio.h>
457c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
46cf8f45c7Sdstaff #include <sys/nvpair.h>
479acbbeafSnn #include <sys/types.h>
48f4b3ec61Sdh #include <sys/sockio.h>
495679c89fSjv #include <sys/systeminfo.h>
50ee519a1fSgjelinek #include <ftw.h>
510209230bSgjelinek #include <pool.h>
520209230bSgjelinek #include <libscf.h>
530209230bSgjelinek #include <libproc.h>
540209230bSgjelinek #include <sys/priocntl.h>
5539935be5Sgjelinek #include <libuutil.h>
56ff17c8bfSgjelinek #include <wait.h>
57ff17c8bfSgjelinek #include <bsm/adt.h>
58cb8a054bSGlenn Faden #include <auth_attr.h>
59cb8a054bSGlenn Faden #include <auth_list.h>
60cb8a054bSGlenn Faden #include <secdb.h>
61cb8a054bSGlenn Faden #include <user_attr.h>
62cb8a054bSGlenn Faden #include <prof_attr.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
657c478bd9Sstevel@tonic-gate #include <netdb.h>
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #include <libxml/xmlmemory.h>
687c478bd9Sstevel@tonic-gate #include <libxml/parser.h>
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
71108322fbScarlsonj #include <uuid/uuid.h>
72ee519a1fSgjelinek #include <dirent.h>
739acbbeafSnn #include <libbrand.h>
74ee519a1fSgjelinek 
757c478bd9Sstevel@tonic-gate #include <libzonecfg.h>
767c478bd9Sstevel@tonic-gate #include "zonecfg_impl.h"
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #define	_PATH_TMPFILE	"/zonecfg.XXXXXX"
79cf8f45c7Sdstaff #define	ZONE_CB_RETRY_COUNT		10
80cf8f45c7Sdstaff #define	ZONE_EVENT_PING_SUBCLASS	"ping"
81cf8f45c7Sdstaff #define	ZONE_EVENT_PING_PUBLISHER	"solaris"
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /* Hard-code the DTD element/attribute/entity names just once, here. */
847c478bd9Sstevel@tonic-gate #define	DTD_ELEM_ATTR		(const xmlChar *) "attr"
857c478bd9Sstevel@tonic-gate #define	DTD_ELEM_COMMENT	(const xmlChar *) "comment"
867c478bd9Sstevel@tonic-gate #define	DTD_ELEM_DEVICE		(const xmlChar *) "device"
877c478bd9Sstevel@tonic-gate #define	DTD_ELEM_FS		(const xmlChar *) "filesystem"
887c478bd9Sstevel@tonic-gate #define	DTD_ELEM_FSOPTION	(const xmlChar *) "fsoption"
897c478bd9Sstevel@tonic-gate #define	DTD_ELEM_NET		(const xmlChar *) "network"
907c478bd9Sstevel@tonic-gate #define	DTD_ELEM_RCTL		(const xmlChar *) "rctl"
917c478bd9Sstevel@tonic-gate #define	DTD_ELEM_RCTLVALUE	(const xmlChar *) "rctl-value"
927c478bd9Sstevel@tonic-gate #define	DTD_ELEM_ZONE		(const xmlChar *) "zone"
93fa9e4066Sahrens #define	DTD_ELEM_DATASET	(const xmlChar *) "dataset"
940209230bSgjelinek #define	DTD_ELEM_TMPPOOL	(const xmlChar *) "tmp_pool"
950209230bSgjelinek #define	DTD_ELEM_PSET		(const xmlChar *) "pset"
960209230bSgjelinek #define	DTD_ELEM_MCAP		(const xmlChar *) "mcap"
97ee519a1fSgjelinek #define	DTD_ELEM_PACKAGE	(const xmlChar *) "package"
986cfd72c6Sgjelinek #define	DTD_ELEM_OBSOLETES	(const xmlChar *) "obsoletes"
99ee519a1fSgjelinek #define	DTD_ELEM_DEV_PERM	(const xmlChar *) "dev-perm"
100cb8a054bSGlenn Faden #define	DTD_ELEM_ADMIN		(const xmlChar *) "admin"
101d2a70789SRichard Lowe #define	DTD_ELEM_SECFLAGS	(const xmlChar *) "security-flags"
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #define	DTD_ATTR_ACTION		(const xmlChar *) "action"
1047c478bd9Sstevel@tonic-gate #define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
105550b6e40SSowmini Varadhan #define	DTD_ATTR_ALLOWED_ADDRESS	(const xmlChar *) "allowed-address"
1067c478bd9Sstevel@tonic-gate #define	DTD_ATTR_AUTOBOOT	(const xmlChar *) "autoboot"
107f4b3ec61Sdh #define	DTD_ATTR_IPTYPE		(const xmlChar *) "ip-type"
108de860bd9Sgfaden #define	DTD_ATTR_DEFROUTER	(const xmlChar *) "defrouter"
1097c478bd9Sstevel@tonic-gate #define	DTD_ATTR_DIR		(const xmlChar *) "directory"
1107c478bd9Sstevel@tonic-gate #define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
111ffbafc53Scomay #define	DTD_ATTR_LIMITPRIV	(const xmlChar *) "limitpriv"
1123f2f09c1Sdp #define	DTD_ATTR_BOOTARGS	(const xmlChar *) "bootargs"
1130209230bSgjelinek #define	DTD_ATTR_SCHED		(const xmlChar *) "scheduling-class"
1147c478bd9Sstevel@tonic-gate #define	DTD_ATTR_MATCH		(const xmlChar *) "match"
1157c478bd9Sstevel@tonic-gate #define	DTD_ATTR_NAME		(const xmlChar *) "name"
1167c478bd9Sstevel@tonic-gate #define	DTD_ATTR_PHYSICAL	(const xmlChar *) "physical"
1177c478bd9Sstevel@tonic-gate #define	DTD_ATTR_POOL		(const xmlChar *) "pool"
1187c478bd9Sstevel@tonic-gate #define	DTD_ATTR_PRIV		(const xmlChar *) "priv"
1197c478bd9Sstevel@tonic-gate #define	DTD_ATTR_RAW		(const xmlChar *) "raw"
1207c478bd9Sstevel@tonic-gate #define	DTD_ATTR_SPECIAL	(const xmlChar *) "special"
1217c478bd9Sstevel@tonic-gate #define	DTD_ATTR_TYPE		(const xmlChar *) "type"
1227c478bd9Sstevel@tonic-gate #define	DTD_ATTR_VALUE		(const xmlChar *) "value"
1237c478bd9Sstevel@tonic-gate #define	DTD_ATTR_ZONEPATH	(const xmlChar *) "zonepath"
1240209230bSgjelinek #define	DTD_ATTR_NCPU_MIN	(const xmlChar *) "ncpu_min"
1250209230bSgjelinek #define	DTD_ATTR_NCPU_MAX	(const xmlChar *) "ncpu_max"
1260209230bSgjelinek #define	DTD_ATTR_IMPORTANCE	(const xmlChar *) "importance"
1270209230bSgjelinek #define	DTD_ATTR_PHYSCAP	(const xmlChar *) "physcap"
128ee519a1fSgjelinek #define	DTD_ATTR_VERSION	(const xmlChar *) "version"
129ee519a1fSgjelinek #define	DTD_ATTR_ID		(const xmlChar *) "id"
130ee519a1fSgjelinek #define	DTD_ATTR_UID		(const xmlChar *) "uid"
131ee519a1fSgjelinek #define	DTD_ATTR_GID		(const xmlChar *) "gid"
132ee519a1fSgjelinek #define	DTD_ATTR_MODE		(const xmlChar *) "mode"
133ee519a1fSgjelinek #define	DTD_ATTR_ACL		(const xmlChar *) "acl"
1349acbbeafSnn #define	DTD_ATTR_BRAND		(const xmlChar *) "brand"
1355679c89fSjv #define	DTD_ATTR_HOSTID		(const xmlChar *) "hostid"
136cb8a054bSGlenn Faden #define	DTD_ATTR_USER		(const xmlChar *) "user"
137cb8a054bSGlenn Faden #define	DTD_ATTR_AUTHS		(const xmlChar *) "auths"
1380fbb751dSJohn Levon #define	DTD_ATTR_FS_ALLOWED	(const xmlChar *) "fs-allowed"
139d2a70789SRichard Lowe #define	DTD_ATTR_DEFAULT	(const xmlChar *) "default"
140d2a70789SRichard Lowe #define	DTD_ATTR_LOWER		(const xmlChar *) "lower"
141d2a70789SRichard Lowe #define	DTD_ATTR_UPPER		(const xmlChar *) "upper"
142d2a70789SRichard Lowe 
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate #define	DTD_ENTITY_BOOLEAN	"boolean"
1457c478bd9Sstevel@tonic-gate #define	DTD_ENTITY_DEVPATH	"devpath"
1467c478bd9Sstevel@tonic-gate #define	DTD_ENTITY_DRIVER	"driver"
1477c478bd9Sstevel@tonic-gate #define	DTD_ENTITY_DRVMIN	"drv_min"
1487c478bd9Sstevel@tonic-gate #define	DTD_ENTITY_FALSE	"false"
1497c478bd9Sstevel@tonic-gate #define	DTD_ENTITY_INT		"int"
1507c478bd9Sstevel@tonic-gate #define	DTD_ENTITY_STRING	"string"
1517c478bd9Sstevel@tonic-gate #define	DTD_ENTITY_TRUE		"true"
1527c478bd9Sstevel@tonic-gate #define	DTD_ENTITY_UINT		"uint"
1537c478bd9Sstevel@tonic-gate 
154a1be23daSdp #define	DTD_ENTITY_BOOL_LEN	6	/* "false" */
155a1be23daSdp 
156ee519a1fSgjelinek #define	ATTACH_FORCED	"SUNWattached.xml"
157ee519a1fSgjelinek 
1580209230bSgjelinek #define	TMP_POOL_NAME	"SUNWtmp_%s"
1590209230bSgjelinek #define	MAX_TMP_POOL_NAME	(ZONENAME_MAX + 9)
1600209230bSgjelinek #define	RCAP_SERVICE	"system/rcap:default"
1610209230bSgjelinek #define	POOLD_SERVICE	"system/pools/dynamic:default"
1620209230bSgjelinek 
1630209230bSgjelinek /*
1640209230bSgjelinek  * rctl alias definitions
1650209230bSgjelinek  *
1660209230bSgjelinek  * This holds the alias, the full rctl name, the default priv value, action
1670209230bSgjelinek  * and lower limit.  The functions that handle rctl aliases step through
1680209230bSgjelinek  * this table, matching on the alias, and using the full values for setting
1690209230bSgjelinek  * the rctl entry as well the limit for validation.
1700209230bSgjelinek  */
1710209230bSgjelinek static struct alias {
1720209230bSgjelinek 	char *shortname;
1730209230bSgjelinek 	char *realname;
1740209230bSgjelinek 	char *priv;
1750209230bSgjelinek 	char *action;
1760209230bSgjelinek 	uint64_t low_limit;
1770209230bSgjelinek } aliases[] = {
1780209230bSgjelinek 	{ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
1790209230bSgjelinek 	{ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
1800209230bSgjelinek 	{ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
1810209230bSgjelinek 	{ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
1820209230bSgjelinek 	{ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
1830209230bSgjelinek 	{ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
1840209230bSgjelinek 	{ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
1850209230bSgjelinek 	{ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
186c97ad5cdSakolb 	{ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
187ff19e029SMenno Lageman 	{ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
1880209230bSgjelinek 	{NULL, NULL, NULL, NULL, 0}
1890209230bSgjelinek };
1900209230bSgjelinek 
1910209230bSgjelinek /*
1920209230bSgjelinek  * Structure for applying rctls to a running zone.  It allows important
1930209230bSgjelinek  * process values to be passed together easily.
1940209230bSgjelinek  */
1950209230bSgjelinek typedef struct pr_info_handle {
1960209230bSgjelinek 	struct ps_prochandle *pr;
1970209230bSgjelinek 	pid_t pid;
1980209230bSgjelinek } pr_info_handle_t;
1990209230bSgjelinek 
2007c478bd9Sstevel@tonic-gate struct zone_dochandle {
2017c478bd9Sstevel@tonic-gate 	char		*zone_dh_rootdir;
2027c478bd9Sstevel@tonic-gate 	xmlDocPtr	zone_dh_doc;
2037c478bd9Sstevel@tonic-gate 	xmlNodePtr	zone_dh_cur;
2047c478bd9Sstevel@tonic-gate 	xmlNodePtr	zone_dh_top;
205087719fdSdp 	boolean_t	zone_dh_newzone;
206087719fdSdp 	boolean_t	zone_dh_snapshot;
207ee519a1fSgjelinek 	boolean_t	zone_dh_sw_inv;
208cb8a054bSGlenn Faden 	zone_userauths_t	*zone_dh_userauths;
209087719fdSdp 	char		zone_dh_delete_name[ZONENAME_MAX];
2107c478bd9Sstevel@tonic-gate };
2117c478bd9Sstevel@tonic-gate 
212cf8f45c7Sdstaff struct znotify {
213cf8f45c7Sdstaff 	void * zn_private;
214cf8f45c7Sdstaff 	evchan_t *zn_eventchan;
215cf8f45c7Sdstaff 	int (*zn_callback)(const  char *zonename, zoneid_t zid,
216cf8f45c7Sdstaff 	    const char *newstate, const char *oldstate, hrtime_t when, void *p);
217cf8f45c7Sdstaff 	pthread_mutex_t zn_mutex;
218cf8f45c7Sdstaff 	pthread_cond_t zn_cond;
219cf8f45c7Sdstaff 	pthread_mutex_t zn_bigmutex;
220cf8f45c7Sdstaff 	volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
221cf8f45c7Sdstaff 	    ZN_PING_RECEIVED} zn_state;
222cf8f45c7Sdstaff 	char zn_subscriber_id[MAX_SUBID_LEN];
223cf8f45c7Sdstaff 	volatile boolean_t zn_failed;
224cf8f45c7Sdstaff 	int zn_failure_count;
225cf8f45c7Sdstaff };
226cf8f45c7Sdstaff 
227ff17c8bfSgjelinek /* used to track nested zone-lock operations */
228ff17c8bfSgjelinek static int zone_lock_cnt = 0;
2296cfd72c6Sgjelinek 
230ff17c8bfSgjelinek /* used to communicate lock status to children */
231ff17c8bfSgjelinek #define	LOCK_ENV_VAR	"_ZONEADM_LOCK_HELD"
232ff17c8bfSgjelinek static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1";
233ff17c8bfSgjelinek static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0";
23439935be5Sgjelinek 
235108322fbScarlsonj char *zonecfg_root = "";
236108322fbScarlsonj 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * For functions which return int, which is most of the functions herein,
2397c478bd9Sstevel@tonic-gate  * the return values should be from the Z_foo set defined in <libzonecfg.h>.
2407c478bd9Sstevel@tonic-gate  * In some instances, we take pains mapping some libc errno values to Z_foo
2417c478bd9Sstevel@tonic-gate  * values from this set.
2427c478bd9Sstevel@tonic-gate  */
2437c478bd9Sstevel@tonic-gate 
244108322fbScarlsonj /*
245108322fbScarlsonj  * Set the root (/) path for all zonecfg configuration files.  This is a
246108322fbScarlsonj  * private interface used by Live Upgrade extensions to access zone
247108322fbScarlsonj  * configuration inside mounted alternate boot environments.
2482a8b76b2SSusan Kamm-Worrell  * This interface is also used by zoneadm mount and unmount subcommands.
249108322fbScarlsonj  */
250108322fbScarlsonj void
zonecfg_set_root(const char * rootpath)251108322fbScarlsonj zonecfg_set_root(const char *rootpath)
252108322fbScarlsonj {
253108322fbScarlsonj 	if (*zonecfg_root != '\0')
254108322fbScarlsonj 		free(zonecfg_root);
255108322fbScarlsonj 	if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
256108322fbScarlsonj 	    (zonecfg_root = strdup(rootpath)) == NULL)
257108322fbScarlsonj 		zonecfg_root = "";
258108322fbScarlsonj }
259108322fbScarlsonj 
260108322fbScarlsonj const char *
zonecfg_get_root(void)261108322fbScarlsonj zonecfg_get_root(void)
262108322fbScarlsonj {
263108322fbScarlsonj 	return (zonecfg_root);
264108322fbScarlsonj }
265108322fbScarlsonj 
266108322fbScarlsonj boolean_t
zonecfg_in_alt_root(void)267108322fbScarlsonj zonecfg_in_alt_root(void)
268108322fbScarlsonj {
269108322fbScarlsonj 	return (*zonecfg_root != '\0');
270108322fbScarlsonj }
271108322fbScarlsonj 
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate  * Callers of the _file_path() functions are expected to have the second
2747c478bd9Sstevel@tonic-gate  * parameter be a (char foo[MAXPATHLEN]).
2757c478bd9Sstevel@tonic-gate  */
2767c478bd9Sstevel@tonic-gate 
277108322fbScarlsonj static boolean_t
config_file_path(const char * zonename,char * answer)2787c478bd9Sstevel@tonic-gate config_file_path(const char *zonename, char *answer)
2797c478bd9Sstevel@tonic-gate {
280108322fbScarlsonj 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
281108322fbScarlsonj 	    ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
284108322fbScarlsonj static boolean_t
snap_file_path(const char * zonename,char * answer)285108322fbScarlsonj snap_file_path(const char *zonename, char *answer)
2867c478bd9Sstevel@tonic-gate {
287108322fbScarlsonj 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
288108322fbScarlsonj 	    zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2927c478bd9Sstevel@tonic-gate static void
zonecfg_error_func(void * ctx,const char * msg,...)2937c478bd9Sstevel@tonic-gate zonecfg_error_func(void *ctx, const char *msg, ...)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate 	/*
2967c478bd9Sstevel@tonic-gate 	 * This function does nothing by design.  Its purpose is to prevent
2977c478bd9Sstevel@tonic-gate 	 * libxml from dumping unwanted messages to stdout/stderr.
2987c478bd9Sstevel@tonic-gate 	 */
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate zone_dochandle_t
zonecfg_init_handle(void)3027c478bd9Sstevel@tonic-gate zonecfg_init_handle(void)
3037c478bd9Sstevel@tonic-gate {
304087719fdSdp 	zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
3057c478bd9Sstevel@tonic-gate 	if (handle == NULL) {
3067c478bd9Sstevel@tonic-gate 		errno = Z_NOMEM;
3077c478bd9Sstevel@tonic-gate 		return (NULL);
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/* generic libxml initialization */
311ced33dd6Sjv 	(void) xmlLineNumbersDefault(1);
3127c478bd9Sstevel@tonic-gate 	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
3137c478bd9Sstevel@tonic-gate 	xmlDoValidityCheckingDefaultValue = 1;
3147c478bd9Sstevel@tonic-gate 	(void) xmlKeepBlanksDefault(0);
3157c478bd9Sstevel@tonic-gate 	xmlGetWarningsDefaultValue = 0;
3167c478bd9Sstevel@tonic-gate 	xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	return (handle);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate int
zonecfg_check_handle(zone_dochandle_t handle)3227c478bd9Sstevel@tonic-gate zonecfg_check_handle(zone_dochandle_t handle)
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate 	if (handle == NULL || handle->zone_dh_doc == NULL)
3257c478bd9Sstevel@tonic-gate 		return (Z_BAD_HANDLE);
3267c478bd9Sstevel@tonic-gate 	return (Z_OK);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate void
zonecfg_fini_handle(zone_dochandle_t handle)3307c478bd9Sstevel@tonic-gate zonecfg_fini_handle(zone_dochandle_t handle)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate 	if (zonecfg_check_handle(handle) == Z_OK)
3337c478bd9Sstevel@tonic-gate 		xmlFreeDoc(handle->zone_dh_doc);
3347c478bd9Sstevel@tonic-gate 	if (handle != NULL)
3357c478bd9Sstevel@tonic-gate 		free(handle);
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate static int
zonecfg_destroy_impl(char * filename)3397c478bd9Sstevel@tonic-gate zonecfg_destroy_impl(char *filename)
3407c478bd9Sstevel@tonic-gate {
3417c478bd9Sstevel@tonic-gate 	if (unlink(filename) == -1) {
3427c478bd9Sstevel@tonic-gate 		if (errno == EACCES)
3437c478bd9Sstevel@tonic-gate 			return (Z_ACCES);
3447c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)
3457c478bd9Sstevel@tonic-gate 			return (Z_NO_ZONE);
3467c478bd9Sstevel@tonic-gate 		return (Z_MISC_FS);
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 	return (Z_OK);
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate int
zonecfg_destroy(const char * zonename,boolean_t force)352087719fdSdp zonecfg_destroy(const char *zonename, boolean_t force)
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
355087719fdSdp 	struct zoneent ze;
356087719fdSdp 	int err, state_err;
357087719fdSdp 	zone_state_t state;
3587c478bd9Sstevel@tonic-gate 
359108322fbScarlsonj 	if (!config_file_path(zonename, path))
360108322fbScarlsonj 		return (Z_MISC_FS);
361087719fdSdp 
362087719fdSdp 	state_err = zone_get_state((char *)zonename, &state);
363087719fdSdp 	err = access(path, W_OK);
364087719fdSdp 
365087719fdSdp 	/*
366087719fdSdp 	 * If there is no file, and no index entry, reliably indicate that no
367087719fdSdp 	 * such zone exists.
368087719fdSdp 	 */
369087719fdSdp 	if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
370087719fdSdp 		return (Z_NO_ZONE);
371087719fdSdp 
372087719fdSdp 	/*
373087719fdSdp 	 * Handle any other filesystem related errors (except if the XML
374087719fdSdp 	 * file is missing, which we treat silently), unless we're forcing,
375087719fdSdp 	 * in which case we plow on.
376087719fdSdp 	 */
377087719fdSdp 	if (err == -1 && errno != ENOENT) {
378087719fdSdp 		if (errno == EACCES)
379087719fdSdp 			return (Z_ACCES);
380087719fdSdp 		else if (!force)
381087719fdSdp 			return (Z_MISC_FS);
382087719fdSdp 	}
383087719fdSdp 
384087719fdSdp 	if (state > ZONE_STATE_INSTALLED)
385087719fdSdp 		return (Z_BAD_ZONE_STATE);
386087719fdSdp 
387087719fdSdp 	if (!force && state > ZONE_STATE_CONFIGURED)
388087719fdSdp 		return (Z_BAD_ZONE_STATE);
389087719fdSdp 
390087719fdSdp 	/*
391087719fdSdp 	 * Index deletion succeeds even if the entry doesn't exist.  So this
392087719fdSdp 	 * will fail only if we've had some more severe problem.
393087719fdSdp 	 */
394087719fdSdp 	bzero(&ze, sizeof (ze));
395087719fdSdp 	(void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
396087719fdSdp 	if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
397087719fdSdp 		if (!force)
398087719fdSdp 			return (err);
399087719fdSdp 
400087719fdSdp 	err = zonecfg_destroy_impl(path);
401087719fdSdp 
402087719fdSdp 	/*
403087719fdSdp 	 * Treat failure to find the XML file silently, since, well, it's
404087719fdSdp 	 * gone, and with the index file cleaned up, we're done.
405087719fdSdp 	 */
406087719fdSdp 	if (err == Z_OK || err == Z_NO_ZONE)
407087719fdSdp 		return (Z_OK);
408087719fdSdp 	return (err);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate int
zonecfg_destroy_snapshot(const char * zonename)412108322fbScarlsonj zonecfg_destroy_snapshot(const char *zonename)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
4157c478bd9Sstevel@tonic-gate 
416108322fbScarlsonj 	if (!snap_file_path(zonename, path))
417108322fbScarlsonj 		return (Z_MISC_FS);
4187c478bd9Sstevel@tonic-gate 	return (zonecfg_destroy_impl(path));
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate static int
getroot(zone_dochandle_t handle,xmlNodePtr * root)422a1be23daSdp getroot(zone_dochandle_t handle, xmlNodePtr *root)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate 	if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
4257c478bd9Sstevel@tonic-gate 		return (Z_BAD_HANDLE);
4267c478bd9Sstevel@tonic-gate 
427a1be23daSdp 	*root = xmlDocGetRootElement(handle->zone_dh_doc);
428a1be23daSdp 
429a1be23daSdp 	if (*root == NULL)
4307c478bd9Sstevel@tonic-gate 		return (Z_EMPTY_DOCUMENT);
4317c478bd9Sstevel@tonic-gate 
432a1be23daSdp 	if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
4337c478bd9Sstevel@tonic-gate 		return (Z_WRONG_DOC_TYPE);
434a1be23daSdp 
435a1be23daSdp 	return (Z_OK);
436a1be23daSdp }
437a1be23daSdp 
438a1be23daSdp static int
operation_prep(zone_dochandle_t handle)439a1be23daSdp operation_prep(zone_dochandle_t handle)
440a1be23daSdp {
441a1be23daSdp 	xmlNodePtr root;
442a1be23daSdp 	int err;
443a1be23daSdp 
444a1be23daSdp 	if ((err = getroot(handle, &root)) != 0)
445a1be23daSdp 		return (err);
446a1be23daSdp 
447a1be23daSdp 	handle->zone_dh_cur = root;
448a1be23daSdp 	handle->zone_dh_top = root;
449a1be23daSdp 	return (Z_OK);
450a1be23daSdp }
451a1be23daSdp 
452ffbafc53Scomay static int
fetchprop(xmlNodePtr cur,const xmlChar * propname,char * dst,size_t dstsize)453ffbafc53Scomay fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
454ffbafc53Scomay {
455ffbafc53Scomay 	xmlChar *property;
456ffbafc53Scomay 	size_t srcsize;
457ffbafc53Scomay 
458ffbafc53Scomay 	if ((property = xmlGetProp(cur, propname)) == NULL)
459ffbafc53Scomay 		return (Z_BAD_PROPERTY);
460ffbafc53Scomay 	srcsize = strlcpy(dst, (char *)property, dstsize);
461ffbafc53Scomay 	xmlFree(property);
462ffbafc53Scomay 	if (srcsize >= dstsize)
463ffbafc53Scomay 		return (Z_TOO_BIG);
464ffbafc53Scomay 	return (Z_OK);
465ffbafc53Scomay }
466ffbafc53Scomay 
467ffbafc53Scomay static int
fetch_alloc_prop(xmlNodePtr cur,const xmlChar * propname,char ** dst)468ffbafc53Scomay fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst)
469ffbafc53Scomay {
470ffbafc53Scomay 	xmlChar *property;
471ffbafc53Scomay 
472ffbafc53Scomay 	if ((property = xmlGetProp(cur, propname)) == NULL)
473ffbafc53Scomay 		return (Z_BAD_PROPERTY);
474ffbafc53Scomay 	if ((*dst = strdup((char *)property)) == NULL) {
475ffbafc53Scomay 		xmlFree(property);
476ffbafc53Scomay 		return (Z_NOMEM);
477ffbafc53Scomay 	}
478ffbafc53Scomay 	xmlFree(property);
479ffbafc53Scomay 	return (Z_OK);
480ffbafc53Scomay }
481ffbafc53Scomay 
482a1be23daSdp static int
getrootattr(zone_dochandle_t handle,const xmlChar * propname,char * propval,size_t propsize)483a1be23daSdp getrootattr(zone_dochandle_t handle, const xmlChar *propname,
484a1be23daSdp     char *propval, size_t propsize)
485a1be23daSdp {
486a1be23daSdp 	xmlNodePtr root;
487a1be23daSdp 	int err;
488a1be23daSdp 
489a1be23daSdp 	if ((err = getroot(handle, &root)) != 0)
490a1be23daSdp 		return (err);
491a1be23daSdp 
492ffbafc53Scomay 	return (fetchprop(root, propname, propval, propsize));
493ffbafc53Scomay }
494ffbafc53Scomay 
495ffbafc53Scomay static int
get_alloc_rootattr(zone_dochandle_t handle,const xmlChar * propname,char ** propval)496ffbafc53Scomay get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname,
497ffbafc53Scomay     char **propval)
498ffbafc53Scomay {
499ffbafc53Scomay 	xmlNodePtr root;
500ffbafc53Scomay 	int err;
501ffbafc53Scomay 
502ffbafc53Scomay 	if ((err = getroot(handle, &root)) != 0)
503ffbafc53Scomay 		return (err);
504ffbafc53Scomay 
505ffbafc53Scomay 	return (fetch_alloc_prop(root, propname, propval));
506a1be23daSdp }
507a1be23daSdp 
508a1be23daSdp static int
setrootattr(zone_dochandle_t handle,const xmlChar * propname,const char * propval)509108322fbScarlsonj setrootattr(zone_dochandle_t handle, const xmlChar *propname,
510108322fbScarlsonj     const char *propval)
511a1be23daSdp {
512a1be23daSdp 	int err;
513a1be23daSdp 	xmlNodePtr root;
514a1be23daSdp 
515a1be23daSdp 	if ((err = getroot(handle, &root)) != Z_OK)
516a1be23daSdp 		return (err);
517a1be23daSdp 
5180209230bSgjelinek 	/*
5190209230bSgjelinek 	 * If we get a null propval remove the property (ignore return since it
5200209230bSgjelinek 	 * may not be set to begin with).
5210209230bSgjelinek 	 */
5220209230bSgjelinek 	if (propval == NULL) {
5230209230bSgjelinek 		(void) xmlUnsetProp(root, propname);
5240209230bSgjelinek 	} else {
5250209230bSgjelinek 		if (xmlSetProp(root, propname, (const xmlChar *) propval)
5260209230bSgjelinek 		    == NULL)
5270209230bSgjelinek 			return (Z_INVAL);
5280209230bSgjelinek 	}
5297c478bd9Sstevel@tonic-gate 	return (Z_OK);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
532087719fdSdp static void
addcomment(zone_dochandle_t handle,const char * comment)533087719fdSdp addcomment(zone_dochandle_t handle, const char *comment)
534087719fdSdp {
535087719fdSdp 	xmlNodePtr node;
536087719fdSdp 	node = xmlNewComment((xmlChar *) comment);
537087719fdSdp 
538087719fdSdp 	if (node != NULL)
539087719fdSdp 		(void) xmlAddPrevSibling(handle->zone_dh_top, node);
540087719fdSdp }
541087719fdSdp 
542087719fdSdp static void
stripcomments(zone_dochandle_t handle)543087719fdSdp stripcomments(zone_dochandle_t handle)
544087719fdSdp {
545087719fdSdp 	xmlDocPtr top;
546087719fdSdp 	xmlNodePtr child, next;
547087719fdSdp 
548087719fdSdp 	top = handle->zone_dh_doc;
549087719fdSdp 	for (child = top->xmlChildrenNode; child != NULL; child = next) {
550087719fdSdp 		next = child->next;
551087719fdSdp 		if (child->name == NULL)
552087719fdSdp 			continue;
553087719fdSdp 		if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
554087719fdSdp 			next = child->next;
555087719fdSdp 			xmlUnlinkNode(child);
556087719fdSdp 			xmlFreeNode(child);
557087719fdSdp 		}
558087719fdSdp 	}
559087719fdSdp }
560087719fdSdp 
561ee519a1fSgjelinek static void
strip_sw_inv(zone_dochandle_t handle)562ee519a1fSgjelinek strip_sw_inv(zone_dochandle_t handle)
563ee519a1fSgjelinek {
564ee519a1fSgjelinek 	xmlNodePtr root, child, next;
565ee519a1fSgjelinek 
566ee519a1fSgjelinek 	root = xmlDocGetRootElement(handle->zone_dh_doc);
567ee519a1fSgjelinek 	for (child = root->xmlChildrenNode; child != NULL; child = next) {
568ee519a1fSgjelinek 		next = child->next;
569ee519a1fSgjelinek 		if (child->name == NULL)
570ee519a1fSgjelinek 			continue;
5714656d474SGarrett D'Amore 		if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0) {
572ee519a1fSgjelinek 			next = child->next;
573ee519a1fSgjelinek 			xmlUnlinkNode(child);
574ee519a1fSgjelinek 			xmlFreeNode(child);
575ee519a1fSgjelinek 		}
576ee519a1fSgjelinek 	}
577ee519a1fSgjelinek }
578ee519a1fSgjelinek 
5797c478bd9Sstevel@tonic-gate static int
zonecfg_get_handle_impl(const char * zonename,const char * filename,zone_dochandle_t handle)580108322fbScarlsonj zonecfg_get_handle_impl(const char *zonename, const char *filename,
581108322fbScarlsonj     zone_dochandle_t handle)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate 	xmlValidCtxtPtr cvp;
5847c478bd9Sstevel@tonic-gate 	struct stat statbuf;
5857c478bd9Sstevel@tonic-gate 	int valid;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	if (zonename == NULL)
5887c478bd9Sstevel@tonic-gate 		return (Z_NO_ZONE);
5899acbbeafSnn 
5907c478bd9Sstevel@tonic-gate 	if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
5917c478bd9Sstevel@tonic-gate 		/* distinguish file not found vs. found but not parsed */
5927c478bd9Sstevel@tonic-gate 		if (stat(filename, &statbuf) == 0)
5937c478bd9Sstevel@tonic-gate 			return (Z_INVALID_DOCUMENT);
5947c478bd9Sstevel@tonic-gate 		return (Z_NO_ZONE);
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate 	if ((cvp = xmlNewValidCtxt()) == NULL)
5977c478bd9Sstevel@tonic-gate 		return (Z_NOMEM);
5987c478bd9Sstevel@tonic-gate 	cvp->error = zonecfg_error_func;
5997c478bd9Sstevel@tonic-gate 	cvp->warning = zonecfg_error_func;
6007c478bd9Sstevel@tonic-gate 	valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
6017c478bd9Sstevel@tonic-gate 	xmlFreeValidCtxt(cvp);
6027c478bd9Sstevel@tonic-gate 	if (valid == 0)
6037c478bd9Sstevel@tonic-gate 		return (Z_INVALID_DOCUMENT);
604087719fdSdp 
6057c478bd9Sstevel@tonic-gate 	/* delete any comments such as inherited Sun copyright / ident str */
606087719fdSdp 	stripcomments(handle);
6077c478bd9Sstevel@tonic-gate 	return (Z_OK);
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate int
zonecfg_get_handle(const char * zonename,zone_dochandle_t handle)611108322fbScarlsonj zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
6147c478bd9Sstevel@tonic-gate 
615108322fbScarlsonj 	if (!config_file_path(zonename, path))
616108322fbScarlsonj 		return (Z_MISC_FS);
617087719fdSdp 	handle->zone_dh_newzone = B_FALSE;
618087719fdSdp 
6197c478bd9Sstevel@tonic-gate 	return (zonecfg_get_handle_impl(zonename, path, handle));
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate 
622ee519a1fSgjelinek int
zonecfg_get_attach_handle(const char * path,const char * fname,const char * zonename,boolean_t preserve_sw,zone_dochandle_t handle)62316ab8c7bSgjelinek zonecfg_get_attach_handle(const char *path, const char *fname,
62416ab8c7bSgjelinek     const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
625ee519a1fSgjelinek {
626ee519a1fSgjelinek 	char		migpath[MAXPATHLEN];
627ee519a1fSgjelinek 	int		err;
628ee519a1fSgjelinek 	struct stat	buf;
629ee519a1fSgjelinek 
630ee519a1fSgjelinek 	if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
631ee519a1fSgjelinek 	    sizeof (migpath))
632ee519a1fSgjelinek 		return (Z_NOMEM);
633ee519a1fSgjelinek 
634ee519a1fSgjelinek 	if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
635ee519a1fSgjelinek 		return (Z_NO_ZONE);
636ee519a1fSgjelinek 
63716ab8c7bSgjelinek 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, fname) >=
638ee519a1fSgjelinek 	    sizeof (migpath))
639ee519a1fSgjelinek 		return (Z_NOMEM);
640ee519a1fSgjelinek 
641ee519a1fSgjelinek 	if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
642ee519a1fSgjelinek 		return (err);
643ee519a1fSgjelinek 
644ee519a1fSgjelinek 	if (!preserve_sw)
645ee519a1fSgjelinek 		strip_sw_inv(handle);
646ee519a1fSgjelinek 
647ee519a1fSgjelinek 	handle->zone_dh_newzone = B_TRUE;
648ee519a1fSgjelinek 	if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
649ee519a1fSgjelinek 		return (err);
650ee519a1fSgjelinek 
651ee519a1fSgjelinek 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
652ee519a1fSgjelinek }
653ee519a1fSgjelinek 
6547c478bd9Sstevel@tonic-gate int
zonecfg_get_snapshot_handle(const char * zonename,zone_dochandle_t handle)655108322fbScarlsonj zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
6567c478bd9Sstevel@tonic-gate {
6577c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
6587c478bd9Sstevel@tonic-gate 
659108322fbScarlsonj 	if (!snap_file_path(zonename, path))
660108322fbScarlsonj 		return (Z_MISC_FS);
661087719fdSdp 	handle->zone_dh_newzone = B_FALSE;
6627c478bd9Sstevel@tonic-gate 	return (zonecfg_get_handle_impl(zonename, path, handle));
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate 
665087719fdSdp int
zonecfg_get_template_handle(const char * template,const char * zonename,zone_dochandle_t handle)666108322fbScarlsonj zonecfg_get_template_handle(const char *template, const char *zonename,
667087719fdSdp     zone_dochandle_t handle)
668087719fdSdp {
669087719fdSdp 	char path[MAXPATHLEN];
670087719fdSdp 	int err;
671087719fdSdp 
672108322fbScarlsonj 	if (!config_file_path(template, path))
673108322fbScarlsonj 		return (Z_MISC_FS);
674087719fdSdp 
675087719fdSdp 	if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
676087719fdSdp 		return (err);
677087719fdSdp 	handle->zone_dh_newzone = B_TRUE;
678087719fdSdp 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
679087719fdSdp }
680087719fdSdp 
6819acbbeafSnn int
zonecfg_get_xml_handle(const char * path,zone_dochandle_t handle)6829acbbeafSnn zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
6839acbbeafSnn {
6849acbbeafSnn 	struct stat buf;
6859acbbeafSnn 	int err;
6869acbbeafSnn 
6879acbbeafSnn 	if (stat(path, &buf) == -1)
6889acbbeafSnn 		return (Z_MISC_FS);
6899acbbeafSnn 
6909acbbeafSnn 	if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
6919acbbeafSnn 		return (err);
6929acbbeafSnn 	handle->zone_dh_newzone = B_TRUE;
6939acbbeafSnn 	return (Z_OK);
6949acbbeafSnn }
6959acbbeafSnn 
6968cd327d5Sgjelinek /*
6978cd327d5Sgjelinek  * Initialize two handles from the manifest read on fd.  The rem_handle
6988cd327d5Sgjelinek  * is initialized from the input file, including the sw inventory.  The
6998cd327d5Sgjelinek  * local_handle is initialized with the same zone configuration but with
7008cd327d5Sgjelinek  * no sw inventory.
7018cd327d5Sgjelinek  */
7028cd327d5Sgjelinek int
zonecfg_attach_manifest(int fd,zone_dochandle_t local_handle,zone_dochandle_t rem_handle)7038cd327d5Sgjelinek zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
7048cd327d5Sgjelinek     zone_dochandle_t rem_handle)
7058cd327d5Sgjelinek {