15928 integrate sample zones management module
authorSteve Lawrence <Stephen.Lawrence@Sun.COM>
Wed, 12 May 2010 16:54:43 -0700
changeset 502 c25750fb55a6
parent 501 23b6b2759539
child 505 c902076ef90a
15928 integrate sample zones management module
usr/src/cmd/rad/mod/Makefile
usr/src/cmd/rad/mod/zones/Makefile
usr/src/cmd/rad/mod/zones/api_zones.c
usr/src/cmd/rad/mod/zones/mod_zones.c
usr/src/cmd/zmgr/zmgr.py
usr/src/cmd/zmgr/ztest.py
usr/src/lib/pyrad/client.py
--- a/usr/src/cmd/rad/mod/Makefile	Fri May 07 17:25:43 2010 -0700
+++ b/usr/src/cmd/rad/mod/Makefile	Wed May 12 16:54:43 2010 -0700
@@ -36,7 +36,9 @@
 	smf \
 	sysid \
 	test \
-	time
+	time \
+	zones
+
 MODULE_SUBDIRS_sparc = $(MODULE_SUBDIRS)
 MODULE_SUBDIRS_i386 = $(MODULE_SUBDIRS) hypervisor
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/rad/mod/zones/Makefile	Wed May 12 16:54:43 2010 -0700
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.env
+
+LDLIBS=-lzonecfg
+MOD_APIS=zones
+MOD_OBJS=mod_zones.o api_zones.o
+MOD_LIBNAME=mod_zones.so
+MOD_INSTALLDIR=$(RADDIR_MODULE)
+
+include ../Makefile.com
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/rad/mod/zones/api_zones.c	Wed May 12 16:54:43 2010 -0700
@@ -0,0 +1,1544 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <libdladm.h>
+#include <libdllink.h>
+#include <libzonecfg.h>
+#include <limits.h>
+#include <locale.h>
+#include <netinet/in.h>
+#include <sys/priocntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <stropts.h>
+#include <sys/fork.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+#include <zone.h>
+#include "api_zones.h"
+#include "rad_object.h"
+#include "rad_adr.h"
+
+/*
+ * Creates a zone error struct based on a zones error code
+ */
+static data_t *
+zone_create_error(char *string)
+{
+	data_t *error = NULL;
+	data_t *ecode = NULL;
+	data_t *msg = NULL;
+
+	error = data_new_struct(&t__ZonesError);
+	if (error == NULL)
+		goto err;
+	ecode = data_new_enum_byname(&t__ZonesErrorCode, string);
+	if (ecode == NULL)
+		goto err;
+
+	struct_set(error, "error", ecode);
+
+	msg = data_new_string(string, lt_copy);
+	struct_set(error, "message", msg);
+
+	return (error);
+err:
+	if (error)
+		data_free(error);
+	return (NULL);
+}
+
+
+conerr_t
+api_SchedulerManagement_invoke_setDefaultScheduler(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_SchedulerManagement_invoke_setDefaultScheduler\n");
+	return (ce_system);
+}
+
+void
+delete_configured_interfaces(zone_dochandle_t handle)
+{
+	struct zone_nwiftab tab;
+
+	for (;;) {
+		if (zonecfg_setnwifent(handle) != Z_OK)
+			return;
+
+		if (zonecfg_getnwifent(handle, &tab) != Z_OK)
+			break;
+
+		(void) zonecfg_delete_nwif(handle, &tab);
+		zonecfg_endnwifent(handle);
+	}
+	zonecfg_endnwifent(handle);
+}
+
+int
+set_configured_interfaces(zone_dochandle_t handle, data_t *cfg,
+    zone_iptype_t ziptype, data_t **error)
+{
+	data_t *networks;
+	data_t *net;
+	data_t *string;
+	int i;
+	struct zone_nwiftab tab;
+
+	networks = struct_get(cfg, "networks");
+	if (networks == NULL)
+		return (0);
+
+	for (i = 0; i < array_size(networks); i++) {
+
+		net = array_get(networks, i);
+		if (net == NULL)
+			continue;
+
+		tab.zone_nwif_address[0] = '\0';
+		tab.zone_nwif_physical[0] = '\0';
+		tab.zone_nwif_defrouter[0] = '\0';
+
+		/* XXX need some funcs to validate physical and address */
+		string = struct_get(net, "physical");
+		(void) strlcpy(tab.zone_nwif_physical, data_to_string(string),
+		    sizeof (tab.zone_nwif_physical));
+
+		string = struct_get(net, "address");
+		(void) strlcpy(tab.zone_nwif_address, data_to_string(string),
+		    sizeof (tab.zone_nwif_address));
+
+		/* physical must be specified */
+		if (tab.zone_nwif_physical[0] == '\0') {
+			*error = zone_create_error("INVALIDNETWORK");
+			return (-1);
+		}
+		/* Exclusive stack zones cannot specify ip addresses */
+		if (ziptype == ZS_EXCLUSIVE &&
+		    tab.zone_nwif_address[0] != '\0') {
+			*error = zone_create_error("INVALIDNETWORK");
+			return (-1);
+		}
+
+		/* Shared stack zones must specify ip addresses */
+		if (ziptype == ZS_SHARED &&
+		    tab.zone_nwif_address[0] == '\0') {
+			*error = zone_create_error("INVALIDNETWORK");
+			return (-1);
+		}
+
+		/* Add network to zone's configuation */
+		if (zonecfg_add_nwif(handle, &tab) != Z_OK) {
+			return (-1);
+		}
+	}
+	return (0);
+}
+
+static data_t *
+get_configured_interfaces(zone_dochandle_t handle, boolean_t noglobalcfg)
+{
+	data_t *networks, *net, *string;
+	struct zone_nwiftab tab;
+
+	networks = data_new_array(&t_array__Network, 0);
+	if (networks == NULL)
+		goto err;
+
+	if (noglobalcfg)
+		return (networks);
+
+	if (zonecfg_setnwifent(handle) != Z_OK)
+		return (NULL);
+
+	while (zonecfg_getnwifent(handle, &tab) == Z_OK) {
+
+		net = data_new_struct(&t__Network);
+		if (net == NULL)
+			goto err;
+
+		if (array_add(networks, net) != 0) {
+			data_free(net);
+			goto err;
+		}
+
+		string = data_new_string(tab.zone_nwif_physical, lt_copy);
+		if (string == NULL)
+			goto err;
+		struct_set(net, "physical", string);
+
+		string = data_new_string(tab.zone_nwif_address, lt_copy);
+		if (string == NULL)
+			goto err;
+		struct_set(net, "address", string);
+
+	}
+	zonecfg_endnwifent(handle);
+	return (networks);
+err:
+	zonecfg_endnwifent(handle);
+
+	if (networks != NULL)
+		data_free(networks);
+
+	return (NULL);
+}
+
+conerr_t
+api_zonesManagement_invoke_getZoneConfig(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count,
+    data_t **error)
+{
+	const char *zonename;
+	data_t *config = NULL;
+	data_t *string;
+	data_t *iptype;
+	data_t *networks;
+	data_t *err = NULL;
+	char  path[MAXPATHLEN];
+	char class[PC_CLNMSZ];
+	char shares[22];
+	int res;
+	uint64_t val;
+	zone_iptype_t ziptype;
+	zone_dochandle_t handle = NULL;
+	int d = 0;
+	boolean_t noglobalcfg = B_FALSE;
+
+	zonename = data_to_string(args[0]);
+
+	/* Make sure zone exists */
+	res = zone_get_zonepath((char *)zonename, path, sizeof (path));
+	if (res != Z_OK) {
+		if (res == Z_NO_ZONE) {
+			err = zone_create_error("ZONENOTEXISTS");
+			goto err;
+		} else {
+			return (ce_system);
+		}
+	}
+
+	/* Create the zoneconfig struct to return */
+	config = data_new_struct(&t__ZoneConfig);
+	if (config == NULL)
+		goto err;
+
+	/* Set zonename */
+	string = data_new_string(zonename, lt_copy);
+	if (string == NULL)
+		goto err;
+	struct_set(config, "zoneName", string);
+
+	/* Set zonepath */
+	string = data_new_string(path, lt_copy);
+	if (string == NULL)
+		goto err;
+	struct_set(config, "zonePath", string);
+
+	/* Get handle to read zone configuration */
+	handle = zonecfg_init_handle();
+	if (handle == NULL)
+		goto err;
+
+	res = zonecfg_get_handle(zonename, handle);
+	if (res != Z_OK) {
+		if (strcmp(zonename, "global") == 0)
+			noglobalcfg = B_TRUE;
+		else
+			goto err;
+	}
+
+	/* Get cpu shares */
+	res = zonecfg_get_aliased_rctl(handle, ALIAS_SHARES, &val);
+	if (res == Z_OK)
+		(void) snprintf(shares, sizeof (shares), "%llu", val);
+	else if (res == Z_NO_ENTRY)
+		shares[0] = '\0';
+	else if (noglobalcfg)
+		shares[0] = '\0';
+	else
+		goto err;
+
+	/* make up stuff for global zone iptype and scheduler */
+	if (strcmp(zonename, "global") == 0) {
+		ziptype = ZS_SHARED;
+		class[0] = '\0';
+
+	} else {
+		res = zonecfg_get_iptype(handle, &ziptype);
+		if (res != Z_OK)
+			goto err;
+
+		res = zonecfg_get_sched_class(handle, class, sizeof (class));
+		if (res != Z_OK)
+			goto err;
+
+	}
+
+	/* Set config struct values */
+	if (ziptype == ZS_SHARED)
+		iptype = data_new_enum_byname(&t__IpType, "SHARED");
+	else
+		iptype = data_new_enum_byname(&t__IpType, "EXCLUSIVE");
+	if (iptype == NULL)
+		goto err;
+	struct_set(config, "iptype", iptype);
+
+	if ((string = data_new_string(class, lt_copy)) == NULL)
+		goto err;
+	struct_set(config, "scheduler", string);
+
+	if ((string = data_new_string(shares, lt_copy)) == NULL)
+		goto err;
+	struct_set(config, "cpuShares", string);
+
+	networks = get_configured_interfaces(handle, noglobalcfg);
+	if (networks == NULL)
+		goto err;
+
+	struct_set(config, "networks", networks);
+	zonecfg_fini_handle(handle);
+
+	/* Get the configured networks for the zone */
+	*ret = config;
+	return (ce_ok);
+err:
+
+	if (handle != NULL)
+		zonecfg_fini_handle(handle);
+
+	if (config != NULL)
+		data_free(config);
+
+	if (err != NULL) {
+		*error = err;
+		return (ce_object);
+	}
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_getAllZoneConfig(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED:"
+	    " api_zonesManagement_invoke_getAllZoneConfig\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_verifyZoneConfig(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED:"
+	    "api_zonesManagement_invoke_verifyZoneConfig\n");
+	return (ce_system);
+}
+
+/*
+ * Shared function used by setZoneConfig and zoneConfigure
+ */
+static int
+set_zone_config(zone_dochandle_t handle, data_t *cfg, const char *zonename,
+    zone_state_t state, boolean_t new, data_t **error)
+{
+	char oldpath[MAXPATHLEN];
+	const char *newpath;
+	const char *oldname, *newname;
+	const char *iptype, *sched, *shares;
+	int res;
+	zone_iptype_t ziptype;
+	uint64_t val;
+	/* Zonename can only be changed for configured or installed zones */
+	newname = data_to_string(struct_get(cfg, "zoneName"));
+	oldname = zonename;
+	if (new == B_FALSE && state != ZONE_STATE_CONFIGURED &&
+	    state != ZONE_STATE_INSTALLED) {
+		if (strcmp(oldname, newname) != 0) {
+			*error = zone_create_error("ZONENAMEIMMUTABLE");
+			goto err;
+		}
+	}
+	res = zonecfg_validate_zonename(newname);
+	if (res == Z_BOGUS_ZONE_NAME) {
+		*error = zone_create_error("INVALIDZONENAME");
+		goto err;
+	} else if (res != Z_OK) {
+		goto err;
+	}
+	if (zonecfg_set_name(handle, (char *)newname) != Z_OK)
+		goto err;
+
+	/* Zonepath can only be changed for configured zones */
+	newpath = data_to_string(struct_get(cfg, "zonePath"));
+	if (new == B_FALSE && state != ZONE_STATE_CONFIGURED) {
+		if (zonecfg_get_zonepath(handle, oldpath, sizeof (oldpath))
+		    != Z_OK)
+			goto err;
+		if (strcmp(oldpath, newpath) != 0) {
+			*error = zone_create_error("ZONEPATHIMMUTABLE");
+			goto err;
+		}
+	}
+	/* XXX no zonecfg function exists to validate zonepath! */
+	if (zonecfg_set_zonepath(handle, (char *)newpath) != Z_OK)
+		goto err;
+
+
+	/* set scheduler.  XXX Need func to validate sched */
+	sched = data_to_string(struct_get(cfg, "scheduler"));
+	if (zonecfg_set_sched(handle, (char *)sched) != Z_OK)
+		goto err;
+
+	shares = data_to_string(struct_get(cfg, "cpuShares"));
+	errno = 0;
+	val = strtoull(shares, NULL, 10);
+	if (errno == 0)
+		if (zonecfg_set_aliased_rctl(handle, ALIAS_SHARES, val)
+		    != Z_OK)
+			goto err;
+
+	/* Set the iptype */
+	iptype = enum_tostring(struct_get(cfg, "iptype"));
+	if (strcmp(iptype, "EXCLUSIVE") == 0)
+		ziptype = ZS_EXCLUSIVE;
+	else
+		ziptype = ZS_SHARED;
+	if (zonecfg_set_iptype(handle, ziptype) != Z_OK)
+		goto err;
+
+	delete_configured_interfaces(handle);
+
+	if (set_configured_interfaces(handle, cfg, ziptype, error) != 0) {
+		goto err;
+	}
+	if (zonecfg_save(handle) != Z_OK) {
+		goto err;
+	}
+
+	return (0);
+err:
+	return (-1);
+}
+
+conerr_t
+api_zonesManagement_invoke_setZoneConfig(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	zone_dochandle_t handle = NULL;
+	zone_state_t state;
+	const char *zonename;
+	data_t *cfg;
+	data_t *eo = NULL;
+	int res;
+
+	zonename = data_to_string(args[0]);
+	cfg = args[1];
+
+	/* Make sure zone exists. */
+	/* XXX Need some atomicity here for check and modify */
+	res = zone_get_state((char *)zonename, &state);
+	if (res != Z_OK) {
+		eo = zone_create_error("ZONENOTEXISTS");
+		goto err;
+	}
+
+	/* get new handle for new zone */
+	handle = zonecfg_init_handle();
+	if (handle == NULL)
+		goto err;
+
+	/* Create a new zone document */
+	res = zonecfg_get_handle(zonename, handle);
+	if (res != Z_OK)
+		goto err;
+
+	/* Set configuration and save */
+	if (set_zone_config(handle, cfg, zonename, state, B_FALSE, &eo) != 0)
+		goto err;
+
+	zonecfg_fini_handle(handle);
+	return (ce_ok);
+
+err:
+	if (handle != NULL)
+		zonecfg_fini_handle(handle);
+
+	if (eo != NULL) {
+		*error = eo;
+		return (ce_object);
+	}
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneConfigure(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	zone_dochandle_t handle = NULL;
+	zone_state_t state;
+	char template[ZONENAME_MAX];
+	const char *zonename;
+	data_t *cfg = args[0];
+	data_t *eo = NULL;
+	int res;
+
+	zonename = data_to_string(struct_get(cfg, "zoneName"));
+
+	/* Make sure zone does not exist */
+	/* XXX Need some atomicity here for check and create */
+	res = zone_get_state((char *)zonename, &state);
+	if (res == Z_OK) {
+		eo = zone_create_error("ZONEEXISTS");
+		goto err;
+	}
+
+	/* get new handle for new zone */
+	handle = zonecfg_init_handle();
+	if (handle == NULL)
+		goto err;
+
+	/* Create a new zone document */
+	(void) strlcpy(template, "SUNWdefault", sizeof (template));
+	res = zonecfg_get_template_handle(template, zonename, handle);
+	if (res != Z_OK)
+		goto err;
+
+	/* Set configuration and save */
+	if (set_zone_config(handle, cfg, zonename, state, B_TRUE, &eo) != 0)
+		goto err;
+
+	zonecfg_fini_handle(handle);
+	return (ce_ok);
+
+err:
+	if (handle != NULL)
+		zonecfg_fini_handle(handle);
+
+	if (eo != NULL) {
+		*error = eo;
+		return (ce_object);
+	}
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneUnconfigure(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	zone_dochandle_t handle = NULL;
+	zone_state_t state;
+	const char *zonename;
+	data_t *cfg;
+	data_t *eo = NULL;
+	int res;
+
+	zonename = data_to_string(args[0]);
+	cfg = args[1];
+
+	/* Make sure zone exists */
+	/* XXX Need some atomicity here for check and create */
+	res = zone_get_state((char *)zonename, &state);
+	if (res != Z_OK) {
+		eo = zone_create_error("ZONENOTEXISTS");
+		goto err;
+	}
+
+	/* Zone must be in the configured state to destroy it */
+	if (state != ZONE_STATE_CONFIGURED) {
+		eo = zone_create_error("ZONENOTCONFIGURED");
+		goto err;
+	}
+
+	/* XXX Need some atomicity here for check and destroy */
+	if (zonecfg_destroy(zonename, B_FALSE) != Z_OK)
+		goto err;
+
+	return (0);
+err:
+	if (eo != NULL) {
+		*error = eo;
+		return (ce_object);
+	}
+	return (ce_system);
+}
+static int
+get_exclusive_interfaces(zoneid_t zid, data_t *networks)
+{
+	int nlinks, new_nlinks, i, res;
+	datalink_id_t *linkids;
+	dladm_status_t dlres;
+	dladm_handle_t dlh = NULL;
+	char linkname[MAXLINKNAMELEN];
+	data_t *network = NULL;
+	data_t *string;
+
+link_again:
+
+	/* Get the datalinks for the zone */
+	nlinks = 0;
+	linkids = NULL;
+	res = zone_list_datalink(zid, &nlinks, NULL);
+	if (res != 0)
+		goto err;
+
+	if (nlinks == 0)
+		return (0);
+
+		linkids = malloc(nlinks *
+		    sizeof (datalink_id_t));
+
+		res = zone_list_datalink(zid, &new_nlinks,
+		    linkids);
+		if (res != 0)
+			goto err;
+
+		if (new_nlinks > nlinks)
+			goto link_again;
+
+		if (new_nlinks == 0) {
+			free(linkids);
+			return (0);
+		}
+
+		if (dladm_open(&dlh) != DLADM_STATUS_OK)
+			goto err;
+
+		/* create a network for each datalink */
+		for (i = 0; i < new_nlinks; i++) {
+
+
+			dlres = dladm_datalink_id2info(dlh,
+			    linkids[i], NULL, NULL, NULL,
+			    linkname, sizeof (linkname));
+
+			if (dlres != DLADM_STATUS_OK)
+				goto err;
+
+			network = data_new_struct(&t__Network);
+			if (network == NULL)
+				goto err;
+			res = array_add(networks, network);
+			if (res != 0) {
+				data_free(network);
+				goto err;
+			}
+			string = data_new_string(linkname,
+			    lt_copy);
+			if (string == NULL)
+				goto err;
+
+			struct_set(network, "physical",
+			    string);
+		}
+		free(linkids);
+		linkids = NULL;
+		dladm_close(dlh);
+		dlh = NULL;
+
+	return (0);
+err:
+	if (linkids != NULL)
+		free(linkids);
+	if (dlh != NULL)
+		dladm_close(dlh);
+
+	return (-1);
+}
+
+static int
+get_shared_interfaces(zoneid_t zid, data_t *networks)
+{
+	struct lifnum lifn;
+	struct lifconf lifc;
+	struct lifreq *lifrp, lifrl;
+	int64_t lifc_flags = LIFC_NOXMIT | LIFC_ALLZONES;
+	int num_ifs, s = -1, i, ret_code = 0;
+	uint_t bufsize;
+	char *buf = NULL;
+	data_t *string;
+	data_t *network;
+	int res;
+	struct sockaddr_in *ipv4;
+	struct sockaddr_in6 *ipv6;
+	char addrstr[INET6_ADDRSTRLEN];
+
+	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+		return (-1);
+	/* Get the number of logical interfaces */
+if_again:
+	lifn.lifn_family = AF_UNSPEC;
+	lifn.lifn_flags = (int)lifc_flags;
+	if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0)
+		goto err;
+
+	num_ifs = lifn.lifn_count;
+	bufsize = num_ifs * sizeof (struct lifreq);
+	if ((buf = malloc(bufsize)) == NULL)
+		goto err;
+
+	/* Get the list of logical interfaces */
+	lifc.lifc_family = AF_UNSPEC;
+	lifc.lifc_flags = (int)lifc_flags;
+	lifc.lifc_len = bufsize;
+	lifc.lifc_buf = buf;
+	if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
+		/* Try again if interfaces no longer fit in buf */
+		if (errno == EINVAL) {
+			free(buf);
+			buf = NULL;
+			goto if_again;
+		} else {
+			goto err;
+		}
+	}
+	close(s);
+	s = -1;
+	/* Walk the list of logical interfaces */
+	lifrp = lifc.lifc_req;
+	for (i = lifc.lifc_len / sizeof (struct lifreq); i > 0; i--, lifrp++) {
+
+		if ((s = socket(lifrp->lifr_addr.ss_family, SOCK_DGRAM, 0)) <
+		    0)
+			goto err;
+
+		(void) memset(&lifrl, 0, sizeof (lifrl));
+		(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
+		    sizeof (lifrl.lifr_name));
+
+		/* Check the flags for loopback interfaces */
+		if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) {
+			if (errno == ENXIO) {
+				/*
+				 * Interface may have been removed by admin or
+				 * another zone halting.
+				 */
+				close(s);
+				s = -1;
+				continue;
+			} else {
+				goto err;
+			}
+		}
+		/* Skip loopback interfaces */
+		if (lifrl.lifr_flags & IFF_LOOPBACK) {
+			close(s);
+			s = -1;
+			continue;
+		}
+		/* get zone of interface */
+		if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifrl) < 0) {
+			if (errno == ENXIO) {
+				/*
+				 * Interface may have been removed by admin or
+				 * another zone halting.
+				 */
+				close(s);
+				s = -1;
+				continue;
+			} else {
+				goto err;
+			}
+		}
+		/* skip interfaces not for this zone */
+		if (lifrl.lifr_zoneid != zid) {
+			close(s);
+			s = -1;
+			continue;
+		}
+		/* get the address of the interface */
+		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifrl) < 0) {
+			if (errno == ENXIO) {
+				/*
+				 * Interface may have been removed by admin or
+				 * another zone halting.
+				 */
+				close(s);
+				s = -1;
+				continue;
+			} else {
+				goto err;
+			}
+		}
+		if (lifrl.lifr_addr.ss_family == AF_INET) {
+			ipv4 = (struct sockaddr_in *)&lifrl.lifr_addr;
+			if (inet_ntop(AF_INET, &ipv4->sin_addr, addrstr,
+			    sizeof (addrstr)) == NULL)
+				goto err;
+
+		} else if (lifrl.lifr_addr.ss_family = AF_INET6) {
+			ipv6 = (struct sockaddr_in6 *)&lifrl.lifr_addr;
+			if (inet_ntop(AF_INET6, &ipv6->sin6_addr, addrstr,
+			    sizeof (addrstr)) == NULL)
+				goto err;
+		} else {
+			close(s);
+			s = -1;
+			continue;
+		}
+
+		network = data_new_struct(&t__Network);
+		if (network == NULL)
+			goto err;
+		res = array_add(networks, network);
+		if (res != 0) {
+			data_free(network);
+			goto err;
+		}
+		string = data_new_string(lifrl.lifr_name, lt_copy);
+		if (string == NULL)
+			goto err;
+
+		struct_set(network, "physical",
+		    string);
+
+		string = data_new_string(addrstr, lt_copy);
+		if (string == NULL)
+			goto err;
+
+		struct_set(network, "address", string);
+
+		close(s);
+	}
+
+	free(buf);
+	return (0);
+
+err:
+	if (s >= 0)
+		close(s);
+	if (buf != NULL)
+		free(buf);
+
+	return (-1);
+}
+
+conerr_t
+api_zonesManagement_invoke_getSystemState(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	data_t *systemState = NULL;
+	data_t *zoneState = NULL;
+	data_t *zoneNames = NULL;
+	data_t *zonesConfigured = NULL;
+	data_t *zonesInstalled = NULL;
+	data_t *zonesRunning = NULL;
+	data_t *zoneStates = NULL;
+	data_t *installedState = NULL;
+	data_t *runningState = NULL;
+	data_t *networks = NULL;
+
+	data_t *string;
+	conerr_t  err;
+	int numzones;
+
+	FILE *cookie;
+	char *name;
+	zone_state_t zstate;
+	zone_iptype_t ziptype;
+	ushort_t zflags;
+	zoneid_t zid;
+	uuid_t uuid;
+
+	char  path[MAXPATHLEN];
+	char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
+	int res;
+
+	/* Top level structure for system State */
+	systemState = data_new_struct(&t__SystemState);
+	if (systemState == NULL)
+		goto err;
+
+	/* Create list of zone state structs */
+	zoneStates = data_new_array(&t_array__ZoneState, 0);
+	if (zoneStates == NULL)
+		goto err;
+	struct_set(systemState, "zones", zoneStates);
+
+	/* Create lists of zone names */
+	zoneNames = data_new_array(&t_array_string, 0);
+	if (zoneNames == NULL)
+		goto err;
+	struct_set(systemState, "zoneNames", zoneNames);
+
+	zonesConfigured = data_new_array(&t_array_string, 0);
+	if (zonesConfigured == NULL)
+		goto err;
+	struct_set(systemState, "zonesConfigured", zonesConfigured);
+
+	zonesInstalled = data_new_array(&t_array_string, 0);
+	if (zonesInstalled == NULL)
+		goto err;
+	struct_set(systemState, "zonesInstalled", zonesInstalled);
+
+	zonesRunning = data_new_array(&t_array_string, 0);
+	if (zonesRunning == NULL)
+		goto err;
+	struct_set(systemState, "zonesRunning", zonesRunning);
+
+	/* Walk each zone and set state */
+	if ((cookie = setzoneent()) == NULL)
+		goto err;
+
+	while ((name = getzoneent(cookie)) != NULL) {
+
+		/* Get the zone's state */
+		/*
+		 * XXX need to interact with zone lock to ensure that
+		 * no zones are configured or configured while this
+		 * look is running, and in general, the index file does
+		 * not change.
+		 */
+		res = zone_get_state(name, &zstate);
+		if (res != Z_OK)
+			goto err;
+
+		/* Add the zone to the name list */
+		string = data_new_string(name, lt_copy);
+		if (string == NULL)
+			goto err;
+		res = array_add(zoneNames, string);
+		if (res != 0) {
+			data_free(string);
+			goto err;
+		}
+
+		/* Create a state object for zone */
+		zoneState = data_new_struct(&t__ZoneState);
+		if (zoneState == NULL)
+			goto err;
+		res = array_add(zoneStates, zoneState);
+		if (res != 0) {
+			data_free(zoneState);
+			goto err;
+		}
+		string = data_new_string(name, lt_copy);
+		if (string == NULL)
+			goto err;
+		struct_set(zoneState, "name", string);
+
+		/* Set the state for each zone */
+		switch (zstate) {
+		case ZONE_STATE_CONFIGURED:
+			struct_set(zoneState, "state",
+			    data_new_enum_byname(&t__ZoneStateCode,
+			    "CONFIGURED"));
+			break;
+		case ZONE_STATE_INCOMPLETE:
+			struct_set(zoneState, "state",
+			    data_new_enum_byname(&t__ZoneStateCode,
+			    "INCOMPLETE"));
+			break;
+		case ZONE_STATE_INSTALLED:
+			struct_set(zoneState, "state",
+			    data_new_enum_byname(&t__ZoneStateCode,
+			    "INSTALLED"));
+			break;
+		case ZONE_STATE_READY:
+			struct_set(zoneState, "state",
+			    data_new_enum_byname(&t__ZoneStateCode,
+			    "READY"));
+			break;
+		case ZONE_STATE_MOUNTED:
+			struct_set(zoneState, "state",
+			    data_new_enum_byname(&t__ZoneStateCode,
+			    "MOUNTED"));
+			break;
+		case ZONE_STATE_RUNNING:
+			struct_set(zoneState, "state",
+			    data_new_enum_byname(&t__ZoneStateCode,
+			    "RUNNING"));
+			break;
+		case ZONE_STATE_SHUTTING_DOWN:
+			struct_set(zoneState, "state",
+			    data_new_enum_byname(&t__ZoneStateCode,
+			    "HALTING"));
+			break;
+		case ZONE_STATE_DOWN:
+			struct_set(zoneState, "state",
+			    data_new_enum_byname(&t__ZoneStateCode,
+			    "DOWN"));
+			break;
+		default:
+			goto err;
+		}
+
+		/* add the state details for each zone */
+		switch (zstate) {
+		case ZONE_STATE_RUNNING:
+		case ZONE_STATE_SHUTTING_DOWN:
+		case ZONE_STATE_DOWN:
+			string = data_new_string(name, lt_copy);
+			if (string == NULL)
+				goto err;
+			res = array_add(zonesRunning, string);
+			if (res != 0) {
+				data_free(string);
+				goto err;
+			}
+
+			/* Create the running state object for the zone */
+			runningState =
+			    data_new_struct(&t__ZoneRunningState);
+			if (runningState == NULL)
+				goto err;
+			struct_set(zoneState, "runningState",
+			    runningState);
+
+			networks = data_new_array(&t_array__Network, 0);
+			if (networks == NULL)
+				goto err;
+			struct_set(runningState, "networks", networks);
+
+			zid = getzoneidbyname(name);
+			if (zid < 0)
+				goto err;
+
+			res = zone_getattr(zid, ZONE_ATTR_FLAGS, &zflags,
+			    sizeof (zflags));
+			if (res != sizeof (zflags))
+				goto err;
+
+			if (zflags & ZF_NET_EXCL) {
+				ziptype = ZS_EXCLUSIVE;
+				res = get_exclusive_interfaces(zid, networks);
+				if (res != 0)
+					goto err;
+				struct_set(runningState, "iptype",
+				    data_new_enum_byname(&t__IpType,
+				    "EXCLUSIVE"));
+			} else {
+				ziptype = ZS_SHARED;
+
+				res = get_shared_interfaces(zid, networks);
+				if (res != 0)
+					goto err;
+				struct_set(runningState, "iptype",
+				    data_new_enum_byname(&t__IpType,
+				    "SHARED"));
+			}
+			/* FALLTHROUGH */
+		case ZONE_STATE_INSTALLED:
+		case ZONE_STATE_MOUNTED:
+		case ZONE_STATE_READY:
+			string = data_new_string(name, lt_copy);
+			if (string == NULL)
+				goto err;
+			res = array_add(zonesInstalled, string);
+			if (res != 0) {
+				data_free(string);
+				goto err;
+			}
+
+			/* Add the details about the installed zone */
+			installedState =
+			    data_new_struct(&t__ZoneInstalledState);
+			if (installedState == NULL)
+				goto err;
+			struct_set(zoneState, "installedState",
+			    installedState);
+
+			res = zone_get_zonepath(name, path, sizeof (path));
+			if (res != 0)
+				goto err;
+			string = data_new_string(path, lt_copy);
+			if (string == NULL)
+				goto err;
+			struct_set(installedState, "zonepath", string);
+
+			res = zonecfg_get_uuid(name, uuid);
+			if (res != 0)
+				goto err;
+			uuid_unparse(uuid, uuidstr);
+			string = data_new_string(uuidstr, lt_copy);
+			if (string == NULL)
+				goto err;
+			struct_set(installedState, "uuid", string);
+
+			/* FALLTHROUGH */
+		case ZONE_STATE_INCOMPLETE:
+		case ZONE_STATE_CONFIGURED:
+			string = data_new_string(name, lt_copy);
+			if (string == NULL)
+				goto err;
+			res = array_add(zonesConfigured, string);
+			if (res != 0) {
+				data_free(string);
+				goto err;
+			}
+			break;
+		default:
+			goto err;
+		}
+
+	}
+	endzoneent(cookie);
+	*ret = systemState;
+	return (ce_ok);
+err:
+
+	if (cookie != NULL)
+		endzoneent(cookie);
+
+	/* Rely on recursive data_free to free everything */
+	if (systemState != NULL)
+		data_free(systemState);
+
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_getZoneState(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED:"
+	    " api_zonesManagement_invoke_getZoneState\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_GetCpuState(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_GetCpuState\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_setZonePool(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_setZonePool\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_setZoneScheduler(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_setZoneScheduler\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_setZoneCpuShares(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_setZoneCpuShares\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_setZoneCappedCpu(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_setZoneCappedCpu\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_setZoneDedicatedCpu(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_setZoneDedicatedCpu\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_setZoneCappedMemory(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_setZoneCappedMemory\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneMove(struct instance *inst, struct method *meth,
+    data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED:"
+	    " api_zonesManagement_invoke_zoneMove\n");
+	return (ce_system);
+}
+
+static int
+forkexec(const char *path, const char **argv, int *status)
+{
+	pid_t p = forkx(FORK_WAITPID);
+	if (p == 0) {
+		(void) dup2(2, 1);
+		(void) execv(path, (char **)argv);
+		_exit(1);
+	}
+	if (p > 0) {
+		siginfo_t si;
+		if (waitid(P_PID, p, &si, WEXITED) == -1) {
+			return (1);
+		}
+		if (status != NULL)
+			*status = si.si_status;
+		return (0);
+	}
+	return (1);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneInstall(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	const char *zonename = data_to_string(args[0]);
+	data_t *pkgs = args[1];
+	data_t *eo = NULL;
+	int res, i;
+	const char **argv = NULL;
+	int argc = 0;
+	int nargs = 5;
+	int npkgs = 0;
+	int status;
+	zone_state_t state;
+
+	/* Make sure zone exists */
+	/* XXX Need some atomicity here for check and install */
+	res = zone_get_state((char *)zonename, &state);
+	if (res != Z_OK) {
+		eo = zone_create_error("ZONENOTEXISTS");
+		goto err;
+	}
+
+	/* Zone must be in the configured state to install it */
+	if (state != ZONE_STATE_CONFIGURED) {
+		eo = zone_create_error("ZONENOTCONFIGURED");
+		goto err;
+	}
+
+	if (pkgs != NULL && array_size(pkgs) > 0) {
+		npkgs = array_size(pkgs);
+	}
+	/* Allocate argv for zoneadm options, including extra packages */
+	argv = malloc(sizeof (char *) * (nargs + (npkgs * 2)));
+	if (argv == NULL)
+		goto err;
+
+	/* add cli options for install */
+	argv[argc++] = "zoneadm";
+	argv[argc++] = "-z";
+	argv[argc++] = (char *)zonename;
+	argv[argc++] = "install";
+	argv[argc] =  NULL;
+
+	/* add cli options for packages */
+	for (i = 0; i < npkgs; i++) {
+		argv[argc++] = "-e";
+		argv[argc++] = (char *)data_to_string(array_get(pkgs, i));
+		argv[argc] == NULL;
+	}
+
+	res = forkexec("/usr/sbin/zoneadm", argv, &status);
+	if (res != 0 || status != 0) {
+		eo = zone_create_error("UNKNOWN");
+		goto err;
+	}
+
+	free(argv);
+	return (ce_ok);
+err:
+	if (argv != NULL)
+		free(argv);
+
+	if (eo != NULL) {
+		*error = eo;
+		return (ce_object);
+	}
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneUninstall(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	const char *zonename = data_to_string(args[0]);
+	data_t *eo = NULL;
+	int res;
+	const char **argv = NULL;
+	int argc = 0;
+	int nargs = 6;
+	int status;
+	zone_state_t state;
+
+	/* Make sure zone exists */
+	/* XXX Need some atomicity here for check and install */
+	res = zone_get_state((char *)zonename, &state);
+	if (res != Z_OK) {
+		eo = zone_create_error("ZONENOTEXISTS");
+		goto err;
+	}
+
+	/* Zone must be in the configured state to install it */
+	if (state != ZONE_STATE_INSTALLED) {
+		eo = zone_create_error("ZONENOTINSTALLED");
+		goto err;
+	}
+
+	/* Allocate argv for zoneadm options, including extra packages */
+	argv = malloc(sizeof (char *) * nargs);
+	if (argv == NULL)
+		goto err;
+
+	/* add cli options for install */
+	argv[argc++] = "zoneadm";
+	argv[argc++] = "-z";
+	argv[argc++] = (char *)zonename;
+	argv[argc++] = "uninstall";
+	argv[argc++] = "-F";
+	argv[argc] =  NULL;
+
+	res = forkexec("/usr/sbin/zoneadm", argv, &status);
+	if (res != 0 || status != 0) {
+		eo = zone_create_error("UNKNOWN");
+		goto err;
+	}
+
+	free(argv);
+	return (ce_ok);
+err:
+	if (argv != NULL)
+		free(argv);
+
+	if (eo != NULL) {
+		*error = eo;
+		return (ce_object);
+	}
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneInstallP2V(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_zoneInstallP2V\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneClone(struct instance *inst, struct method *meth,
+    data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_zoneClone\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneAttach(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_zoneAttach\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneDetach(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_zoneDetach\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneVerify(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_zoneVerify\n");
+	return (ce_system);
+}
+
+/*
+ * Adds a warning to an array of warnings.   If "warnings" is NULL,
+ * the warning list will be created.
+ */
+static data_t *
+zone_add_warning(data_t *warnings, char *string)
+{
+	data_t *warning = NULL;
+	data_t *wcode = NULL;
+	data_t *msg = NULL;
+
+	if (warnings == NULL) {
+		if (data_new_array(&t_array__ZonesWarning, 0) != 0)
+			goto err;
+	}
+	if ((warning = data_new_struct(&t__ZonesWarning)) == NULL)
+		goto err;
+	if (array_add(warnings, warning) != 0)
+		goto err;
+	if ((wcode = data_new_enum_byname(&t__ZonesWarningCode, string))
+	    == NULL)
+		goto err;
+	struct_set(warning, "warning", wcode);
+	if ((msg = data_new_string(string, lt_copy)) == NULL)
+		goto err;
+	struct_set(warning, "message", msg);
+
+	return (warnings);
+err:
+	if (warnings != NULL)
+		data_free(warnings);
+
+	return (NULL);
+}
+
+conerr_t
+do_zoneadmd_cmd(struct instance *inst, struct method *meth,
+    data_t **ret, data_t **args, int count, data_t **error, int cmd)
+{
+	zone_cmd_arg_t zarg;
+	char *locale;
+	zarg.cmd = Z_BOOT;
+	const char *zonename;
+	data_t *warnings;
+	data_t *err;
+	int i, res;
+	char *zone_lock_env;
+	zone_state_t zstate;
+	char  path[MAXPATHLEN];
+
+	/* We can trust that there is one arg which is a string */
+	zonename = data_to_string(args[0]);
+
+	/* Make sure zone exists */
+	res = zone_get_state((char *)zonename, &zstate);
+	if (res != Z_OK) {
+		if (res == Z_NO_ZONE) {
+			if ((err = zone_create_error("ZONENOTCONFIGURED"))
+			    == NULL)
+				return (ce_system);
+			goto err;
+		} else {
+			return (ce_system);
+		}
+	}
+	if ((locale = setlocale(LC_ALL, "")) == NULL)
+		locale = "C";
+
+	zonecfg_init_lock_file(zonename, &zone_lock_env);
+
+	zarg.bootbuf[0] = '\0';
+	zarg.cmd = cmd;
+	/*
+	 * XXX lacks sanity checks done my zoneadm.  Will succeed if zone
+	 * is already booted.
+	 */
+	/*
+	 * XXX libzonecfg should use forkx(FORK_WAITPID)
+	 */
+	sigset(SIGCHLD, SIG_DFL);
+	res = zonecfg_call_zoneadmd(zonename, &zarg, locale, B_TRUE);
+	sigset(SIGCHLD, SIG_IGN);
+
+	if (res != Z_OK) {
+		if ((err = zone_create_error("UNKNOWN")) == NULL)
+			return (ce_system);
+		goto err;
+	} else {
+		return (ce_ok);
+	}
+
+err:
+	if (data_purify(err) == NULL) {
+		return (ce_system);
+	}
+	*error = err;
+	return (ce_object);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneBoot(struct instance *inst, struct method *meth,
+    data_t **ret, data_t **args, int count, data_t **error)
+{
+
+	return (do_zoneadmd_cmd(inst, meth, ret, args, count, error, Z_BOOT));
+}
+
+
+conerr_t
+api_zonesManagement_invoke_zoneReboot(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	return (do_zoneadmd_cmd(inst, meth, ret, args, count, error, Z_REBOOT));
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneHalt(struct instance *inst, struct method *meth,
+    data_t **ret, data_t **args, int count, data_t **error)
+{
+	return (do_zoneadmd_cmd(inst, meth, ret, args, count, error, Z_HALT));
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneIsConfigured(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_zoneIsConfigured\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneIsInstalled(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_zoneIsInstalled\n");
+	return (ce_system);
+}
+
+conerr_t
+api_zonesManagement_invoke_zoneIsRunning(struct instance *inst,
+    struct method *meth, data_t **ret, data_t **args, int count, data_t **error)
+{
+	(void) fprintf(stderr, "NOT IMPLEMENTED: "
+	    "api_zonesManagement_invoke_zoneIsRunning\n");
+	return (ce_system);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/rad/mod/zones/mod_zones.c	Wed May 12 16:54:43 2010 -0700
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/list.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include "rad_adr.h"
+#include "rad_object.h"
+#include "rad_modapi.h"
+#include "rad_util.h"
+#include "rad_log.h"
+#include "rad.h"
+
+#include "api_zones.h"
+
+static rad_modinfo_t modinfo = {"zonesManagement", "Zones Management Module" };
+
+int
+_rad_init(void *handle)
+{
+	if (rad_module_register(handle, RAD_MODVERSION, &modinfo) == -1)
+		return (-1);
+
+	if (rad_isproxy)
+		return (0);
+
+	cont_insert_singleton(&rad_container,
+	    "com.oracle.solaris.zonesManagement:type=zonesManager",
+	    &api_zonesManagement, NULL);
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/zmgr/zmgr.py	Wed May 12 16:54:43 2010 -0700
@@ -0,0 +1,539 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+import socket
+import rad.client as rad
+import sys
+import getopt
+
+
+def usage():
+	print >> sys.stderr, "Usage: zmgr help"
+	print >> sys.stderr, ""
+	print >> sys.stderr, "       zmgr -z <zonename> create -p <zonepath>"
+	print >> sys.stderr, "       zmgr -z <zonename> delete"
+	print >> sys.stderr, ""
+	print >> sys.stderr, "       zmgr -z <zonename> config list"
+	print >> sys.stderr, "       zmgr -z <zonename> config info"
+	print >> sys.stderr, ""
+	print >> sys.stderr, "       zmgr -z <zonename> config set iptype [shared | exclusive ] "
+	print >> sys.stderr, "       zmgr -z <zonename> config set scheduler <sched>"
+	print >> sys.stderr, "       zmgr -z <zonename> config set cpu-shares <shares>"
+	print >> sys.stderr, "       zmgr -z <zonename> config add net -p <physical> -a <address>"
+	print >> sys.stderr, "       zmgr -z <zonename> config remove net -p <physical> -a <address>"
+	print >> sys.stderr, ""
+	print >> sys.stderr, "       zmgr -z <zonename> state list"
+	print >> sys.stderr, "       zmgr -z <zonename> state info"
+	print >> sys.stderr, ""
+	print >> sys.stderr, "       zmgr -z <zonename> install <pkgs> ..."
+	print >> sys.stderr, "       zmgr -z <zonename> uninstall"
+	print >> sys.stderr, ""
+	print >> sys.stderr, "       zmgr -z <zonename> boot"
+	print >> sys.stderr, "       zmgr -z <zonename> halt"
+	print >> sys.stderr, "       zmgr -z <zonename> reboot"
+	print >> sys.stderr, ""
+	sys.exit(2);
+
+def state_info_func(zones):
+
+	for zone in zones:
+
+		print ""
+		print zone.name
+
+		print "    state   :", zone.state
+		if zone.installedState:
+			print "    zonepath:", zone.installedState.zonepath
+			print "    uuid    :", zone.installedState.uuid
+		if zone.runningState:
+			print "    iptype  :", zone.runningState.iptype
+			for net in zone.runningState.networks:
+				print "    network  :", net.physical
+				if (zone.runningState.iptype == "SHARED"):
+					print "       addr  :", net.address
+			
+	return (0);
+
+def state_list_func(zones):
+
+	format = "%-15s%-15s%-20s%-10s%-20s"
+	print format %("NAME", "STATUS", "PATH", "IPTYPE", "NETS")
+	for zone in zones:
+
+		path = "-";
+		iptype = "-"
+		nets = {};
+
+		if (zone.installedState):
+			path = zone.installedState.zonepath
+
+		if (zone.runningState):
+			iptype = zone.runningState.iptype;
+			for net in zone.runningState.networks:
+				nets[net.physical] = 1;
+
+		print format % (zone.name, zone.state, path, iptype, nets.keys())
+	return(0);
+
+def state_func(args):
+
+	if (len(args) == 0):
+		usage();
+
+	try:
+		state = obj.getSystemState(1, 0, 0, 0, None);
+	except rad.RadException, ex:
+		print ex.message;
+		return 1;
+
+	if (zonename != ""):
+		for zone in state.zones:
+			if (zone.name == zonename):	
+				zones = [ zone ];
+				break;
+	else:
+		zones = state.zones
+
+	if (args[0] == "list"):
+		return state_list_func(zones);
+	elif (args[0] == "info"):
+		return state_info_func(zones);
+	else:
+		usage();
+
+# Configure a new zone
+def create_func(args):
+	try:
+		opts, args = getopt.getopt(args, "p:");
+	except getopt.GetoptError, err:
+		print >> sys.stderr, str(err)
+		usage();
+		sys.exit(2);
+
+	found=0
+	for o,a in opts:
+		if o == "-p":
+			zonepath = a
+			found=1
+
+	if (found == 0):
+		usage();
+
+	argtype = obj._object.get_type("ZoneConfig");
+	cfg = argtype.makev(zonename, zonepath, "", "1", "SHARED",
+	    None, None, None, None)
+
+	try:
+		obj.zoneConfigure(cfg);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+		return 1
+	return 0;
+
+def delete_func(args):
+	try:
+		obj.zoneUnconfigure(zonename);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+	return 0;
+
+def config_list_func(args):
+	try:
+		state = obj.getSystemState(1, 0, 0, 0, None);
+	except rad.RadException, ex:
+		print ex.message;
+		return 1;
+
+	if (zonename != ""):
+		for zone in state.zoneNames:
+			if (zone.name == zonename):	
+				zones = [ zonename ];
+				break;
+	else:
+		zones = state.zoneNames
+
+	format = "%-15s%-25s%-10s%-10s%-15s"
+	print format %("NAME", "PATH", "IPTYPE", "SHARES", "NETS")
+
+	for zone in zones:
+		try:
+			cfg = obj.getZoneConfig(zone);
+		except rad.RadException, ex:
+			error = ex.get_payload();
+			print error.message
+
+		if (cfg.cpuShares != ""):
+			if cfg.scheduler == "FSS":
+				shares = cfg.cpuShares
+			else:
+				shares = "*%s" % (cfg.cpuShares)
+		else:
+			shares="-"
+		nets = {};
+		for net in cfg.networks:
+			nets[net.physical] = 1;
+
+		print format % (zone, cfg.zonePath, cfg.iptype, shares, nets.keys())
+	return(0);
+
+def config_info_func(args):
+	try:
+		state = obj.getSystemState(1, 0, 0, 0, None);
+	except rad.RadException, ex:
+		print ex.message;
+		return 1;
+
+	if (zonename != ""):
+		for zone in state.zoneNames:
+			if (zone == zonename):	
+				zones = [ zonename ];
+				break;
+	else:
+		zones = state.zoneNames
+
+
+	for zone in zones:
+		try:
+			cfg = obj.getZoneConfig(zone);
+		except rad.RadException, ex:
+			error = ex.get_payload();
+			print error.message
+
+		if (cfg.cpuShares != ""):
+			if cfg.scheduler == "FSS":
+				shares = cfg.cpuShares
+			else:
+				shares = "*%s" % (cfg.cpuShares)
+		else:
+			shares=""
+		nets = {};
+		for net in cfg.networks:
+			nets[net.physical] = 1;
+
+		print ""
+		print zone
+		print "    zonepath :", cfg.zonePath
+		print "    ipytpe   :", cfg.iptype
+		print "    scheduler:", cfg.scheduler
+		print "    cpu-share:", shares
+		for net in cfg.networks:
+			print "    network  :", net.physical
+			if (cfg.iptype == "SHARED"):
+				print "       addr  :", net.address
+
+	return(0);
+
+def config_set_func(args):
+
+	if (zonename == ""):
+		usage()
+
+	if (len(args) != 2):
+		usage;
+	try:
+		cfg = obj.getZoneConfig(zonename);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+
+	prop = args[0];
+	value = args[1];
+
+	if prop == "iptype":
+		if value == "shared":
+			cfg.iptype = "SHARED";
+		elif value == "exclusive":
+			cfg.iptype = "EXCLUSIVE";
+		else:
+			usage();
+	elif prop == "scheduler":
+		cfg.scheduler = value;
+	elif prop == "cpu-shares":
+		cfg.cpuShares = value;
+	else:
+		usage()
+
+	try:
+		obj.setZoneConfig(zonename, cfg);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+		return 1;
+	return 0;
+
+def config_add_func(args):
+	if (zonename == ""):
+		usage()
+
+	if args[0] != "net":
+		usage();
+
+	args = args[1:];
+
+	physical=""
+	address=""
+
+	try:
+		opts, args = getopt.getopt(args, "p:a:");
+	except getopt.GetoptError, err:
+		print >> sys.stderr, str(err)
+		usage();
+
+	for o, a in opts:
+		if o == "-p":
+			physical = a
+		if o == "-a":
+			address = a;
+
+	if physical == "":
+		print >> sys.stderr, "-p <physical> required"
+		usage()
+	try:
+		cfg = obj.getZoneConfig(zonename);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+
+
+	if (cfg.iptype == "EXCLUSIVE"):
+
+		if address != "":
+			print >> sys.stderr, "-a not invalid for exclusive stack"
+			usage();
+
+		found = 0;
+		for net in cfg.networks:
+			if net.physical == physical:
+				found = 1;
+
+		if found == 0:
+			argtype = obj._object.get_type("Network");
+			net = argtype.makev(physical, "", "");
+			cfg.networks.append(net);
+	else:
+		if address == "":
+			print >> sys.stderr, "-a not required for shared stack"
+			usage();
+
+		found = 0;
+		for net in cfg.networks:
+			if net.physical == physical and net.address == address:
+				found = 1;
+				net.address = address;
+		if found == 0:
+			argtype = obj._object.get_type("Network");
+			net = argtype.makev(physical, address, "");
+			cfg.networks.append(net);
+	
+	try:
+		obj.setZoneConfig(zonename, cfg);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+		return 1;
+	return 0;
+
+def config_remove_func(args):
+
+	if (zonename == ""):
+		usage()
+
+	if args[0] != "net":
+		usage();
+
+	args = args[1:];
+
+	physical=""
+	address=""
+
+	try:
+		opts, args = getopt.getopt(args, "p:a:");
+	except getopt.GetoptError, err:
+		print >> sys.stderr, str(err)
+		usage();
+
+	for o, a in opts:
+		if o == "-p":
+			physical = a
+		if o == "-a":
+			address = a;
+
+	if physical == "":
+		print >> sys.stderr, "-p <physical> required"
+		usage()
+	try:
+		cfg = obj.getZoneConfig(zonename);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+
+	newnets = [];
+	if (cfg.iptype == "EXCLUSIVE"):
+
+		if address != "":
+			print >> sys.stderr, "-a not invalid for exclusive stack"
+			usage();
+
+		found = 0;
+		for net in cfg.networks:
+			if net.physical == physical:
+				found = 1;
+			else:
+				newnets.append(net);
+		if found == 0:
+			print >> sys.stderr, "Network not found!"
+	else:
+		if address == "":
+			print >> sys.stderr, "-a not required for shared stack"
+			usage();
+
+		found = 0;
+		for net in cfg.networks:
+			if net.physical == physical and net.address == address:
+				found = 1;
+			else:
+				newnets.append(net)
+		if found == 0:
+			print >> sys.stderr, "Network not found!"
+
+	cfg.networks = newnets;	
+	try:
+		obj.setZoneConfig(zonename, cfg);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+		return 1;
+	return 0;
+
+def config_func(args):
+
+	config_funcs = {
+	    "list" : config_list_func,
+	    "info" : config_info_func,
+	    "set"  : config_set_func,
+	    "add"  : config_add_func,
+ 	    "remove" : config_remove_func }
+
+	cmd = args[0];
+	args = args[1:];
+
+	if cmd not in config_funcs:
+		usage();
+
+	return config_funcs[cmd](args);
+
+def install_func(args):
+	try:
+		obj.zoneinstall(zonename, []);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+		return 1
+	return 0;
+
+def uninstall_func(args):
+	try:
+		obj.zoneUninstall(zonename);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+		return 1
+	return 0;
+
+def boot_func(args):
+	try:
+		obj.zoneBoot(zonename);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+		return 1
+	return 0;
+
+def halt_func(args):
+	try:
+		obj.zoneHalt(zonename);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+		return 1
+
+	return 0;
+
+def reboot_func(args):
+	try:
+		obj.zoneReboot(zonename);
+	except rad.RadException, ex:
+		error = ex.get_payload();
+		print error.message
+		return 1
+	return 0;
+
+def list_func(args):
+	return ();
+
+# set up some dispatch
+do_funcs = {
+    "state" : state_func,
+    "create" : create_func,
+    "delete" : delete_func,
+    "config" : config_func,
+    "install" : install_func,
+    "uninstall" : uninstall_func,
+    "boot" : boot_func,
+    "halt" : halt_func,
+    "reboot" : reboot_func }
+
+# process args
+argv = sys.argv[1:]
+try:
+	opts, args = getopt.getopt(argv, "z:");
+except getopt.GetoptError, err:
+	print >> sys.stderr, str(err)
+	usage();
+
+zonename=""
+for o,a in opts:
+	if o == "-z":
+		zonename = a
+
+cmd = args[0];
+args = args[1:];
+
+if (cmd == "help"):
+	usage();
+
+if cmd not in do_funcs:
+	usage();
+
+# Inital args look ok.  Connect to rad
+s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM);
+s.connect("/var/run/radsocket");
+rc = rad.RadConnection(s)
+obj = rc.get_object_s("com.oracle.solaris.zonesManagement", [("type", "zonesManager")])
+
+res = do_funcs[cmd](args)
+
+sys.exit(res);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/zmgr/ztest.py	Wed May 12 16:54:43 2010 -0700
@@ -0,0 +1,188 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+import socket
+import rad.client as rad
+import sys
+
+# Make connection (AF_UNIX socket lets us bypass authentication)
+s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM);
+s.connect("/var/run/radsocket");
+
+#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
+#s.connect(("localhost", 1234))
+
+rc = rad.RadConnection(s)
+
+# Get an authorization token from authenticated session
+#auth = rc.get_object_s("org.opensolaris.os.rad", [("type", "authentication")])
+#block = auth.login("C", "root");
+#print block.type
+#for m in block.messages:
+#	print m.style
+#	print m.message
+#block = auth.submit(["l1admin"])
+#print block.type
+
+# Continue using newly authenticated session
+# Obtain service object for application/pkg/server:default
+obj = rc.get_object_s("com.oracle.solaris.zonesManagement", [("type", "zonesManager")])
+
+print ""
+print "Test getSystemState"
+try:
+	systemState = obj.getSystemState(0, 0, 0, 0, None)
+	print "\tPASS"
+except:
+	print "\tFAIL"
+
+print ""
+print "Test zone name lists"
+try:
+	
+	print "\tzones     :", systemState.zoneNames
+	print "\tconfigured:", systemState.zonesConfigured
+	print "\tinstalled :", systemState.zonesInstalled
+	print "\trunning   :", systemState.zonesRunning
+	print "\tPASS"
+except:
+	print "\tFAIL"
+
+print ""
+print "Test print zone states"
+try:
+	for state in systemState.zones:
+
+		cfg = obj.getZoneConfig(state.name)
+
+
+		print ""
+		print "\t", state.name
+		print "\tstate: ", state.state
+
+		print "\tconfigured:"
+
+		print "\tzonepath: ", cfg.zonePath
+		print "\tiptype  : ", cfg.iptype
+		print "\tscheduler: ", cfg.scheduler
+		for network in cfg.networks:
+			print "\tnetwork : ", network.physical
+			if network.address:
+				print "\t          ", network.address
+
+		print "    installed:"
+		if state.name in systemState.zonesInstalled:
+			print "\tzonepath: ", state.installedState.zonepath
+			print "\tuuid    : ", state.installedState.uuid
+		print "    running:"
+		if state.name in systemState.zonesRunning:
+			print "\tiptype  : ", state.runningState.iptype
+			for network in state.runningState.networks:
+				print "\tnetwork : ", network.physical
+				if network.address:
+					print "\t          ", network.address
+except:
+	print "\tFAIL"
+
+print ""
+print "Test configure and unconfigure zone"
+try:
+	cfgtype = obj._object.get_type("ZoneConfig");
+	cfg = cfgtype.makev("test-unconfig", "/export/test-unconfig",
+	    "FSS", "1", "SHARED", None, None, None, None)
+	obj.zoneConfigure(cfg);
+	cfg = obj.getZoneConfig("test-unconfig");
+	obj.zoneUnconfigure("test-unconfig");
+	try:
+		obj.getZoneConfig("test-unconfig");
+		print "\tFAIL"
+	except rad.RadException, ex:
+		print "\tPASS"
+except rad.RadException, ex:
+	print "\tFAIL"
+	print ex.get_payload()
+
+print ""
+print "Test configure, install, boot, reboot, halt, uninstall, unconfigure"
+try:
+	cfgtype = obj._object.get_type("ZoneConfig");
+	cfg = cfgtype.makev("test-install", "/export/test-install",
+	    "FSS", "1", "SHARED", None, None, None, None)
+	obj.zoneConfigure(cfg);
+	obj.zoneInstall("test-install", []);
+	obj.zoneBoot("test-install")
+	obj.zoneReboot("test-install")
+	obj.zoneHalt("test-install")
+	obj.zoneUninstall("test-install");
+	obj.zoneUnconfigure("test-install");
+	print "\tPASS"
+except rad.RadException, ex:
+	print "\tFAIL"
+	err = ex.get_payload()
+	print err;
+
+print ""
+print "Test boot non-existent zone:"
+try:
+	res = obj.zoneBoot("nosuchzone")
+	print "\tFAILED"
+except rad.RadException, ex:
+	error = ex.get_payload();
+	print "\t", error.message
+	print "\tPASS"
+
+
+print ""
+print "Test setZoneConfig"
+argtype = obj._object.get_type("ZoneConfig");
+
+try:
+	# Configure zone
+	zoneConfig = argtype.makev("test", "/export/oldpath", "", "",
+	    "SHARED", None, None, None, None)
+	obj.zoneConfigure(zoneConfig);
+
+	# Change zonepath
+	newConfig = argtype.makev("test", "/export/newpath", "", "",
+	    "SHARED", None, None, None, None)
+	obj.setZoneConfig("test", newConfig);
+
+	# Change zonename
+	newConfig = argtype.makev("test-new", "/export/newpath", "", "",
+	    "SHARED", None, None, None, None)
+	obj.setZoneConfig("test", newConfig);
+
+	# Change scheduler and cpu shares
+	newConfig = argtype.makev("test-new", "/export/newpath", "FSS", "10",
+	    "SHARED", None, None, None, None)
+	obj.setZoneConfig("test-new", newConfig);
+
+	# Unconfigure zones
+	obj.zoneUnconfigure("test-new");
+	print "\tPASS"
+except rad.RadException, ex:
+	error = ex.get_payload();
+	print error.message
+	print "\tFAILED"
+
+s.close()
--- a/usr/src/lib/pyrad/client.py	Fri May 07 17:25:43 2010 -0700
+++ b/usr/src/lib/pyrad/client.py	Wed May 12 16:54:43 2010 -0700
@@ -181,7 +181,7 @@
 	    return unpacker.unpack_array(lambda: self._atype.read(unpacker))
 	elif self._type == Type.COMPOSITE:
 	    o = RadData(self)
-	    for i in self._fields:
+	    for i in self._pfields:
 		# order isn't important, yet
 		name = unpacker.unpack_string()
 		o.__dict__[name] = self._fields[name]._type.read(unpacker, True)