summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordp <none@none>2005-09-16 16:54:53 -0700
committerdp <none@none>2005-09-16 16:54:53 -0700
commit087719fdb025870aa55ae7d42f46547e050208ec (patch)
treeb328283bfbc18a3122c5f281d090d203d29c1b89
parentfb87b5d22f7b8fbdd3a861267723144d852c7869 (diff)
downloadillumos-joyent-087719fdb025870aa55ae7d42f46547e050208ec.tar.gz
PSARC 2005/485 Zone Rename
4963365 zonecfg is unhelpful if /etc/zones not present 4971371 zonecfg should be more paranoid when saving a zone for the first time 5022506 RFE: ability to rename zones 6231612 zonecfg messaging should be improved. 6305400 when zone metadata gets confused, removing configured zones can fail 6318536 zonecfg sometimes seen spinning during certain STC test cases 6321858 zonecfg tab completion could complete slightly more
-rw-r--r--usr/src/cmd/zonecfg/zonecfg.c600
-rw-r--r--usr/src/cmd/zonecfg/zonecfg.h54
-rw-r--r--usr/src/cmd/zonecfg/zonecfg_grammar.y18
-rw-r--r--usr/src/cmd/zonecfg/zonecfg_lex.l5
-rw-r--r--usr/src/head/libzonecfg.h15
-rw-r--r--usr/src/lib/libzonecfg/common/getzoneent.c29
-rw-r--r--usr/src/lib/libzonecfg/common/libzonecfg.c500
-rw-r--r--usr/src/lib/libzonecfg/spec/libzonecfg.spec26
8 files changed, 830 insertions, 417 deletions
diff --git a/usr/src/cmd/zonecfg/zonecfg.c b/usr/src/cmd/zonecfg/zonecfg.c
index 46f389a768..69e931e1a9 100644
--- a/usr/src/cmd/zonecfg/zonecfg.c
+++ b/usr/src/cmd/zonecfg/zonecfg.c
@@ -143,6 +143,7 @@ static struct help helptab[] = {
/* These *must* match the order of the RT_ define's from zonecfg.h */
static char *res_types[] = {
"unknown",
+ "zonename",
"zonepath",
"autoboot",
"pool",
@@ -158,6 +159,7 @@ static char *res_types[] = {
/* These *must* match the order of the PT_ define's from zonecfg.h */
static char *prop_types[] = {
"unknown",
+ "zonename",
"zonepath",
"autoboot",
"pool",
@@ -221,19 +223,20 @@ static const char *add_cmds[] = {
};
static const char *select_cmds[] = {
- "select fs",
- "select inherit-pkg-dir",
- "select net",
- "select device",
- "select rctl",
- "select attr",
+ "select fs ",
+ "select inherit-pkg-dir ",
+ "select net ",
+ "select device ",
+ "select rctl ",
+ "select attr ",
NULL
};
static const char *set_cmds[] = {
- "set zonepath",
- "set autoboot",
- "set pool",
+ "set zonename=",
+ "set zonepath=",
+ "set autoboot=",
+ "set pool=",
NULL
};
@@ -314,7 +317,8 @@ static char *execname;
static zone_dochandle_t handle;
/* used all over the place */
-static char *zone;
+static char zone[ZONENAME_MAX];
+static char revert_zone[ZONENAME_MAX];
/* set in modifying functions, checked in read_input() */
static bool need_to_commit = FALSE;
@@ -344,9 +348,6 @@ static bool interactive_mode;
/* set in main(), checked in multiple places */
static bool read_only_mode;
-/* set in check_if_zone_already_exists(), checked in save_it() */
-static bool new_zone = FALSE;
-
static bool global_scope = TRUE; /* scope is outer/global or inner/resource */
static int resource_scope; /* should be in the RT_ list from zonecfg.h */
static int end_op = -1; /* operation on end is either add or modify */
@@ -849,6 +850,8 @@ usage(bool verbose, uint_t flags)
(void) fprintf(fp, gettext("For resource type ... there are "
"property types ...:\n"));
(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
+ pt_to_str(PT_ZONENAME));
+ (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
pt_to_str(PT_ZONEPATH));
(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
pt_to_str(PT_AUTOBOOT));
@@ -942,6 +945,23 @@ initialize(bool handle_expected)
return (Z_OK);
}
+static bool
+state_atleast(zone_state_t state)
+{
+ zone_state_t state_num;
+ int err;
+
+ if ((err = zone_get_state(zone, &state_num)) != Z_OK) {
+ /* all states are greater than "non-existent" */
+ if (err == Z_NO_ZONE)
+ return (B_FALSE);
+ zerr(gettext("Unexpectedly failed to determine state "
+ "of zone %s: %s"), zone, zonecfg_strerror(err));
+ exit(Z_ERR);
+ }
+ return (state_num >= state);
+}
+
/*
* short_usage() is for bad syntax: getopt() issues, too many arguments, etc.
*/
@@ -1023,10 +1043,13 @@ ask_yesno(bool default_answer, const char *question)
return (-1);
}
for (;;) {
- (void) printf("%s (%s)? ", question,
- default_answer ? "[y]/n" : "y/[n]");
- if (fgets(line, sizeof (line), stdin) == NULL ||
- line[0] == '\n')
+ if (printf("%s (%s)? ", question,
+ default_answer ? "[y]/n" : "y/[n]") < 0)
+ return (-1);
+ if (fgets(line, sizeof (line), stdin) == NULL)
+ return (-1);
+
+ if (line[0] == '\n')
return (default_answer ? 1 : 0);
if (tolower(line[0]) == 'y')
return (1);
@@ -1048,7 +1071,6 @@ static int
check_if_zone_already_exists(bool force)
{
char line[ZONENAME_MAX + 128]; /* enough to ask a question */
- zone_state_t state_num;
zone_dochandle_t tmphandle;
int res, answer;
@@ -1058,12 +1080,10 @@ check_if_zone_already_exists(bool force)
}
res = zonecfg_get_handle(zone, tmphandle);
zonecfg_fini_handle(tmphandle);
- if (res != Z_OK) {
- new_zone = TRUE;
+ if (res != Z_OK)
return (Z_OK);
- }
- if (zone_get_state(zone, &state_num) == Z_OK &&
- state_num >= ZONE_STATE_INSTALLED) {
+
+ if (state_atleast(ZONE_STATE_INSTALLED)) {
zerr(gettext("Zone %s already installed; %s not allowed."),
zone, cmd_to_str(CMD_CREATE));
return (Z_ERR);
@@ -1167,17 +1187,17 @@ create_func(cmd_t *cmd)
zone_perror(execname, Z_NOMEM, TRUE);
exit(Z_ERR);
}
- if ((err = zonecfg_get_handle(zone_template, tmphandle)) != Z_OK) {
+ if ((err = zonecfg_get_template_handle(zone_template, zone,
+ tmphandle)) != Z_OK) {
zonecfg_fini_handle(tmphandle);
zone_perror(zone_template, err, TRUE);
return;
}
+
+ need_to_commit = TRUE;
zonecfg_fini_handle(handle);
handle = tmphandle;
- if ((err = zonecfg_set_name(handle, zone)) == Z_OK)
- need_to_commit = TRUE;
- else
- zone_perror(zone, err, TRUE);
+ got_handle = TRUE;
}
/*
@@ -1456,7 +1476,6 @@ static void
add_resource(cmd_t *cmd)
{
int type;
- zone_state_t state_num;
if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
long_usage(CMD_ADD, TRUE);
@@ -1468,8 +1487,7 @@ add_resource(cmd_t *cmd)
bzero(&in_progress_fstab, sizeof (in_progress_fstab));
return;
case RT_IPD:
- if (zone_get_state(zone, &state_num) == Z_OK &&
- state_num >= ZONE_STATE_INSTALLED) {
+ if (state_atleast(ZONE_STATE_INSTALLED)) {
zerr(gettext("Zone %s already installed; %s %s not "
"allowed."), zone, cmd_to_str(CMD_ADD),
rt_to_str(RT_IPD));
@@ -1722,13 +1740,20 @@ add_func(cmd_t *cmd)
add_property(cmd);
}
+/*
+ * This routine has an unusual implementation, because it tries very
+ * hard to succeed in the face of a variety of failure modes.
+ * The most common and most vexing occurs when the index file and
+ * the /etc/zones/<zonename.xml> file are not both present. In
+ * this case, delete must eradicate as much of the zone state as is left
+ * so that the user can later create a new zone with the same name.
+ */
void
delete_func(cmd_t *cmd)
{
int err, arg, answer;
char line[ZONENAME_MAX + 128]; /* enough to ask a question */
bool force = FALSE;
- zone_state_t state_num;
optind = 0;
while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
@@ -1752,54 +1777,70 @@ delete_func(cmd_t *cmd)
if (zone_is_read_only(CMD_DELETE))
return;
- if (zone_get_state(zone, &state_num) == Z_OK &&
- state_num >= ZONE_STATE_INCOMPLETE) {
- zerr(gettext("Zone %s not in %s state; %s not allowed."),
- zone, zone_state_str(ZONE_STATE_CONFIGURED),
- cmd_to_str(CMD_DELETE));
- saw_error = TRUE;
- return;
- }
-
- if (initialize(TRUE) != Z_OK)
- return;
-
if (!force) {
+ /*
+ * Initialize sets up the global called "handle" and warns the
+ * user if the zone is not configured. In force mode, we don't
+ * trust that evaluation, and hence skip it. (We don't need the
+ * handle to be loaded anyway, since zonecfg_destroy is done by
+ * zonename). However, we also have to take care to emulate the
+ * messages spit out by initialize; see below.
+ */
+ if (initialize(TRUE) != Z_OK)
+ return;
+
(void) snprintf(line, sizeof (line),
gettext("Are you sure you want to delete zone %s"), zone);
if ((answer = ask_yesno(FALSE, line)) == -1) {
- zerr(gettext("Input not from "
- "terminal and -F not specified:\n%s command "
- "ignored, exiting."), cmd_to_str(CMD_DELETE));
+ zerr(gettext("Input not from terminal and -F not "
+ "specified:\n%s command ignored, exiting."),
+ cmd_to_str(CMD_DELETE));
exit(Z_ERR);
}
if (answer != 1)
return;
}
- if ((err = zonecfg_delete_index(zone)) != Z_OK) {
- zone_perror(zone, err, TRUE);
- return;
+ if ((err = zonecfg_destroy(zone, force)) != Z_OK) {
+ if ((err == Z_BAD_ZONE_STATE) && !force) {
+ zerr(gettext("Zone %s not in %s state; %s not "
+ "allowed. Use -F to force %s."),
+ zone, zone_state_str(ZONE_STATE_CONFIGURED),
+ cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE));
+ } else {
+ zone_perror(zone, err, TRUE);
+ }
}
-
need_to_commit = FALSE;
- if ((err = zonecfg_destroy(zone)) != Z_OK)
- zone_perror(zone, err, TRUE);
+
+ /*
+ * Emulate initialize's messaging; if there wasn't a valid handle to
+ * begin with, then user had typed delete (or delete -F) multiple
+ * times. So we emit a message.
+ *
+ * We only do this in the 'force' case because normally, initialize()
+ * takes care of this for us.
+ */
+ if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode)
+ (void) printf(gettext("Use '%s' to begin "
+ "configuring a new zone.\n"), cmd_to_str(CMD_CREATE));
/*
* Time for a new handle: finish the old one off first
* then get a new one properly to avoid leaks.
*/
- zonecfg_fini_handle(handle);
- if ((handle = zonecfg_init_handle()) == NULL) {
- zone_perror(execname, Z_NOMEM, TRUE);
- exit(Z_ERR);
- }
- if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) {
- /* If there was no zone before, that's OK */
- if (err != Z_NO_ZONE)
- zone_perror(zone, err, TRUE);
- got_handle = FALSE;
+ if (got_handle) {
+ zonecfg_fini_handle(handle);
+ if ((handle = zonecfg_init_handle()) == NULL) {
+ zone_perror(execname, Z_NOMEM, TRUE);
+ exit(Z_ERR);
+ }
+ if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) {
+ /* If there was no zone before, that's OK */
+ if (err != Z_NO_ZONE)
+ zone_perror(zone, err, TRUE);
+ got_handle = FALSE;
+ }
}
}
@@ -2045,7 +2086,6 @@ remove_resource(cmd_t *cmd)
struct zone_devtab devtab;
struct zone_attrtab attrtab;
struct zone_rctltab rctltab;
- zone_state_t state_num;
if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
long_usage(CMD_REMOVE, TRUE);
@@ -2068,8 +2108,7 @@ remove_resource(cmd_t *cmd)
zonecfg_free_fs_option_list(fstab.zone_fs_options);
return;
case RT_IPD:
- if (zone_get_state(zone, &state_num) == Z_OK &&
- state_num >= ZONE_STATE_INSTALLED) {
+ if (state_atleast(ZONE_STATE_INSTALLED)) {
zerr(gettext("Zone %s already installed; %s %s not "
"allowed."), zone, cmd_to_str(CMD_REMOVE),
rt_to_str(RT_IPD));
@@ -2278,7 +2317,6 @@ void
select_func(cmd_t *cmd)
{
int type, err;
- zone_state_t state_num;
if (zone_is_read_only(CMD_SELECT))
return;
@@ -2312,8 +2350,7 @@ select_func(cmd_t *cmd)
sizeof (struct zone_fstab));
return;
case RT_IPD:
- if (zone_get_state(zone, &state_num) == Z_OK &&
- state_num >= ZONE_STATE_INCOMPLETE) {
+ if (state_atleast(ZONE_STATE_INCOMPLETE)) {
zerr(gettext("Zone %s not in %s state; %s %s not "
"allowed."), zone,
zone_state_str(ZONE_STATE_CONFIGURED),
@@ -2473,7 +2510,7 @@ valid_fs_type(const char *type)
*/
if (strchr(type, '/') != NULL || type[0] == '\0' ||
strcmp(type, ".") == 0 || strcmp(type, "..") == 0)
- return (B_FALSE);
+ return (B_FALSE);
/*
* More detailed verification happens later by zoneadm(1m).
*/
@@ -2486,7 +2523,6 @@ set_func(cmd_t *cmd)
char *prop_id;
int err, res_type, prop_type;
property_value_ptr_t pp;
- zone_state_t state_num;
boolean_t autoboot;
if (zone_is_read_only(CMD_SET))
@@ -2496,7 +2532,9 @@ set_func(cmd_t *cmd)
prop_type = cmd->cmd_prop_name[0];
if (global_scope) {
- if (prop_type == PT_ZONEPATH) {
+ if (prop_type == PT_ZONENAME) {
+ res_type = RT_ZONENAME;
+ } else if (prop_type == PT_ZONEPATH) {
res_type = RT_ZONEPATH;
} else if (prop_type == PT_AUTOBOOT) {
res_type = RT_AUTOBOOT;
@@ -2533,13 +2571,35 @@ set_func(cmd_t *cmd)
return;
}
+ /*
+ * Special case: the user can change the zone name prior to 'create';
+ * if the zone already exists, we fall through letting initialize()
+ * and the rest of the logic run.
+ */
+ if (res_type == RT_ZONENAME && got_handle == FALSE &&
+ !state_atleast(ZONE_STATE_CONFIGURED)) {
+ (void) strlcpy(zone, prop_id, sizeof (zone));
+ return;
+ }
+
if (initialize(TRUE) != Z_OK)
return;
switch (res_type) {
+ case RT_ZONENAME:
+ if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) {
+ /*
+ * Use prop_id instead of 'zone' here, since we're
+ * reporting a problem about the *new* zonename.
+ */
+ zone_perror(prop_id, err, TRUE);
+ } else {
+ need_to_commit = TRUE;
+ (void) strlcpy(zone, prop_id, sizeof (zone));
+ }
+ return;
case RT_ZONEPATH:
- if (zone_get_state(zone, &state_num) == Z_OK &&
- state_num >= ZONE_STATE_INSTALLED) {
+ if (state_atleast(ZONE_STATE_INSTALLED)) {
zerr(gettext("Zone %s already installed; %s %s not "
"allowed."), zone, cmd_to_str(CMD_SET),
rt_to_str(RT_ZONEPATH));
@@ -2759,8 +2819,21 @@ output_prop(FILE *fp, int pnum, char *pval, bool print_notspec)
(void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr);
free(qstr);
} else if (print_notspec)
- (void) fprintf(fp, "\t%s %s\n", pt_to_str(pnum),
- gettext("not specified"));
+ (void) fprintf(fp, gettext("\t%s not specified\n"),
+ pt_to_str(pnum));
+}
+
+static void
+info_zonename(zone_dochandle_t handle, FILE *fp)
+{
+ char zonename[ZONENAME_MAX];
+
+ if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK)
+ (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME),
+ zonename);
+ else
+ (void) fprintf(fp, gettext("%s not specified\n"),
+ pt_to_str(PT_ZONENAME));
}
static void
@@ -2771,9 +2844,10 @@ info_zonepath(zone_dochandle_t handle, FILE *fp)
if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK)
(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH),
zonepath);
- else
- (void) fprintf(fp, "%s %s\n", pt_to_str(PT_ZONEPATH),
- gettext("not specified"));
+ else {
+ (void) fprintf(fp, gettext("%s not specified\n"),
+ pt_to_str(PT_ZONEPATH));
+ }
}
static void
@@ -3124,6 +3198,7 @@ info_func(cmd_t *cmd)
switch (cmd->cmd_res_type) {
case RT_UNKNOWN:
+ info_zonename(handle, fp);
info_zonepath(handle, fp);
info_autoboot(handle, fp);
info_pool(handle, fp);
@@ -3134,6 +3209,9 @@ info_func(cmd_t *cmd)
info_rctl(handle, fp, cmd);
info_attr(handle, fp, cmd);
break;
+ case RT_ZONENAME:
+ info_zonename(handle, fp);
+ break;
case RT_ZONEPATH:
info_zonepath(handle, fp);
break;
@@ -3171,22 +3249,20 @@ cleanup:
(void) pclose(fp);
}
-static int
-save_it(char *zonepath)
+/*
+ * Helper function for verify-- checks that a required string property
+ * exists.
+ */
+static void
+check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
{
- int err;
-
- if (new_zone) {
- err = zonecfg_add_index(zone, zonepath);
- if (err != Z_OK) {
- zone_perror(zone, err, TRUE);
- return (err);
- }
- new_zone = FALSE;
+ if (strlen(attr) == 0) {
+ zerr(gettext("%s: %s not specified"), rt_to_str(rt),
+ pt_to_str(pt));
+ saw_error = TRUE;
+ if (*ret_val == Z_OK)
+ *ret_val = Z_REQD_PROPERTY_MISSING;
}
- if ((err = zonecfg_save(handle)) == Z_OK)
- need_to_commit = FALSE;
- return (err);
}
/*
@@ -3236,13 +3312,12 @@ verify_func(cmd_t *cmd)
return;
if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK) {
- zerr("%s %s", pt_to_str(PT_ZONEPATH), gettext("not specified"));
+ zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH));
ret_val = Z_REQD_RESOURCE_MISSING;
saw_error = TRUE;
}
if (strlen(zonepath) == 0) {
- zerr("%s %s", pt_to_str(PT_ZONEPATH),
- gettext("cannot be empty."));
+ zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH));
ret_val = Z_REQD_RESOURCE_MISSING;
saw_error = TRUE;
}
@@ -3252,13 +3327,7 @@ verify_func(cmd_t *cmd)
return;
}
while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
- if (strlen(fstab.zone_fs_dir) == 0) {
- zerr("%s: %s %s", rt_to_str(RT_IPD), pt_to_str(PT_DIR),
- gettext("not specified"));
- saw_error = TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_REQD_PROPERTY_MISSING;
- }
+ check_reqd_prop(fstab.zone_fs_dir, RT_IPD, PT_DIR, &ret_val);
}
(void) zonecfg_endipdent(handle);
@@ -3267,27 +3336,11 @@ verify_func(cmd_t *cmd)
return;
}
while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
- if (strlen(fstab.zone_fs_dir) == 0) {
- zerr("%s: %s %s", rt_to_str(RT_FS), pt_to_str(PT_DIR),
- gettext("not specified"));
- saw_error = TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_REQD_PROPERTY_MISSING;
- }
- if (strlen(fstab.zone_fs_special) == 0) {
- zerr("%s: %s %s", rt_to_str(RT_FS),
- pt_to_str(PT_SPECIAL), gettext("not specified"));
- saw_error = TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_REQD_PROPERTY_MISSING;
- }
- if (strlen(fstab.zone_fs_type) == 0) {
- zerr("%s: %s %s", rt_to_str(RT_FS), pt_to_str(PT_TYPE),
- gettext("not specified"));
- saw_error = TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_REQD_PROPERTY_MISSING;
- }
+ check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val);
+ check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL,
+ &ret_val);
+ check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val);
+
zonecfg_free_fs_option_list(fstab.zone_fs_options);
}
(void) zonecfg_endfsent(handle);
@@ -3297,20 +3350,10 @@ verify_func(cmd_t *cmd)
return;
}
while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
- if (strlen(nwiftab.zone_nwif_address) == 0) {
- zerr("%s: %s %s", rt_to_str(RT_NET),
- pt_to_str(PT_ADDRESS), gettext("not specified"));
- saw_error = TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_REQD_PROPERTY_MISSING;
- }
- if (strlen(nwiftab.zone_nwif_physical) == 0) {
- zerr("%s: %s %s", rt_to_str(RT_NET),
- pt_to_str(PT_PHYSICAL), gettext("not specified"));
- saw_error = TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_REQD_PROPERTY_MISSING;
- }
+ check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
+ PT_ADDRESS, &ret_val);
+ check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET,
+ PT_PHYSICAL, &ret_val);
}
(void) zonecfg_endnwifent(handle);
@@ -3319,13 +3362,9 @@ verify_func(cmd_t *cmd)
return;
}
while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
- if (strlen(rctltab.zone_rctl_name) == 0) {
- zerr("%s: %s %s", rt_to_str(RT_RCTL),
- pt_to_str(PT_NAME), gettext("not specified"));
- saw_error = TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_REQD_PROPERTY_MISSING;
- }
+ check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME,
+ &ret_val);
+
if (rctltab.zone_rctl_valptr == NULL) {
zerr(gettext("%s: no %s specified"),
rt_to_str(RT_RCTL), pt_to_str(PT_VALUE));
@@ -3343,27 +3382,12 @@ verify_func(cmd_t *cmd)
return;
}
while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
- if (strlen(attrtab.zone_attr_name) == 0) {
- zerr("%s: %s %s", rt_to_str(RT_ATTR),
- pt_to_str(PT_NAME), gettext("not specified"));
- saw_error = TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_REQD_PROPERTY_MISSING;
- }
- if (strlen(attrtab.zone_attr_type) == 0) {
- zerr("%s: %s %s", rt_to_str(RT_ATTR),
- pt_to_str(PT_TYPE), gettext("not specified"));
- saw_error = TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_REQD_PROPERTY_MISSING;
- }
- if (strlen(attrtab.zone_attr_value) == 0) {
- zerr("%s: %s %s", rt_to_str(RT_ATTR),
- pt_to_str(PT_VALUE), gettext("not specified"));
- saw_error = TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_REQD_PROPERTY_MISSING;
- }
+ check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME,
+ &ret_val);
+ check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE,
+ &ret_val);
+ check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE,
+ &ret_val);
}
(void) zonecfg_endattrent(handle);
@@ -3375,10 +3399,15 @@ verify_func(cmd_t *cmd)
}
if (save) {
- if (ret_val == Z_OK)
- ret_val = save_it(zonepath);
- else
- zerr("zone %s %s", zone, gettext("failed to verify"));
+ if (ret_val == Z_OK) {
+ if ((ret_val = zonecfg_save(handle)) == Z_OK) {
+ need_to_commit = FALSE;
+ (void) strlcpy(revert_zone, zone,
+ sizeof (revert_zone));
+ }
+ } else {
+ zerr(gettext("Zone %s failed to verify"), zone);
+ }
}
if (ret_val != Z_OK)
zone_perror(zone, ret_val, TRUE);
@@ -3486,6 +3515,21 @@ validate_attr_type_val(struct zone_attrtab *attrtab)
return (Z_ERR);
}
+/*
+ * Helper function for end_func-- checks the existence of a given property
+ * and emits a message if not specified.
+ */
+static int
+end_check_reqd(char *attr, int pt, bool *validation_failed)
+{
+ if (strlen(attr) == 0) {
+ *validation_failed = TRUE;
+ zerr(gettext("%s not specified"), pt_to_str(pt));
+ return (Z_ERR);
+ }
+ return (Z_OK);
+}
+
void
end_func(cmd_t *cmd)
{
@@ -3525,36 +3569,35 @@ end_func(cmd_t *cmd)
switch (resource_scope) {
case RT_FS:
/* First make sure everything was filled in. */
- if (strlen(in_progress_fstab.zone_fs_dir) == 0) {
- zerr("dir %s", gettext("not specified"));
- saw_error = TRUE;
- validation_failed = TRUE;
- } else if (in_progress_fstab.zone_fs_dir[0] != '/') {
- zerr("dir %s %s", in_progress_fstab.zone_fs_dir,
- gettext("is not an absolute path."));
- saw_error = TRUE;
- validation_failed = TRUE;
- }
- if (strlen(in_progress_fstab.zone_fs_special) == 0) {
- zerr("special %s", gettext("not specified"));
- saw_error = TRUE;
- validation_failed = TRUE;
+ if (end_check_reqd(in_progress_fstab.zone_fs_dir,
+ PT_DIR, &validation_failed) == Z_OK) {
+ if (in_progress_fstab.zone_fs_dir[0] != '/') {
+ zerr(gettext("%s %s is not an absolute path."),
+ pt_to_str(PT_DIR),
+ in_progress_fstab.zone_fs_dir);
+ validation_failed = TRUE;
+ }
}
+
+ (void) end_check_reqd(in_progress_fstab.zone_fs_special,
+ PT_SPECIAL, &validation_failed);
+
if (in_progress_fstab.zone_fs_raw[0] != '\0' &&
in_progress_fstab.zone_fs_raw[0] != '/') {
- zerr("raw device %s %s",
- in_progress_fstab.zone_fs_raw,
- gettext("is not an absolute path."));
- saw_error = TRUE;
+ zerr(gettext("%s %s is not an absolute path."),
+ pt_to_str(PT_RAW),
+ in_progress_fstab.zone_fs_raw);
validation_failed = TRUE;
}
- if (strlen(in_progress_fstab.zone_fs_type) == 0) {
- zerr("type %s", gettext("not specified"));
+
+ (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE,
+ &validation_failed);
+
+ if (validation_failed) {
saw_error = TRUE;
- validation_failed = TRUE;
- }
- if (validation_failed)
return;
+ }
+
if (end_op == CMD_ADD) {
/* Make sure there isn't already one like this. */
bzero(&tmp_fstab, sizeof (tmp_fstab));
@@ -3580,20 +3623,23 @@ end_func(cmd_t *cmd)
zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
in_progress_fstab.zone_fs_options = NULL;
break;
+
case RT_IPD:
/* First make sure everything was filled in. */
- if (strlen(in_progress_ipdtab.zone_fs_dir) == 0) {
- zerr("dir %s", gettext("not specified"));
- saw_error = TRUE;
- validation_failed = TRUE;
- } else if (in_progress_ipdtab.zone_fs_dir[0] != '/') {
- zerr("dir %s %s", in_progress_ipdtab.zone_fs_dir,
- gettext("is not an absolute path."));
- saw_error = TRUE;
- validation_failed = TRUE;
+ if (end_check_reqd(in_progress_ipdtab.zone_fs_dir, PT_DIR,
+ &validation_failed) == Z_OK) {
+ if (in_progress_ipdtab.zone_fs_dir[0] != '/') {
+ zerr(gettext("%s %s is not an absolute path."),
+ pt_to_str(PT_DIR),
+ in_progress_ipdtab.zone_fs_dir);
+ validation_failed = TRUE;
+ }
}
- if (validation_failed)
+ if (validation_failed) {
+ saw_error = TRUE;
return;
+ }
+
if (end_op == CMD_ADD) {
/* Make sure there isn't already one like this. */
bzero(&tmp_fstab, sizeof (tmp_fstab));
@@ -3617,18 +3663,16 @@ end_func(cmd_t *cmd)
break;
case RT_NET:
/* First make sure everything was filled in. */
- if (strlen(in_progress_nwiftab.zone_nwif_physical) == 0) {
- zerr("physical %s", gettext("not specified"));
- saw_error = TRUE;
- validation_failed = TRUE;
- }
- if (strlen(in_progress_nwiftab.zone_nwif_address) == 0) {
- zerr("address %s", gettext("not specified"));
+ (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical,
+ PT_PHYSICAL, &validation_failed);
+ (void) end_check_reqd(in_progress_nwiftab.zone_nwif_address,
+ PT_ADDRESS, &validation_failed);
+
+ if (validation_failed) {
saw_error = TRUE;
- validation_failed = TRUE;
- }
- if (validation_failed)
return;
+ }
+
if (end_op == CMD_ADD) {
/* Make sure there isn't already one like this. */
bzero(&tmp_nwiftab, sizeof (tmp_nwiftab));
@@ -3649,15 +3693,17 @@ end_func(cmd_t *cmd)
&in_progress_nwiftab);
}
break;
+
case RT_DEVICE:
/* First make sure everything was filled in. */
- if (strlen(in_progress_devtab.zone_dev_match) == 0) {
- zerr("match %s", gettext("not specified"));
+ (void) end_check_reqd(in_progress_devtab.zone_dev_match,
+ PT_MATCH, &validation_failed);
+
+ if (validation_failed) {
saw_error = TRUE;
- validation_failed = TRUE;
- }
- if (validation_failed)
return;
+ }
+
if (end_op == CMD_ADD) {
/* Make sure there isn't already one like this. */
(void) strlcpy(tmp_devtab.zone_dev_match,
@@ -3677,20 +3723,22 @@ end_func(cmd_t *cmd)
&in_progress_devtab);
}
break;
+
case RT_RCTL:
/* First make sure everything was filled in. */
- if (strlen(in_progress_rctltab.zone_rctl_name) == 0) {
- zerr("name %s", gettext("not specified"));
- saw_error = TRUE;
- validation_failed = TRUE;
- }
+ (void) end_check_reqd(in_progress_rctltab.zone_rctl_name,
+ PT_NAME, &validation_failed);
+
if (in_progress_rctltab.zone_rctl_valptr == NULL) {
zerr(gettext("no %s specified"), pt_to_str(PT_VALUE));
- saw_error = TRUE;
validation_failed = TRUE;
}
- if (validation_failed)
+
+ if (validation_failed) {
+ saw_error = TRUE;
return;
+ }
+
if (end_op == CMD_ADD) {
/* Make sure there isn't already one like this. */
(void) strlcpy(tmp_rctltab.zone_rctl_name,
@@ -3719,34 +3767,27 @@ end_func(cmd_t *cmd)
in_progress_rctltab.zone_rctl_valptr = NULL;
}
break;
+
case RT_ATTR:
/* First make sure everything was filled in. */
- if (strlen(in_progress_attrtab.zone_attr_name) == 0) {
- zerr("name %s", gettext("not specified"));
- saw_error = TRUE;
- validation_failed = TRUE;
- }
- if (strlen(in_progress_attrtab.zone_attr_type) == 0) {
- zerr("type %s", gettext("not specified"));
- saw_error = TRUE;
- validation_failed = TRUE;
- }
- if (strlen(in_progress_attrtab.zone_attr_value) == 0) {
- zerr("value %s", gettext("not specified"));
- saw_error = TRUE;
- validation_failed = TRUE;
- }
+ (void) end_check_reqd(in_progress_attrtab.zone_attr_name,
+ PT_NAME, &validation_failed);
+ (void) end_check_reqd(in_progress_attrtab.zone_attr_type,
+ PT_TYPE, &validation_failed);
+ (void) end_check_reqd(in_progress_attrtab.zone_attr_value,
+ PT_VALUE, &validation_failed);
+
if (validate_attr_name(in_progress_attrtab.zone_attr_name) !=
- Z_OK) {
- saw_error = TRUE;
+ Z_OK)
validation_failed = TRUE;
- }
- if (validate_attr_type_val(&in_progress_attrtab) != Z_OK) {
- saw_error = TRUE;
+
+ if (validate_attr_type_val(&in_progress_attrtab) != Z_OK)
validation_failed = TRUE;
- }
- if (validation_failed)
+
+ if (validation_failed) {
+ saw_error = TRUE;
return;
+ }
if (end_op == CMD_ADD) {
/* Make sure there isn't already one like this. */
bzero(&tmp_attrtab, sizeof (tmp_attrtab));
@@ -3882,15 +3923,16 @@ revert_func(cmd_t *cmd)
zone_perror(execname, Z_NOMEM, TRUE);
exit(Z_ERR);
}
- if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) {
+ if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) {
saw_error = TRUE;
got_handle = FALSE;
if (err == Z_NO_ZONE)
zerr(gettext("%s: no such saved zone to revert to."),
- zone);
+ revert_zone);
else
zone_perror(zone, err, TRUE);
}
+ (void) strlcpy(zone, revert_zone, sizeof (zone));
}
void
@@ -4109,9 +4151,9 @@ do_interactive(void)
*/
(void) initialize(FALSE);
}
- do
+ do {
err = read_input();
- while (err == Z_REPEAT);
+ } while (err == Z_REPEAT);
return (err);
}
@@ -4231,42 +4273,6 @@ get_execbasename(char *execfullname)
return (execbasename);
}
-static void
-validate_zone_name()
-{
- regex_t reg;
- char *locale = NULL, locale_buf[MAXPATHLEN];
-
- if (strcmp(zone, GLOBAL_ZONENAME) == 0)
- goto err;
-
- /*
- * The regex(5) functions below are locale-sensitive, so save the
- * user's locale, then set it to "C" for the regex's, and restore
- * it afterwards.
- */
- if ((locale = setlocale(LC_ALL, NULL)) != NULL) {
- (void) strlcpy(locale_buf, locale, sizeof (locale_buf));
- locale = locale_buf;
- }
- (void) setlocale(LC_ALL, "C");
- if (regcomp(&reg, "^" ZONENAME_REGEXP "$", REG_EXTENDED|REG_NOSUB) != 0)
- goto err;
-
- if (regexec(&reg, zone, (size_t)0, NULL, 0) != 0)
- goto err;
-
- regfree(&reg);
- (void) setlocale(LC_ALL, locale);
- return;
-
-err:
- (void) setlocale(LC_ALL, locale);
- zone_perror(zone, Z_BOGUS_ZONE_NAME, TRUE);
- usage(FALSE, HELP_SYNTAX);
- exit(Z_USAGE);
-}
-
int
main(int argc, char *argv[])
{
@@ -4297,7 +4303,6 @@ main(int argc, char *argv[])
exit(Z_OK);
}
- zone = NULL;
while ((arg = getopt(argc, argv, "?f:z:")) != EOF) {
switch (arg) {
case '?':
@@ -4312,7 +4317,13 @@ main(int argc, char *argv[])
cmd_file_mode = TRUE;
break;
case 'z':
- zone = optarg;
+ if (zonecfg_validate_zonename(optarg) != Z_OK) {
+ zone_perror(optarg, Z_BOGUS_ZONE_NAME, TRUE);
+ usage(FALSE, HELP_SYNTAX);
+ exit(Z_USAGE);
+ }
+ (void) strlcpy(zone, optarg, sizeof (zone));
+ (void) strlcpy(revert_zone, optarg, sizeof (zone));
break;
default:
usage(FALSE, HELP_USAGE);
@@ -4320,21 +4331,24 @@ main(int argc, char *argv[])
}
}
- if (optind > argc || zone == NULL) {
+ if (optind > argc || strcmp(zone, "") == 0) {
usage(FALSE, HELP_USAGE);
exit(Z_USAGE);
}
- validate_zone_name();
- if (zonecfg_access(zone, W_OK) == Z_OK) {
+ if ((err = zonecfg_access(zone, W_OK)) == Z_OK) {
read_only_mode = FALSE;
- } else {
+ } else if (err == Z_ACCES) {
read_only_mode = TRUE;
/* skip this message in one-off from command line mode */
if (optind == argc)
(void) fprintf(stderr, gettext("WARNING: you do not "
"have write access to this zone's configuration "
"file;\ngoing into read-only mode.\n"));
+ } else {
+ fprintf(stderr, "%s: Could not access zone configuration "
+ "store: %s\n", execname, zonecfg_strerror(err));
+ exit(Z_ERR);
}
if ((handle = zonecfg_init_handle()) == NULL) {
diff --git a/usr/src/cmd/zonecfg/zonecfg.h b/usr/src/cmd/zonecfg/zonecfg.h
index 8337811ac1..e0fca7a02d 100644
--- a/usr/src/cmd/zonecfg/zonecfg.h
+++ b/usr/src/cmd/zonecfg/zonecfg.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -69,37 +69,39 @@ typedef int bool;
/* resource types: increment RT_MAX when expanding this list */
#define RT_UNKNOWN 0
-#define RT_ZONEPATH 1 /* really a property, but for info ... */
-#define RT_AUTOBOOT 2 /* really a property, but for info ... */
-#define RT_POOL 3 /* really a property, but for info ... */
-#define RT_FS 4
-#define RT_IPD 5
-#define RT_NET 6
-#define RT_DEVICE 7
-#define RT_RCTL 8
-#define RT_ATTR 9
+#define RT_ZONENAME 1 /* really a property, but for info ... */
+#define RT_ZONEPATH 2 /* really a property, but for info ... */
+#define RT_AUTOBOOT 3 /* really a property, but for info ... */
+#define RT_POOL 4 /* really a property, but for info ... */
+#define RT_FS 5
+#define RT_IPD 6
+#define RT_NET 7
+#define RT_DEVICE 8
+#define RT_RCTL 9
+#define RT_ATTR 10
#define RT_MIN RT_UNKNOWN
#define RT_MAX RT_ATTR
/* property types: increment PT_MAX when expanding this list */
#define PT_UNKNOWN 0
-#define PT_ZONEPATH 1
-#define PT_AUTOBOOT 2
-#define PT_POOL 3
-#define PT_DIR 4
-#define PT_SPECIAL 5
-#define PT_TYPE 6
-#define PT_OPTIONS 7
-#define PT_ADDRESS 8
-#define PT_PHYSICAL 9
-#define PT_NAME 10
-#define PT_VALUE 11
-#define PT_MATCH 12
-#define PT_PRIV 13
-#define PT_LIMIT 14
-#define PT_ACTION 15
-#define PT_RAW 16
+#define PT_ZONENAME 1
+#define PT_ZONEPATH 2
+#define PT_AUTOBOOT 3
+#define PT_POOL 4
+#define PT_DIR 5
+#define PT_SPECIAL 6
+#define PT_TYPE 7
+#define PT_OPTIONS 8
+#define PT_ADDRESS 9
+#define PT_PHYSICAL 10
+#define PT_NAME 11
+#define PT_VALUE 12
+#define PT_MATCH 13
+#define PT_PRIV 14
+#define PT_LIMIT 15
+#define PT_ACTION 16
+#define PT_RAW 17
#define PT_MIN PT_UNKNOWN
#define PT_MAX PT_RAW
diff --git a/usr/src/cmd/zonecfg/zonecfg_grammar.y b/usr/src/cmd/zonecfg/zonecfg_grammar.y
index 2927233b95..abca323bed 100644
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y
@@ -58,9 +58,9 @@ extern void yyerror(char *s);
%start commands
%token HELP CREATE EXPORT ADD DELETE REMOVE SELECT SET INFO CANCEL END VERIFY
-%token COMMIT REVERT EXIT SEMICOLON TOKEN ZONEPATH AUTOBOOT POOL NET FS IPD ATTR
-%token DEVICE RCTL SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL NAME
-%token MATCH PRIV LIMIT ACTION VALUE EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
+%token COMMIT REVERT EXIT SEMICOLON TOKEN ZONENAME ZONEPATH AUTOBOOT POOL NET
+%token FS IPD ATTR DEVICE RCTL SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL
+%token NAME MATCH PRIV LIMIT ACTION VALUE EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
%token OPEN_PAREN CLOSE_PAREN COMMA
%type <strval> TOKEN EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
@@ -68,7 +68,7 @@ extern void yyerror(char *s);
%type <complex> complex_piece complex_prop_val
%type <ival> resource_type NET FS IPD DEVICE RCTL ATTR
%type <ival> property_name SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL NAME
- MATCH ZONEPATH AUTOBOOT POOL VALUE PRIV LIMIT ACTION
+ MATCH ZONENAME ZONEPATH AUTOBOOT POOL VALUE PRIV LIMIT ACTION
%type <cmd> command
%type <cmd> add_command ADD
%type <cmd> cancel_command CANCEL
@@ -402,6 +402,15 @@ info_command: INFO
$$->cmd_res_type = $2;
$$->cmd_prop_nv_pairs = 0;
}
+ | INFO ZONENAME
+ {
+ if (($$ = alloc_cmd()) == NULL)
+ YYERROR;
+ cmd = $$;
+ $$->cmd_handler = &info_func;
+ $$->cmd_res_type = RT_ZONENAME;
+ $$->cmd_prop_nv_pairs = 0;
+ }
| INFO ZONEPATH
{
if (($$ = alloc_cmd()) == NULL)
@@ -665,6 +674,7 @@ property_name: SPECIAL { $$ = PT_SPECIAL; }
| DIR { $$ = PT_DIR; }
| TYPE { $$ = PT_TYPE; }
| OPTIONS { $$ = PT_OPTIONS; }
+ | ZONENAME { $$ = PT_ZONENAME; }
| ZONEPATH { $$ = PT_ZONEPATH; }
| AUTOBOOT { $$ = PT_AUTOBOOT; }
| POOL { $$ = PT_POOL; }
diff --git a/usr/src/cmd/zonecfg/zonecfg_lex.l b/usr/src/cmd/zonecfg/zonecfg_lex.l
index 1beafcd7f0..1a5de3659e 100644
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l
@@ -20,7 +20,7 @@
*
* CDDL HEADER END
*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -156,6 +156,9 @@ char *safe_strdup(char *s);
<TSTATE>attr { return ATTR; }
+<TSTATE>zonename { return ZONENAME; }
+<CSTATE>zonename { return ZONENAME; }
+
<TSTATE>zonepath { return ZONEPATH; }
<CSTATE>zonepath { return ZONEPATH; }
diff --git a/usr/src/head/libzonecfg.h b/usr/src/head/libzonecfg.h
index e5c3f9a451..dd3c1d41ef 100644
--- a/usr/src/head/libzonecfg.h
+++ b/usr/src/head/libzonecfg.h
@@ -72,9 +72,9 @@ extern "C" {
#define Z_NO_RESOURCE_ID 18 /* no/wrong resource id */
#define Z_NO_PROPERTY_TYPE 19 /* no/wrong property type */
#define Z_NO_PROPERTY_ID 20 /* no/wrong property id */
-#define Z_RESOURCE_EXISTS 21 /* resource already exists */
+#define Z_BAD_ZONE_STATE 21 /* zone state invalid for given task */
#define Z_INVALID_DOCUMENT 22 /* libxml can't validate against DTD */
-#define Z_ID_IN_USE 23 /* add_index conflict */
+#define Z_NAME_IN_USE 23 /* zone name already in use (rename) */
#define Z_NO_SUCH_ID 24 /* delete_index: no old ID */
#define Z_UPDATING_INDEX 25 /* add/modify/delete_index problem */
#define Z_LOCKING_FILE 26 /* problem locking index file */
@@ -108,6 +108,7 @@ struct zoneent {
char zone_name[ZONENAME_MAX]; /* name of the zone */
int zone_state; /* configured | incomplete | installed */
char zone_path[MAXPATHLEN];
+ char zone_newname[ZONENAME_MAX]; /* for doing renames */
};
typedef struct zone_dochandle *zone_dochandle_t; /* opaque handle */
@@ -160,9 +161,10 @@ struct zone_attrtab {
extern zone_dochandle_t zonecfg_init_handle(void);
extern int zonecfg_get_handle(char *, zone_dochandle_t);
extern int zonecfg_get_snapshot_handle(char *, zone_dochandle_t);
+extern int zonecfg_get_template_handle(char *, char *, zone_dochandle_t);
extern int zonecfg_check_handle(zone_dochandle_t);
extern void zonecfg_fini_handle(zone_dochandle_t);
-extern int zonecfg_destroy(const char *);
+extern int zonecfg_destroy(const char *, boolean_t);
extern int zonecfg_destroy_snapshot(char *);
extern int zonecfg_save(zone_dochandle_t);
extern int zonecfg_create_snapshot(char *);
@@ -172,6 +174,7 @@ extern int zonecfg_access(const char *, int);
/*
* Zone name, path to zone directory, autoboot setting and pool.
*/
+extern int zonecfg_validate_zonename(char *);
extern int zonecfg_get_name(zone_dochandle_t, char *, size_t);
extern int zonecfg_set_name(zone_dochandle_t, char *);
extern int zonecfg_get_zonepath(zone_dochandle_t, char *, size_t);
@@ -279,12 +282,6 @@ extern int zonecfg_endrctlent(zone_dochandle_t);
extern int zonecfg_get_privset(priv_set_t *);
/*
- * Index update routines.
- */
-extern int zonecfg_add_index(char *, char *);
-extern int zonecfg_delete_index(char *);
-
-/*
* Higher-level routines.
*/
extern int zone_get_rootpath(char *, char *, size_t);
diff --git a/usr/src/lib/libzonecfg/common/getzoneent.c b/usr/src/lib/libzonecfg/common/getzoneent.c
index 1ac5730c9d..4a62bddaa9 100644
--- a/usr/src/lib/libzonecfg/common/getzoneent.c
+++ b/usr/src/lib/libzonecfg/common/getzoneent.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -228,17 +228,20 @@ unlock_index_file(int lock_fd)
*
* If ze->zone_state is < 0, it means leave the
* existing value unchanged; this is only meaningful when operation ==
- * PZE_MODIFY (i.e., it's bad on PZE_ADD and a no-op on PZE_DELETE).
+ * PZE_MODIFY (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
*
- * Likewise, a zero-length ze->zone_path means leave the existing value
+ * A zero-length ze->zone_path means leave the existing value
* unchanged; this is only meaningful when operation == PZE_MODIFY
- * (i.e., it's bad on PZE_ADD and a no-op on PZE_DELETE).
+ * (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
+ *
+ * A zero-length ze->zone_newname means leave the existing name
+ * unchanged; otherwise the zone is renamed to zone_newname. This is
+ * only meaningful when operation == PZE_MODIFY.
*
* Locking and unlocking is done via the functions above.
* The file itself is not modified in place; rather, a copy is made which
* is modified, then the copy is atomically renamed back to the main file.
*/
-
int
putzoneent(struct zoneent *ze, zoneent_op_t operation)
{
@@ -254,6 +257,10 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
if (operation == PZE_ADD &&
(ze->zone_state < 0 || strlen(ze->zone_path) == 0))
return (Z_INVAL);
+
+ if (operation != PZE_MODIFY && strlen(ze->zone_newname) != 0)
+ return (Z_INVAL);
+
if ((err = lock_index_file(&lock_fd)) != Z_OK)
return (err);
tmp_file_name = strdup(_PATH_TMPFILE);
@@ -331,6 +338,7 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
goto error;
} else if (operation == PZE_MODIFY) {
char tmp_state[ZONE_STATE_MAXSTRLEN + 1];
+ char *tmp_name;
if (ze->zone_state >= 0 &&
strlen(ze->zone_path) > 0) {
@@ -351,12 +359,21 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
p = gettok(&cp);
+ /*
+ * If a new name is supplied, use it.
+ */
+ if (strlen(ze->zone_newname) != 0)
+ tmp_name = ze->zone_newname;
+ else
+ tmp_name = ze->zone_name;
+
(void) fprintf(tmp_file, "%s:%s:%s%s%s\n",
- ze->zone_name, tmp_state,
+ tmp_name, tmp_state,
need_quotes ? "\"" : "",
(strlen(ze->zone_path) == 0) ? p :
ze->zone_path, need_quotes ? "\"" : "");
}
+ /* else if (operation == PZE_REMOVE) { no-op } */
} else {
(void) fputs(orig_buf, tmp_file);
}
diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c
index 87d2e45c52..b9d80dbefa 100644
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c
@@ -38,6 +38,7 @@
#include <ctype.h>
#include <sys/mntio.h>
#include <sys/mnttab.h>
+#include <sys/types.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -99,6 +100,9 @@ struct zone_dochandle {
xmlDocPtr zone_dh_doc;
xmlNodePtr zone_dh_cur;
xmlNodePtr zone_dh_top;
+ boolean_t zone_dh_newzone;
+ boolean_t zone_dh_snapshot;
+ char zone_dh_delete_name[ZONENAME_MAX];
};
/*
@@ -140,14 +144,11 @@ zonecfg_error_func(void *ctx, const char *msg, ...)
zone_dochandle_t
zonecfg_init_handle(void)
{
- zone_dochandle_t handle = malloc(sizeof (struct zone_dochandle));
+ zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
if (handle == NULL) {
errno = Z_NOMEM;
return (NULL);
}
- handle->zone_dh_doc = NULL;
- handle->zone_dh_cur = NULL;
- handle->zone_dh_top = NULL;
/* generic libxml initialization */
xmlLineNumbersDefault(1);
@@ -191,12 +192,62 @@ zonecfg_destroy_impl(char *filename)
}
int
-zonecfg_destroy(const char *zonename)
+zonecfg_destroy(const char *zonename, boolean_t force)
{
char path[MAXPATHLEN];
+ struct zoneent ze;
+ int err, state_err;
+ zone_state_t state;
config_file_path(zonename, path);
- return (zonecfg_destroy_impl(path));
+
+ state_err = zone_get_state((char *)zonename, &state);
+ err = access(path, W_OK);
+
+ /*
+ * If there is no file, and no index entry, reliably indicate that no
+ * such zone exists.
+ */
+ if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
+ return (Z_NO_ZONE);
+
+ /*
+ * Handle any other filesystem related errors (except if the XML
+ * file is missing, which we treat silently), unless we're forcing,
+ * in which case we plow on.
+ */
+ if (err == -1 && errno != ENOENT) {
+ if (errno == EACCES)
+ return (Z_ACCES);
+ else if (!force)
+ return (Z_MISC_FS);
+ }
+
+ if (state > ZONE_STATE_INSTALLED)
+ return (Z_BAD_ZONE_STATE);
+
+ if (!force && state > ZONE_STATE_CONFIGURED)
+ return (Z_BAD_ZONE_STATE);
+
+ /*
+ * Index deletion succeeds even if the entry doesn't exist. So this
+ * will fail only if we've had some more severe problem.
+ */
+ bzero(&ze, sizeof (ze));
+ (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
+ if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
+ if (!force)
+ return (err);
+
+ err = zonecfg_destroy_impl(path);
+
+ /*
+ * Treat failure to find the XML file silently, since, well, it's
+ * gone, and with the index file cleaned up, we're done.
+ */
+ if (err == Z_OK || err == Z_NO_ZONE)
+ return (Z_OK);
+ return (err);
}
int
@@ -277,12 +328,39 @@ setrootattr(zone_dochandle_t handle, const xmlChar *propname, char *propval)
return (Z_OK);
}
+static void
+addcomment(zone_dochandle_t handle, const char *comment)
+{
+ xmlNodePtr node;
+ node = xmlNewComment((xmlChar *) comment);
+
+ if (node != NULL)
+ (void) xmlAddPrevSibling(handle->zone_dh_top, node);
+}
+
+static void
+stripcomments(zone_dochandle_t handle)
+{
+ xmlDocPtr top;
+ xmlNodePtr child, next;
+
+ top = handle->zone_dh_doc;
+ for (child = top->xmlChildrenNode; child != NULL; child = next) {
+ next = child->next;
+ if (child->name == NULL)
+ continue;
+ if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
+ next = child->next;
+ xmlUnlinkNode(child);
+ xmlFreeNode(child);
+ }
+ }
+}
+
static int
zonecfg_get_handle_impl(char *zonename, char *filename, zone_dochandle_t handle)
{
xmlValidCtxtPtr cvp;
- xmlDocPtr top;
- xmlNodePtr child, next;
struct stat statbuf;
int valid;
@@ -302,18 +380,9 @@ zonecfg_get_handle_impl(char *zonename, char *filename, zone_dochandle_t handle)
xmlFreeValidCtxt(cvp);
if (valid == 0)
return (Z_INVALID_DOCUMENT);
+
/* delete any comments such as inherited Sun copyright / ident str */
- top = handle->zone_dh_doc;
- for (child = top->xmlChildrenNode; child != NULL; child = next) {
- next = child->next;
- if (child->name == NULL)
- continue;
- if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
- next = child->next;
- xmlUnlinkNode(child);
- xmlFreeNode(child);
- }
- }
+ stripcomments(handle);
return (Z_OK);
}
@@ -323,6 +392,8 @@ zonecfg_get_handle(char *zonename, zone_dochandle_t handle)
char path[MAXPATHLEN];
config_file_path(zonename, path);
+ handle->zone_dh_newzone = B_FALSE;
+
return (zonecfg_get_handle_impl(zonename, path, handle));
}
@@ -332,10 +403,84 @@ zonecfg_get_snapshot_handle(char *zonename, zone_dochandle_t handle)
char path[MAXPATHLEN];
snap_file_path(zonename, path);
+ handle->zone_dh_newzone = B_FALSE;
return (zonecfg_get_handle_impl(zonename, path, handle));
}
int
+zonecfg_get_template_handle(char *template, char *zonename,
+ zone_dochandle_t handle)
+{
+ char path[MAXPATHLEN];
+ int err;
+
+ config_file_path(template, path);
+
+ if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
+ return (err);
+ handle->zone_dh_newzone = B_TRUE;
+ return (setrootattr(handle, DTD_ATTR_NAME, zonename));
+}
+
+static boolean_t
+is_renaming(zone_dochandle_t handle)
+{
+ if (handle->zone_dh_newzone)
+ return (B_FALSE);
+ if (strlen(handle->zone_dh_delete_name) > 0)
+ return (B_TRUE);
+ return (B_FALSE);
+}
+
+static boolean_t
+is_new(zone_dochandle_t handle)
+{
+ return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
+}
+
+static boolean_t
+is_snapshot(zone_dochandle_t handle)
+{
+ return (handle->zone_dh_snapshot);
+}
+
+/*
+ * It would be great to be able to use libc's ctype(3c) macros, but we
+ * can't, as they are locale sensitive, and it would break our limited thread
+ * safety if this routine had to change the app locale on the fly.
+ */
+int
+zonecfg_validate_zonename(char *zone)
+{
+ int i;
+
+ if (strcmp(zone, GLOBAL_ZONENAME) == 0)
+ return (Z_BOGUS_ZONE_NAME);
+
+ if (strlen(zone) >= ZONENAME_MAX)
+ return (Z_BOGUS_ZONE_NAME);
+
+ if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
+ (zone[0] >= 'A' && zone[0] <= 'Z') ||
+ (zone[0] >= '0' && zone[0] <= '9')))
+ return (Z_BOGUS_ZONE_NAME);
+
+ for (i = 1; zone[i] != '\0'; i++) {
+ if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
+ (zone[i] >= 'A' && zone[i] <= 'Z') ||
+ (zone[i] >= '0' && zone[i] <= '9') ||
+ (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
+ return (Z_BOGUS_ZONE_NAME);
+ }
+
+ return (Z_OK);
+}
+
+/*
+ * Changing the zone name requires us to track both the old and new
+ * name of the zone until commit time.
+ */
+int
zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
{
return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
@@ -344,7 +489,85 @@ zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
int
zonecfg_set_name(zone_dochandle_t handle, char *name)
{
- return (setrootattr(handle, DTD_ATTR_NAME, name));
+ zone_state_t state;
+ char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
+ int err;
+
+ if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
+ sizeof (curname))) != Z_OK)
+ return (err);
+
+ if (strcmp(name, curname) == 0)
+ return (Z_OK);
+
+ /*
+ * Switching zone names to one beginning with SUNW is not permitted.
+ */
+ if (strncmp(name, "SUNW", 4) == 0)
+ return (Z_BOGUS_ZONE_NAME);
+
+ if ((err = zonecfg_validate_zonename(name)) != Z_OK)
+ return (err);
+
+ /*
+ * Setting the name back to the original name (effectively a revert of
+ * the name) is fine. But if we carry on, we'll falsely identify the
+ * name as "in use," so special case here.
+ */
+ if (strcmp(name, handle->zone_dh_delete_name) == 0) {
+ err = setrootattr(handle, DTD_ATTR_NAME, name);
+ handle->zone_dh_delete_name[0] = '\0';
+ return (err);
+ }
+
+ /* Check to see if new name chosen is already in use */
+ if (zone_get_state(name, &state) != Z_NO_ZONE)
+ return (Z_NAME_IN_USE);
+
+ /*
+ * If this isn't already "new" or in a renaming transition, then
+ * we're initiating a rename here; so stash the "delete name"
+ * (i.e. the name of the zone we'll be removing) for the rename.
+ */
+ (void) strlcpy(old_delname, handle->zone_dh_delete_name,
+ sizeof (old_delname));
+ if (!is_new(handle) && !is_renaming(handle)) {
+ /*
+ * Name change is allowed only when the zone we're altering
+ * is not ready or running.
+ */
+ err = zone_get_state(curname, &state);
+ if (err == Z_OK) {
+ if (state > ZONE_STATE_INSTALLED)
+ return (Z_BAD_ZONE_STATE);
+ } else if (err != Z_NO_ZONE) {
+ return (err);
+ }
+
+ (void) strlcpy(handle->zone_dh_delete_name, curname,
+ sizeof (handle->zone_dh_delete_name));
+ assert(is_renaming(handle));
+ } else if (is_renaming(handle)) {
+ err = zone_get_state(handle->zone_dh_delete_name, &state);
+ if (err == Z_OK) {
+ if (state > ZONE_STATE_INSTALLED)
+ return (Z_BAD_ZONE_STATE);
+ } else if (err != Z_NO_ZONE) {
+ return (err);
+ }
+ }
+
+ if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
+ /*
+ * Restore the deletename to whatever it was at the
+ * top of the routine, since we've had a failure.
+ */
+ (void) strlcpy(handle->zone_dh_delete_name, old_delname,
+ sizeof (handle->zone_dh_delete_name));
+ return (err);
+ }
+
+ return (Z_OK);
}
int
@@ -402,6 +625,11 @@ zonecfg_set_pool(zone_dochandle_t handle, char *pool)
* in the <zonename>.xml file: the path to the zone. This is for performance,
* since we need to walk all zonepath's in order to be able to detect conflicts
* (see crosscheck_zonepaths() in the zoneadm command).
+ *
+ * An additional complexity is that when doing a rename, we'd like the entire
+ * index update operation (rename, and potential state changes) to be atomic.
+ * In general, the operation of this function should succeed or fail as
+ * a unit.
*/
int
zonecfg_refresh_index_file(zone_dochandle_t handle)
@@ -409,25 +637,94 @@ zonecfg_refresh_index_file(zone_dochandle_t handle)
char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
struct zoneent ze;
int err;
+ int opcode;
+ char *zn;
+
+ bzero(&ze, sizeof (ze));
+ ze.zone_state = -1; /* Preserve existing state in index */
if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
return (err);
+ (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
+
if ((err = zonecfg_get_zonepath(handle, zonepath,
sizeof (zonepath))) != Z_OK)
return (err);
- (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
- ze.zone_state = -1;
(void) strlcpy(ze.zone_path, zonepath, sizeof (ze.zone_path));
- return (putzoneent(&ze, PZE_MODIFY));
+
+ if (is_renaming(handle)) {
+ opcode = PZE_MODIFY;
+ (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
+ sizeof (ze.zone_name));
+ (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
+ } else if (is_new(handle)) {
+ FILE *cookie;
+ /*
+ * Be tolerant of the zone already existing in the index file,
+ * since we might be forcibly overwriting an existing
+ * configuration with a new one (for example 'create -F'
+ * in zonecfg).
+ */
+ opcode = PZE_ADD;
+ cookie = setzoneent();
+ while ((zn = getzoneent(cookie)) != NULL) {
+ if (strcmp(zn, name) == 0) {
+ opcode = PZE_MODIFY;
+ free(zn);
+ break;
+ }
+ free(zn);
+ }
+ endzoneent(cookie);
+ ze.zone_state = ZONE_STATE_CONFIGURED;
+ } else {
+ opcode = PZE_MODIFY;
+ }
+
+ if ((err = putzoneent(&ze, opcode)) != Z_OK)
+ return (err);
+
+ return (Z_OK);
}
+/*
+ * The goal of this routine is to cause the index file update and the
+ * document save to happen as an atomic operation. We do the document
+ * first, saving a backup copy using a hard link; if that succeeds, we go
+ * on to the index. If that fails, we roll the document back into place.
+ *
+ * Strategy:
+ *
+ * New zone 'foo' configuration:
+ * Create tmpfile (zonecfg.xxxxxx)
+ * Write XML to tmpfile
+ * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
+ * Add entry to index file
+ * If it fails, delete foo.xml, leaving nothing behind.
+ *
+ * Save existing zone 'foo':
+ * Make backup of foo.xml -> .backup
+ * Create tmpfile (zonecfg.xxxxxx)
+ * Write XML to tmpfile
+ * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
+ * Modify index file as needed
+ * If it fails, recover from .backup -> foo.xml
+ *
+ * Rename 'foo' to 'bar':
+ * Create tmpfile (zonecfg.xxxxxx)
+ * Write XML to tmpfile
+ * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
+ * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
+ * If it fails, delete bar.xml; foo.xml is left behind.
+ */
static int
zonecfg_save_impl(zone_dochandle_t handle, char *filename)
{
char tmpfile[MAXPATHLEN];
- int tmpfd;
+ char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
+ int tmpfd, err;
xmlValidCtxt cvp = { NULL };
- xmlNodePtr comment;
+ boolean_t backup;
(void) strlcpy(tmpfile, filename, sizeof (tmpfile));
(void) dirname(tmpfile);
@@ -443,28 +740,82 @@ zonecfg_save_impl(zone_dochandle_t handle, char *filename)
cvp.error = zonecfg_error_func;
cvp.warning = zonecfg_error_func;
- if ((comment = xmlNewComment((xmlChar *) "\n DO NOT EDIT THIS "
- "FILE. Use zonecfg(1M) instead.\n")) == NULL)
- goto err;
- if (xmlAddPrevSibling(handle->zone_dh_top, comment) == 0)
- goto err;
-
- if (xmlValidateDocument(&cvp, handle->zone_dh_doc) == 0)
- goto err;
+ /*
+ * We do a final validation of the document-- but the library has
+ * malfunctioned if it fails to validate, so it's an assert.
+ */
+ assert(xmlValidateDocument(&cvp, handle->zone_dh_doc) != 0);
if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
goto err;
+
(void) chmod(tmpfile, 0644);
+ /*
+ * In the event we are doing a standard save, hard link a copy of the
+ * original file in .backup.<pid>.filename so we can restore it if
+ * something goes wrong.
+ */
+ if (!is_new(handle) && !is_renaming(handle)) {
+ backup = B_TRUE;
+
+ (void) strlcpy(bakdir, filename, sizeof (bakdir));
+ (void) strlcpy(bakbase, filename, sizeof (bakbase));
+ (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
+ dirname(bakdir), getpid(), basename(bakbase));
+
+ if (link(filename, bakfile) == -1) {
+ err = errno;
+ (void) unlink(tmpfile);
+ if (errno == EACCES)
+ return (Z_ACCES);
+ return (Z_MISC_FS);
+ }
+ }
+
+ /*
+ * Move the new document over top of the old.
+ * i.e.: zonecfg.XXXXXX -> myzone.xml
+ */
if (rename(tmpfile, filename) == -1) {
+ err = errno;
(void) unlink(tmpfile);
- if (errno == EACCES)
+ if (backup)
+ (void) unlink(bakfile);
+ if (err == EACCES)
return (Z_ACCES);
return (Z_MISC_FS);
}
- /* now update the cached copy of the zone path in the index file */
- return (zonecfg_refresh_index_file(handle));
+ /*
+ * If this is a snapshot, we're done-- don't add an index entry.
+ */
+ if (is_snapshot(handle))
+ return (Z_OK);
+
+ /* now update the index file to reflect whatever we just did */
+ if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
+ if (backup) {
+ /*
+ * Try to restore from our backup.
+ */
+ (void) unlink(filename);
+ (void) rename(bakfile, filename);
+ } else {
+ /*
+ * Either the zone is new, in which case we can delete
+ * new.xml, or we're doing a rename, so ditto.
+ */
+ assert(is_new(handle) || is_renaming(handle));
+ (void) unlink(filename);
+ }
+ return (Z_UPDATING_INDEX);
+ }
+
+ if (backup)
+ (void) unlink(bakfile);
+
+ return (Z_OK);
err:
(void) unlink(tmpfile);
@@ -474,14 +825,43 @@ err:
int
zonecfg_save(zone_dochandle_t handle)
{
- char zname[MAXPATHLEN], path[MAXPATHLEN];
- int err;
+ char zname[ZONENAME_MAX], path[MAXPATHLEN];
+ char delpath[MAXPATHLEN];
+ int err = Z_SAVING_FILE;
+
+ if (zonecfg_check_handle(handle) != Z_OK)
+ return (Z_BAD_HANDLE);
- if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) {
+ /*
+ * We don't support saving snapshots at this time.
+ */
+ if (handle->zone_dh_snapshot)
+ return (Z_INVAL);
+
+ if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
return (err);
- }
+
config_file_path(zname, path);
- return (zonecfg_save_impl(handle, path));
+
+ addcomment(handle, "\n DO NOT EDIT THIS "
+ "FILE. Use zonecfg(1M) instead.\n");
+
+ err = zonecfg_save_impl(handle, path);
+
+ stripcomments(handle);
+
+ if (err != Z_OK)
+ return (err);
+
+ handle->zone_dh_newzone = B_FALSE;
+
+ if (is_renaming(handle)) {
+ config_file_path(handle->zone_dh_delete_name, delpath);
+ (void) unlink(delpath);
+ handle->zone_dh_delete_name[0] = '\0';
+ }
+
+ return (Z_OK);
}
/*
@@ -519,6 +899,9 @@ zonecfg_create_snapshot(char *zonename)
return (Z_NOMEM);
}
+ handle->zone_dh_newzone = B_TRUE;
+ handle->zone_dh_snapshot = B_TRUE;
+
if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
goto out;
if ((error = operation_prep(handle)) != Z_OK)
@@ -548,8 +931,14 @@ zonecfg_create_snapshot(char *zonename)
}
snap_file_path(zonename, path);
+
+ addcomment(handle, "\n DO NOT EDIT THIS FILE. "
+ "It is a snapshot of running zone state.\n");
+
error = zonecfg_save_impl(handle, path);
+ stripcomments(handle);
+
out:
zonecfg_fini_handle(handle);
return (error);
@@ -2142,13 +2531,13 @@ zonecfg_strerror(int errnum)
return (dgettext(TEXT_DOMAIN, "No such property type"));
case Z_NO_PROPERTY_ID:
return (dgettext(TEXT_DOMAIN, "No such property with that id"));
- case Z_RESOURCE_EXISTS:
+ case Z_BAD_ZONE_STATE:
return (dgettext(TEXT_DOMAIN,
- "Resource already exists with that id"));
+ "Zone state is invalid for the requested operation"));
case Z_INVALID_DOCUMENT:
return (dgettext(TEXT_DOMAIN, "Invalid document"));
- case Z_ID_IN_USE:
- return (dgettext(TEXT_DOMAIN, "Zone ID in use"));
+ case Z_NAME_IN_USE:
+ return (dgettext(TEXT_DOMAIN, "Zone name already in use"));
case Z_NO_SUCH_ID:
return (dgettext(TEXT_DOMAIN, "No such zone ID"));
case Z_UPDATING_INDEX:
@@ -2578,26 +2967,6 @@ zonecfg_get_privset(priv_set_t *privs)
}
int
-zonecfg_add_index(char *zone, char *path)
-{
- struct zoneent ze;
-
- (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
- ze.zone_state = ZONE_STATE_CONFIGURED;
- (void) strlcpy(ze.zone_path, path, sizeof (ze.zone_path));
- return (putzoneent(&ze, PZE_ADD));
-}
-
-int
-zonecfg_delete_index(char *zone)
-{
- struct zoneent ze;
-
- (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
- return (putzoneent(&ze, PZE_REMOVE));
-}
-
-int
zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
{
zone_dochandle_t handle;
@@ -2733,6 +3102,7 @@ zone_set_state(char *zone, zone_state_t state)
state != ZONE_STATE_INCOMPLETE)
return (Z_INVAL);
+ bzero(&ze, sizeof (ze));
(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
ze.zone_state = state;
(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
diff --git a/usr/src/lib/libzonecfg/spec/libzonecfg.spec b/usr/src/lib/libzonecfg/spec/libzonecfg.spec
index 7c7c1a456a..3d3a84a12f 100644
--- a/usr/src/lib/libzonecfg/spec/libzonecfg.spec
+++ b/usr/src/lib/libzonecfg/spec/libzonecfg.spec
@@ -44,6 +44,12 @@ declaration int zonecfg_get_snapshot_handle(char *, zone_dochandle_t)
version SUNWprivate_1.1
end
+function zonecfg_get_template_handle
+include <libzonecfg.h>
+declaration int zonecfg_get_template_handle(char *, char *, zone_dochandle_t)
+version SUNWprivate_1.1
+end
+
function zonecfg_check_handle
include <libzonecfg.h>
declaration int zonecfg_check_handle(zone_dochandle_t)
@@ -68,6 +74,12 @@ declaration int zonecfg_set_name(zone_dochandle_t, char *)
version SUNWprivate_1.1
end
+function zonecfg_validate_zonename
+include <libzonecfg.h>
+declaration int zonecfg_validate_zonename(char *)
+version SUNWprivate_1.1
+end
+
function zonecfg_get_zonepath
include <libzonecfg.h>
declaration int zonecfg_get_zonepath(zone_dochandle_t, char *, size_t)
@@ -430,7 +442,7 @@ end
function zonecfg_destroy
include <libzonecfg.h>
-declaration int zonecfg_destroy(const char *)
+declaration int zonecfg_destroy(const char *, boolean_t)
version SUNWprivate_1.1
end
@@ -495,18 +507,6 @@ declaration void putzoneent(struct zoneent *, int)
version SUNWprivate_1.1
end
-function zonecfg_add_index
-include <libzonecfg.h>
-declaration int zonecfg_add_index(char *, char *)
-version SUNWprivate_1.1
-end
-
-function zonecfg_delete_index
-include <libzonecfg.h>
-declaration int zonecfg_delete_index(char *)
-version SUNWprivate_1.1
-end
-
function zone_get_id
include <libzonecfg.h>
declaration int zone_get_id(const char *, zoneid_t *);