summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2016-12-09 13:30:42 -0600
committerDavid Teigland <teigland@redhat.com>2017-01-04 12:16:49 -0600
commitc87d9704f805b1b792ae24a5c8345e550db2af2c (patch)
tree9ea65c145f2a46767f62be74357c95c7b21de98f
parentf30977d4bf8100d1d4195ece3a56074ff0526689 (diff)
downloadlvm2-c87d9704f805b1b792ae24a5c8345e550db2af2c.tar.gz
toollib: find VG name in option values when needed
-rw-r--r--tools/commands.h2
-rw-r--r--tools/lvconvert.c2
-rw-r--r--tools/toollib.c158
-rw-r--r--tools/tools.h2
4 files changed, 162 insertions, 2 deletions
diff --git a/tools/commands.h b/tools/commands.h
index c66320794..4739479dd 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -47,7 +47,7 @@ xx(lvchange,
xx(lvconvert,
"Change logical volume layout",
- 0)
+ GET_VGNAME_FROM_OPTIONS)
xx(lvcreate,
"Create a logical volume",
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index e2754e4dc..35d19d81c 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -5378,6 +5378,8 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv)
};
struct processing_handle *handle = init_processing_handle(cmd, NULL);
+ cmd->command->flags &= ~GET_VGNAME_FROM_OPTIONS;
+
if (!handle) {
log_error("Failed to initialize processing handle.");
return ECMD_FAILED;
diff --git a/tools/toollib.c b/tools/toollib.c
index 76650dea1..ada8ef988 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -3364,6 +3364,157 @@ static int _get_arg_lvnames(struct cmd_context *cmd,
return ret_max;
}
+/*
+ * This is a non-standard way of finding vgname/lvname to process. It exists
+ * because an earlier form of lvconvert did not follow the standard form, and
+ * came up with its own inconsistent approach.
+ *
+ * In this case, when the position arg is a single name, it is treated as an LV
+ * name (not a VG name). This leaves the VG unknown. So, other option values
+ * must be searched for a VG name. If one of those option values contains a
+ * vgname/lvname value, then the VG name is extracted and used for the LV
+ * position arg.
+ *
+ * Other option values that are searched for a VG name are:
+ * --thinpool, --cachepool.
+ *
+ * . command vg/lv1
+ * . add vg to arg_vgnames
+ * . add vg/lv1 to arg_lvnames
+ *
+ * command lv1
+ * . error: no vg name
+ *
+ * command --option vg/lv1 vg/lv2
+ * . verify both vg names match
+ * . add vg to arg_vgnames
+ * . add vg/lv2 to arg_lvnames
+ *
+ * command --option lv1 lv2
+ * . error: no vg name
+ *
+ * command --option vg/lv1 lv2
+ * . add vg to arg_vgnames
+ * . add vg/lv2 to arg_lvnames
+ *
+ * command --option lv1 vg/lv2
+ * . add vg to arg_vgnames
+ * . add vg/lv2 to arg_lvnames
+ */
+
+static int _get_arg_lvnames_using_options(struct cmd_context *cmd,
+ int argc, char **argv,
+ struct dm_list *arg_vgnames,
+ struct dm_list *arg_lvnames,
+ struct dm_list *arg_tags)
+{
+ const char *pos_name = NULL;
+ const char *arg_name = NULL;
+ const char *pos_vgname = NULL;
+ const char *opt_vgname = NULL;
+ const char *pos_lvname = NULL;
+ const char *use_vgname = NULL;
+ char *tmp_name;
+ char *split;
+ char *vglv;
+ size_t vglv_sz;
+
+ if (argc != 1) {
+ log_error("One LV position arg is required.");
+ return ECMD_FAILED;
+ }
+
+ if (!(pos_name = dm_pool_strdup(cmd->mem, argv[0]))) {
+ log_error("string alloc failed.");
+ return ECMD_FAILED;
+ }
+
+ if (*pos_name == '@') {
+ if (!validate_tag(pos_name + 1)) {
+ log_error("Skipping invalid tag %s.", pos_name);
+ return ECMD_FAILED;
+ }
+ if (!str_list_add(cmd->mem, arg_tags,
+ dm_pool_strdup(cmd->mem, pos_name + 1))) {
+ log_error("strlist allocation failed.");
+ return ECMD_FAILED;
+ }
+ return ECMD_PROCESSED;
+ }
+
+ if ((split = strchr(pos_name, '/'))) {
+ pos_vgname = pos_name;
+ pos_lvname = split + 1;
+ *split = '\0';
+ } else {
+ pos_lvname = pos_name;
+ pos_vgname = NULL;
+ }
+
+ if (arg_is_set(cmd, thinpool_ARG))
+ arg_name = arg_str_value(cmd, thinpool_ARG, NULL);
+ else if (arg_is_set(cmd, cachepool_ARG))
+ arg_name = arg_str_value(cmd, cachepool_ARG, NULL);
+
+ if (!pos_vgname && !arg_name) {
+ log_error("Cannot find VG name for LV %s.", pos_lvname);
+ return ECMD_FAILED;
+ }
+
+ if (arg_name && (split = strchr(arg_name, '/'))) {
+ /* combined VG/LV */
+
+ if (!(tmp_name = dm_pool_strdup(cmd->mem, arg_name))) {
+ log_error("string alloc failed.");
+ return ECMD_FAILED;
+ }
+
+ if (!(split = strchr(tmp_name, '/')))
+ return ECMD_FAILED;
+
+ opt_vgname = tmp_name;
+ /* Don't care about opt lvname. */
+ /* opt_lvname = split + 1; */
+ *split = '\0';
+ } else {
+ /* Don't care about opt lvname. */
+ /* opt_lvname = arg_name; */
+ opt_vgname = NULL;
+ }
+
+ if (!pos_vgname && !opt_vgname) {
+ log_error("Cannot find VG name for LV %s.", pos_lvname);
+ return ECMD_FAILED;
+ }
+
+ if (pos_vgname && opt_vgname && strcmp(pos_vgname, opt_vgname)) {
+ log_error("VG name mismatch from position arg (%s) and option arg (%s).",
+ pos_vgname, opt_vgname);
+ return ECMD_FAILED;
+ }
+
+ use_vgname = pos_vgname ? pos_vgname : opt_vgname;
+
+ if (!str_list_add(cmd->mem, arg_vgnames, dm_pool_strdup(cmd->mem, use_vgname))) {
+ log_error("strlist allocation failed.");
+ return ECMD_FAILED;
+ }
+
+ vglv_sz = strlen(use_vgname) + strlen(pos_lvname) + 2;
+
+ if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) ||
+ dm_snprintf(vglv, vglv_sz, "%s/%s", use_vgname, pos_lvname) < 0) {
+ log_error("vg/lv string alloc failed.");
+ return ECMD_FAILED;
+ }
+ if (!str_list_add(cmd->mem, arg_lvnames, vglv)) {
+ log_error("strlist allocation failed.");
+ return ECMD_FAILED;
+ }
+
+ return ECMD_PROCESSED;
+}
+
static int _process_lv_vgnameid_list(struct cmd_context *cmd, uint32_t read_flags,
struct dm_list *vgnameids_to_process,
struct dm_list *arg_vgnames,
@@ -3523,7 +3674,12 @@ int process_each_lv(struct cmd_context *cmd,
/*
* Find any LVs, VGs or tags explicitly provided on the command line.
*/
- if ((ret = _get_arg_lvnames(cmd, argc, argv, one_vgname, one_lvname, &arg_vgnames, &arg_lvnames, &arg_tags) != ECMD_PROCESSED)) {
+ if (cmd->command->flags & GET_VGNAME_FROM_OPTIONS)
+ ret = _get_arg_lvnames_using_options(cmd, argc, argv, &arg_vgnames, &arg_lvnames, &arg_tags);
+ else
+ ret = _get_arg_lvnames(cmd, argc, argv, one_vgname, one_lvname, &arg_vgnames, &arg_lvnames, &arg_tags);
+
+ if (ret != ECMD_PROCESSED) {
ret_max = ret;
goto_out;
}
diff --git a/tools/tools.h b/tools/tools.h
index f31057080..2deded903 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -162,6 +162,8 @@ struct lv_types {
#define ENABLE_DUPLICATE_DEVS 0x00000400
/* Command does not accept tags as args. */
#define DISALLOW_TAG_ARGS 0x00000800
+/* Command may need to find VG name in an option value. */
+#define GET_VGNAME_FROM_OPTIONS 0x00001000
void usage(const char *name);