Print this page
@@ -20,12 +20,12 @@
*/
/*
* 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.
*/
/*
* zoneadm is a command interpreter for zone administration. It is all in
* C (i.e., no lex/yacc), and all the argument passing is argc/argv based.
@@ -105,10 +105,13 @@
zoneid_t zdid;
} zone_entry_t;
#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))
struct net_if {
char *name;
@@ -403,10 +406,23 @@
(void) vfprintf(stderr, fmt, alist);
(void) fprintf(stderr, "\n");
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)
{
static boolean_t firsttime = B_TRUE;
char *ip_type_str;
@@ -474,13 +490,10 @@
(void) strlcpy(zent->zname, zone_name, sizeof (zent->zname));
(void) strlcpy(zent->zroot, "???", sizeof (zent->zroot));
(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 &&
!uuid_is_null(uuid))
uuid_unparse(uuid, zent->zuuid);
@@ -521,12 +534,12 @@
return (Z_ERR);
}
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.
*/
if (getzoneid() != GLOBAL_ZONEID) {
@@ -592,67 +605,169 @@
zonecfg_fini_handle(handle);
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);
- continue;
+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);
}
- } 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;
+ if (nzents != nzents_saved) {
+ /* list changed, try again */
+ free(zids);
+ goto again;
+ }
- if (zid != -1) {
- int err;
+ zents = safe_calloc(nzents, sizeof (zone_entry_t));
- 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);
+ 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;
}
-
- zent.zstate_num = ze->zone_state;
- zent.zstate_str = zone_state_str(zent.zstate_num);
+ /* Ignore zones in other alternate roots */
+ if (strcmp(rev_altroot, altroot) != 0)
+ continue;
+ (void) strcpy(name, altname);
+ } else {
+ /* 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);
+ free(zids);
+ return (retv);
+}
+
+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;
+
+ /*
+ * 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);
}
@@ -909,16 +1024,12 @@
}
if (strcmp(stbuf.st_fstype, MNTTYPE_TMPFS) == 0) {
(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);
- }
/*
* Try to collect and report as many minor errors as possible
* before returning, so the user can learn everything that needs
* to be fixed up front.
*/
@@ -1101,27 +1212,23 @@
static int
ready_func(int argc, char *argv[])
{
zone_cmd_arg_t zarg;
- boolean_t debug = B_FALSE;
int arg;
if (zonecfg_in_alt_root()) {
zerror(gettext("cannot ready zone in alternate root"));
return (Z_ERR);
}
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);
}
}
@@ -1134,11 +1241,10 @@
return (Z_ERR);
if (verify_details(CMD_READY, argv) != Z_OK)
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);
}
return (Z_OK);
@@ -1147,11 +1253,10 @@
static int
boot_func(int argc, char *argv[])
{
zone_cmd_arg_t zarg;
boolean_t force = B_FALSE;
- boolean_t debug = B_FALSE;
int arg;
if (zonecfg_in_alt_root()) {
zerror(gettext("cannot boot zone in alternate root"));
return (Z_ERR);
@@ -1174,11 +1279,11 @@
* is:
*
* 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);
return (optopt == '?' ? Z_OK : Z_USAGE);
case 's':
@@ -1186,13 +1291,10 @@
sizeof (zarg.bootbuf));
break;
case 'f':
force = B_TRUE;
break;
- case 'X':
- debug = B_TRUE;
- break;
default:
sub_usage(SHELP_BOOT, CMD_BOOT);
return (Z_USAGE);
}
}
@@ -1214,11 +1316,10 @@
!= Z_OK)
return (Z_ERR);
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);
}
@@ -1524,14 +1625,14 @@
* zone, the name service knows about it.
* 4b. For some operations which expect a zone not to be running, that it is
* 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];
FILE *fp;
@@ -1598,58 +1699,55 @@
"with SUNW."), cmd_to_str(cmd_num));
return (Z_ERR);
}
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);
}
/*
* 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);
}
} 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) {
zerror(gettext("is already in state '%s'."),
zone_state_str(ZONE_STATE_CONFIGURED));
@@ -1733,27 +1831,23 @@
static int
halt_func(int argc, char *argv[])
{
zone_cmd_arg_t zarg;
- boolean_t debug = B_FALSE;
int arg;
if (zonecfg_in_alt_root()) {
zerror(gettext("cannot halt zone in alternate root"));
return (Z_ERR);
}
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);
}
}
@@ -1775,11 +1869,10 @@
*/
if (invoke_brand_handler(CMD_HALT, argv) != Z_OK)
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);
}
static int
@@ -1853,27 +1946,23 @@
static int
reboot_func(int argc, char *argv[])
{
zone_cmd_arg_t zarg;
- boolean_t debug = B_FALSE;
int arg;
if (zonecfg_in_alt_root()) {
zerror(gettext("cannot reboot zone in alternate root"));
return (Z_ERR);
}
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);
}
}
@@ -1904,11 +1993,10 @@
return (Z_ERR);
if (verify_details(CMD_REBOOT, argv) != Z_OK)
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);
}
static int
@@ -2132,14 +2220,10 @@
return (Z_OK);
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,
fstab->zone_fs_special, strerror(errno));
return (Z_ERR);
@@ -2539,10 +2623,11 @@
boolean_t in_alt_root;
zone_iptype_t iptype;
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)
goto no_net;
@@ -2621,10 +2706,15 @@
nwiftab.zone_nwif_physical, &linkid, NULL,
NULL, NULL);
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;
if (zone_check_datalink(&dl_owner_zid, linkid) != 0)
break;
@@ -2718,12 +2808,13 @@
*/
static boolean_t
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);
if (mydid == -1) {
zonecfg_set_did(handle);
@@ -2730,38 +2821,24 @@
return (B_TRUE);
}
/* Get the full list of zones from the configuration. */
cookie = setzoneent();
- while ((ze = getzoneent_private(cookie)) != NULL) {
- char *name;
- zoneid_t did;
-
- name = ze->zone_name;
- if (strcmp(name, GLOBAL_ZONENAME) == 0 ||
- strcmp(name, target_zone) == 0) {
- free(ze);
- continue;
+ while ((name = getzoneent(cookie)) != NULL) {
+ if (strcmp(target_zone, name) == 0) {
+ free(name);
+ break; /* Once we find our entry, stop. */
}
- 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);
+ if (strcmp(name, "global") == 0 ||
+ lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) {
+ free(name);
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;
}
}
endzoneent(cookie);
@@ -2928,11 +3005,10 @@
char zonepath[MAXPATHLEN];
brand_handle_t bh = NULL;
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) {
sub_usage(SHELP_INSTALL, CMD_INSTALL);
return (Z_USAGE);
@@ -3004,16 +3080,10 @@
sub_usage(SHELP_INSTALL, CMD_INSTALL);
brand_help = B_TRUE;
}
/* 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;
}
@@ -3062,11 +3132,10 @@
errno = err;
zperror2(target_zone, gettext("could not set state"));
goto done;
}
- if (do_dataset)
create_zfs_zonepath(zonepath);
}
status = do_subproc(cmdbuf);
if ((subproc_err =
@@ -5027,11 +5096,10 @@
* well it will then shut itself down.
*/
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);
}
@@ -5143,11 +5211,10 @@
return (Z_ERR);
if (verify_details(CMD_MOUNT, argv) != Z_OK)
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");
return (Z_ERR);
}
@@ -5165,11 +5232,10 @@
if (sanity_check(target_zone, CMD_UNMOUNT, B_FALSE, B_FALSE, B_FALSE)
!= Z_OK)
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);
}
return (Z_OK);