--- old/usr/src/cmd/zoneadm/zoneadm.c	Wed Oct  5 00:33:10 2016
+++ new/usr/src/cmd/zoneadm/zoneadm.c	Wed Oct  5 00:33:10 2016
@@ -22,8 +22,8 @@
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
- * Copyright 2015, Joyent Inc. All rights reserved.
  * Copyright (c) 2015 by Delphix. All rights reserved.
+ * Copyright 2015, Joyent Inc. All rights reserved.
  */
 
 /*
@@ -107,6 +107,9 @@
 
 #define	CLUSTER_BRAND_NAME	"cluster"
 
+static zone_entry_t *zents;
+static size_t nzents;
+
 #define	LOOPBACK_IF	"lo0"
 #define	SOCKET_AF(af)	(((af) == AF_UNSPEC) ? AF_INET : (af))
 
@@ -405,6 +408,19 @@
 	va_end(alist);
 }
 
+static void *
+safe_calloc(size_t nelem, size_t elsize)
+{
+	void *r = calloc(nelem, elsize);
+
+	if (r == NULL) {
+		zerror(gettext("failed to allocate %lu bytes: %s"),
+		    (ulong_t)nelem * elsize, strerror(errno));
+		exit(Z_ERR);
+	}
+	return (r);
+}
+
 static void
 zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable)
 {
@@ -476,9 +492,6 @@
 	(void) strlcpy(zent->zbrand, "???", sizeof (zent->zbrand));
 	zent->zstate_str = "???";
 
-	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
-		zid = zent->zdid = GLOBAL_ZONEID;
-
 	zent->zid = zid;
 
 	if (zonecfg_get_uuid(zone_name, uuid) == Z_OK &&
@@ -523,8 +536,8 @@
 	zent->zstate_str = zone_state_str(zent->zstate_num);
 
 	/*
-	 * A zone's brand might only be available in the .xml file describing
-	 * it, which is only visible to the global zone.  This causes
+	 * A zone's brand is only available in the .xml file describing it,
+	 * which is only visible to the global zone.  This causes
 	 * zone_get_brand() to fail when called from within a non-global
 	 * zone.  Fortunately we only do this on labeled systems, where we
 	 * know all zones are native.
@@ -594,63 +607,165 @@
 	return (Z_OK);
 }
 
+/*
+ * fetch_zents() calls zone_list(2) to find out how many zones are running
+ * (which is stored in the global nzents), then calls zone_list(2) again
+ * to fetch the list of running zones (stored in the global zents).  This
+ * function may be called multiple times, so if zents is already set, we
+ * return immediately to save work.
+ *
+ * Note that the data about running zones can change while this function
+ * is running, so its possible that the list of zones will have empty slots
+ * at the end.
+ */
+
 static int
-zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable)
+fetch_zents(void)
 {
-	zone_entry_t zent;
-	FILE *cookie;
-	struct zoneent *ze;
+	zoneid_t *zids = NULL;
+	uint_t nzents_saved;
+	int i, retv;
+	FILE *fp;
+	boolean_t inaltroot;
+	zone_entry_t *zentp;
+	const char *altroot;
 
-	/*
-	 * Get the full list of zones from the configuration.
-	 */
-	cookie = setzoneent();
-	while ((ze = getzoneent_private(cookie)) != NULL) {
-		char *name = ze->zone_name;
-		zoneid_t zid;
+	if (nzents > 0)
+		return (Z_OK);
 
-		zid = getzoneidbyname(name);
+	if (zone_list(NULL, &nzents) != 0) {
+		zperror(gettext("failed to get zoneid list"), B_FALSE);
+		return (Z_ERR);
+	}
 
-		if (ze->zone_brand[0] == '\0') {
-			/* old, incomplete index entry */
-			if (lookup_zone_info(name, zid, &zent) != Z_OK) {
-				free(ze);
+again:
+	if (nzents == 0)
+		return (Z_OK);
+
+	zids = safe_calloc(nzents, sizeof (zoneid_t));
+	nzents_saved = nzents;
+
+	if (zone_list(zids, &nzents) != 0) {
+		zperror(gettext("failed to get zone list"), B_FALSE);
+		free(zids);
+		return (Z_ERR);
+	}
+	if (nzents != nzents_saved) {
+		/* list changed, try again */
+		free(zids);
+		goto again;
+	}
+
+	zents = safe_calloc(nzents, sizeof (zone_entry_t));
+
+	inaltroot = zonecfg_in_alt_root();
+	if (inaltroot) {
+		fp = zonecfg_open_scratch("", B_FALSE);
+		altroot = zonecfg_get_root();
+	} else {
+		fp = NULL;
+	}
+	zentp = zents;
+	retv = Z_OK;
+	for (i = 0; i < nzents; i++) {
+		char name[ZONENAME_MAX];
+		char altname[ZONENAME_MAX];
+		char rev_altroot[MAXPATHLEN];
+
+		if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) {
+			/*
+			 * There is a race condition where the zone may have
+			 * shutdown since we retrieved the number of running
+			 * zones above.  This is not an error, there will be
+			 * an empty slot at the end of the list.
+			 */
+			continue;
+		}
+		if (zonecfg_is_scratch(name)) {
+			/* Ignore scratch zones by default */
+			if (!inaltroot)
 				continue;
+			if (fp == NULL ||
+			    zonecfg_reverse_scratch(fp, name, altname,
+			    sizeof (altname), rev_altroot,
+			    sizeof (rev_altroot)) == -1) {
+				zerror(gettext("could not resolve scratch "
+				    "zone %s"), name);
+				retv = Z_ERR;
+				continue;
 			}
+			/* Ignore zones in other alternate roots */
+			if (strcmp(rev_altroot, altroot) != 0)
+				continue;
+			(void) strcpy(name, altname);
 		} else {
-			/* new, full index entry */
-			(void) strlcpy(zent.zname, name, sizeof (zent.zname));
-			(void) strlcpy(zent.zroot, ze->zone_path,
-			    sizeof (zent.zroot));
-			uuid_unparse(ze->zone_uuid, zent.zuuid);
-			(void) strlcpy(zent.zbrand, ze->zone_brand,
-			    sizeof (zent.zbrand));
-			zent.ziptype = ze->zone_iptype;
-			zent.zdid = ze->zone_did;
-			zent.zid = zid;
+			/* Ignore non-scratch when in an alternate root */
+			if (inaltroot && strcmp(name, GLOBAL_ZONENAME) != 0)
+				continue;
+		}
+		if (lookup_zone_info(name, zids[i], zentp) != Z_OK) {
+			/*
+			 * There is a race condition where the zone may have
+			 * shutdown since we retrieved the number of running
+			 * zones above.  This is not an error, there will be
+			 * an empty slot at the end of the list.
+			 */
+			continue;
+		}
+		zentp++;
+	}
+	nzents = zentp - zents;
+	if (fp != NULL)
+		zonecfg_close_scratch(fp);
 
-			if (zid != -1) {
-				int err;
+	free(zids);
+	return (retv);
+}
 
-				err = zone_get_state(name,
-				    (zone_state_t *)&ze->zone_state);
-				if (err != Z_OK) {
-					errno = err;
-					zperror2(name, gettext("could not get "
-					    "state"));
-					free(ze);
-					continue;
-				}
-			}
+static int
+zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable)
+{
+	int i;
+	zone_entry_t zent;
+	FILE *cookie;
+	char *name;
 
-			zent.zstate_num = ze->zone_state;
-			zent.zstate_str = zone_state_str(zent.zstate_num);
+	/*
+	 * First get the list of running zones from the kernel and print them.
+	 * If that is all we need, then return.
+	 */
+	if ((i = fetch_zents()) != Z_OK) {
+		/*
+		 * No need for error messages; fetch_zents() has already taken
+		 * care of this.
+		 */
+		return (i);
+	}
+	for (i = 0; i < nzents; i++)
+		zone_print(&zents[i], verbose, parsable);
+	if (min_state >= ZONE_STATE_RUNNING)
+		return (Z_OK);
+	/*
+	 * Next, get the full list of zones from the configuration, skipping
+	 * any we have already printed.
+	 */
+	cookie = setzoneent();
+	while ((name = getzoneent(cookie)) != NULL) {
+		for (i = 0; i < nzents; i++) {
+			if (strcmp(zents[i].zname, name) == 0)
+				break;
 		}
-
+		if (i < nzents) {
+			free(name);
+			continue;
+		}
+		if (lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) {
+			free(name);
+			continue;
+		}
+		free(name);
 		if (zent.zstate_num >= min_state)
 			zone_print(&zent, verbose, parsable);
-
-		free(ze);
 	}
 	endzoneent(cookie);
 	return (Z_OK);
@@ -911,12 +1026,8 @@
 		(void) printf(gettext("WARNING: %s is on a temporary "
 		    "file system.\n"), rpath);
 	}
-	if (cmd_num != CMD_BOOT && cmd_num != CMD_REBOOT &&
-	    cmd_num != CMD_READY) {
-		/* we checked when we installed, no need to check each boot */
-		if (crosscheck_zonepaths(rpath) != Z_OK)
-			return (Z_ERR);
-	}
+	if (crosscheck_zonepaths(rpath) != Z_OK)
+		return (Z_ERR);
 	/*
 	 * Try to collect and report as many minor errors as possible
 	 * before returning, so the user can learn everything that needs
@@ -1103,7 +1214,6 @@
 ready_func(int argc, char *argv[])
 {
 	zone_cmd_arg_t zarg;
-	boolean_t debug = B_FALSE;
 	int arg;
 
 	if (zonecfg_in_alt_root()) {
@@ -1112,14 +1222,11 @@
 	}
 
 	optind = 0;
-	if ((arg = getopt(argc, argv, "?X")) != EOF) {
+	if ((arg = getopt(argc, argv, "?")) != EOF) {
 		switch (arg) {
 		case '?':
 			sub_usage(SHELP_READY, CMD_READY);
 			return (optopt == '?' ? Z_OK : Z_USAGE);
-		case 'X':
-			debug = B_TRUE;
-			break;
 		default:
 			sub_usage(SHELP_READY, CMD_READY);
 			return (Z_USAGE);
@@ -1136,7 +1243,6 @@
 		return (Z_ERR);
 
 	zarg.cmd = Z_READY;
-	zarg.debug = debug;
 	if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
 		zerror(gettext("call to %s failed"), "zoneadmd");
 		return (Z_ERR);
@@ -1149,7 +1255,6 @@
 {
 	zone_cmd_arg_t zarg;
 	boolean_t force = B_FALSE;
-	boolean_t debug = B_FALSE;
 	int arg;
 
 	if (zonecfg_in_alt_root()) {
@@ -1176,7 +1281,7 @@
 	 *	zoneadm -z myzone boot -- -s -v -m verbose.
 	 */
 	optind = 0;
-	while ((arg = getopt(argc, argv, "?fsX")) != EOF) {
+	while ((arg = getopt(argc, argv, "?fs")) != EOF) {
 		switch (arg) {
 		case '?':
 			sub_usage(SHELP_BOOT, CMD_BOOT);
@@ -1188,9 +1293,6 @@
 		case 'f':
 			force = B_TRUE;
 			break;
-		case 'X':
-			debug = B_TRUE;
-			break;
 		default:
 			sub_usage(SHELP_BOOT, CMD_BOOT);
 			return (Z_USAGE);
@@ -1216,7 +1318,6 @@
 	if (verify_details(CMD_BOOT, argv) != Z_OK)
 		return (Z_ERR);
 	zarg.cmd = force ? Z_FORCEBOOT : Z_BOOT;
-	zarg.debug = debug;
 	if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
 		zerror(gettext("call to %s failed"), "zoneadmd");
 		return (Z_ERR);
@@ -1526,10 +1627,10 @@
  *     not already running (or ready).
  */
 static int
-sanity_check(char *zone, int cmd_num, boolean_t need_running,
+sanity_check(char *zone, int cmd_num, boolean_t running,
     boolean_t unsafe_when_running, boolean_t force)
 {
-	boolean_t is_running = B_FALSE;
+	zone_entry_t *zent;
 	priv_set_t *privset;
 	zone_state_t state, min_state;
 	char kernzone[ZONENAME_MAX];
@@ -1600,15 +1701,15 @@
 	}
 
 	if (!zonecfg_in_alt_root()) {
-		/* Avoid the xml read overhead of lookup_running_zone */
-		if (getzoneidbyname(zone) != -1)
-			is_running = B_TRUE;
-
-	} else if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
-		if (zonecfg_find_scratch(fp, zone, zonecfg_get_root(), kernzone,
-		    sizeof (kernzone)) == 0 && getzoneidbyname(kernzone) != -1)
-			is_running = B_TRUE;
-
+		zent = lookup_running_zone(zone);
+	} else if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL) {
+		zent = NULL;
+	} else {
+		if (zonecfg_find_scratch(fp, zone, zonecfg_get_root(),
+		    kernzone, sizeof (kernzone)) == 0)
+			zent = lookup_running_zone(kernzone);
+		else
+			zent = NULL;
 		zonecfg_close_scratch(fp);
 	}
 
@@ -1615,8 +1716,8 @@
 	/*
 	 * Look up from the kernel for 'running' zones.
 	 */
-	if (need_running && !force) {
-		if (!is_running) {
+	if (running && !force) {
+		if (zent == NULL) {
 			zerror(gettext("not running"));
 			return (Z_ERR);
 		}
@@ -1623,31 +1724,28 @@
 	} else {
 		int err;
 
-		err = zone_get_state(zone, &state);
-
-		if (unsafe_when_running && is_running) {
+		if (unsafe_when_running && zent != NULL) {
 			/* check whether the zone is ready or running */
-			char *zstate_str;
-
-			if (err != Z_OK) {
+			if ((err = zone_get_state(zent->zname,
+			    &zent->zstate_num)) != Z_OK) {
 				errno = err;
-				zperror2(zone, gettext("could not get state"));
+				zperror2(zent->zname,
+				    gettext("could not get state"));
 				/* can't tell, so hedge */
-				zstate_str = "ready/running";
+				zent->zstate_str = "ready/running";
 			} else {
-				zstate_str = zone_state_str(state);
+				zent->zstate_str =
+				    zone_state_str(zent->zstate_num);
 			}
 			zerror(gettext("%s operation is invalid for %s zones."),
-			    cmd_to_str(cmd_num), zstate_str);
+			    cmd_to_str(cmd_num), zent->zstate_str);
 			return (Z_ERR);
 		}
-
-		if (err != Z_OK) {
+		if ((err = zone_get_state(zone, &state)) != Z_OK) {
 			errno = err;
 			zperror2(zone, gettext("could not get state"));
 			return (Z_ERR);
 		}
-
 		switch (cmd_num) {
 		case CMD_UNINSTALL:
 			if (state == ZONE_STATE_CONFIGURED) {
@@ -1735,7 +1833,6 @@
 halt_func(int argc, char *argv[])
 {
 	zone_cmd_arg_t zarg;
-	boolean_t debug = B_FALSE;
 	int arg;
 
 	if (zonecfg_in_alt_root()) {
@@ -1744,14 +1841,11 @@
 	}
 
 	optind = 0;
-	if ((arg = getopt(argc, argv, "?X")) != EOF) {
+	if ((arg = getopt(argc, argv, "?")) != EOF) {
 		switch (arg) {
 		case '?':
 			sub_usage(SHELP_HALT, CMD_HALT);
 			return (optopt == '?' ? Z_OK : Z_USAGE);
-		case 'X':
-			debug = B_TRUE;
-			break;
 		default:
 			sub_usage(SHELP_HALT, CMD_HALT);
 			return (Z_USAGE);
@@ -1777,7 +1871,6 @@
 		return (Z_ERR);
 
 	zarg.cmd = Z_HALT;
-	zarg.debug = debug;
 	return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale,
 	    B_TRUE) == 0) ?  Z_OK : Z_ERR);
 }
@@ -1855,7 +1948,6 @@
 reboot_func(int argc, char *argv[])
 {
 	zone_cmd_arg_t zarg;
-	boolean_t debug = B_FALSE;
 	int arg;
 
 	if (zonecfg_in_alt_root()) {
@@ -1864,14 +1956,11 @@
 	}
 
 	optind = 0;
-	if ((arg = getopt(argc, argv, "?X")) != EOF) {
+	if ((arg = getopt(argc, argv, "?")) != EOF) {
 		switch (arg) {
 		case '?':
 			sub_usage(SHELP_REBOOT, CMD_REBOOT);
 			return (optopt == '?' ? Z_OK : Z_USAGE);
-		case 'X':
-			debug = B_TRUE;
-			break;
 		default:
 			sub_usage(SHELP_REBOOT, CMD_REBOOT);
 			return (Z_USAGE);
@@ -1906,7 +1995,6 @@
 		return (Z_ERR);
 
 	zarg.cmd = Z_REBOOT;
-	zarg.debug = debug;
 	return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) == 0)
 	    ? Z_OK : Z_ERR);
 }
@@ -2134,10 +2222,6 @@
 	if (strcmp(fstab->zone_fs_type, MNTTYPE_ZFS) == 0)
 		return (verify_fs_zfs(fstab));
 
-	if (strcmp(fstab->zone_fs_type, MNTTYPE_HYPRLOFS) == 0 &&
-	    strcmp(fstab->zone_fs_special, "swap") == 0)
-			return (Z_OK);
-
 	if (stat64(fstab->zone_fs_special, &st) != 0) {
 		(void) fprintf(stderr, gettext("could not verify fs "
 		    "%s: could not access %s: %s\n"), fstab->zone_fs_dir,
@@ -2541,6 +2625,7 @@
 	dladm_handle_t dh;
 	dladm_status_t status;
 	datalink_id_t linkid;
+	char errmsg[DLADM_STRSIZE];
 
 	in_alt_root = zonecfg_in_alt_root();
 	if (in_alt_root)
@@ -2623,6 +2708,11 @@
 				dladm_close(dh);
 			}
 			if (status != DLADM_STATUS_OK) {
+				(void) fprintf(stderr,
+				    gettext("WARNING: skipping network "
+				    "interface '%s': %s\n"),
+				    nwiftab.zone_nwif_physical,
+				    dladm_status2str(status, errmsg));
 				break;
 			}
 			dl_owner_zid = ALL_ZONES;
@@ -2720,8 +2810,9 @@
 verify_fix_did(zone_dochandle_t handle)
 {
 	zoneid_t mydid;
-	struct zoneent *ze;
+	zone_entry_t zent;
 	FILE *cookie;
+	char *name;
 	boolean_t fix = B_FALSE;
 
 	mydid = zonecfg_get_did(handle);
@@ -2732,34 +2823,20 @@
 
 	/* Get the full list of zones from the configuration. */
 	cookie = setzoneent();
-	while ((ze = getzoneent_private(cookie)) != NULL) {
-		char *name;
-		zoneid_t did;
+	while ((name = getzoneent(cookie)) != NULL) {
+		if (strcmp(target_zone, name) == 0) {
+			free(name);
+			break;	/* Once we find our entry, stop. */
+		}
 
-		name = ze->zone_name;
-		if (strcmp(name, GLOBAL_ZONENAME) == 0 ||
-		    strcmp(name, target_zone) == 0) {
-			free(ze);
+		if (strcmp(name, "global") == 0 ||
+		    lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) {
+			free(name);
 			continue;
 		}
 
-		if (ze->zone_brand[0] == '\0') {
-			/* old, incomplete index entry */
-			zone_entry_t zent;
-
-			if (lookup_zone_info(name, ZONE_ID_UNDEFINED,
-			    &zent) != Z_OK) {
-				free(ze);
-				continue;
-			}
-			did = zent.zdid;
-		} else {
-			/* new, full index entry */
-			did = ze->zone_did;
-		}
-		free(ze);
-
-		if (did == mydid) {
+		free(name);
+		if (zent.zdid == mydid) {
 			fix = B_TRUE;
 			break;
 		}
@@ -2930,7 +3007,6 @@
 	int status;
 	boolean_t do_postinstall = B_FALSE;
 	boolean_t brand_help = B_FALSE;
-	boolean_t do_dataset = B_TRUE;
 	char opts[128];
 
 	if (target_zone == NULL) {
@@ -3006,12 +3082,6 @@
 			}
 			/* Ignore unknown options - may be brand specific. */
 			break;
-		case 'x':
-			if (strcmp(optarg, "nodataset") == 0) {
-				do_dataset = B_FALSE;
-				continue; /* internal arg, don't pass thru */
-			}
-			break;
 		default:
 			/* Ignore unknown options - may be brand specific. */
 			break;
@@ -3064,8 +3134,7 @@
 			goto done;
 		}
 
-		if (do_dataset)
-			create_zfs_zonepath(zonepath);
+		create_zfs_zonepath(zonepath);
 	}
 
 	status = do_subproc(cmdbuf);
@@ -5029,7 +5098,6 @@
 		if (zonecfg_ping_zoneadmd(target_zone) == Z_OK) {
 			zone_cmd_arg_t zarg;
 			zarg.cmd = Z_NOTE_UNINSTALLING;
-			zarg.debug = B_FALSE;
 			/* we don't care too much if this fails, just plow on */
 			(void) zonecfg_call_zoneadmd(target_zone, &zarg, locale,
 			    B_TRUE);
@@ -5145,7 +5213,6 @@
 		return (Z_ERR);
 
 	zarg.cmd = force ? Z_FORCEMOUNT : Z_MOUNT;
-	zarg.debug = B_FALSE;
 	zarg.bootbuf[0] = '\0';
 	if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
 		zerror(gettext("call to %s failed"), "zoneadmd");
@@ -5167,7 +5234,6 @@
 		return (Z_ERR);
 
 	zarg.cmd = Z_UNMOUNT;
-	zarg.debug = B_FALSE;
 	if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
 		zerror(gettext("call to %s failed"), "zoneadmd");
 		return (Z_ERR);
