summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2016-12-09 13:30:42 -0600
committerDavid Teigland <teigland@redhat.com>2016-12-14 11:30:24 -0600
commit2c85362c911f9202e2816cd2a9c42ed427e63d1e (patch)
tree6753e31484c4d7ad95661bf1bb33af5895b8058e
parenta2b3b88e633dad25848464b1b4041486f90d2e9f (diff)
downloadlvm2-2c85362c911f9202e2816cd2a9c42ed427e63d1e.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 0dfcb4b95..b013f6f0f 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -5134,6 +5134,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 cdf1faaea..d07ac5eb4 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 f9979aa75..6da772e52 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);