master - ccmd: split into multiple files
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=15d9f2850e60a4...
Commit: 15d9f2850e60a44cfc55d48ce108b4a82aecd9ae
Parent: 013c080756dcc2faaecc80b489d85d7ab1384cbf
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jan 12 14:44:58 2017 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Feb 13 08:20:10 2017 -0600
ccmd: split into multiple files
---
tools/Makefile.in | 36 +-
tools/ccmd-main.c | 1130 +++++++++++++++++
tools/ccmd-man.c | 997 +++++++++++++++
tools/ccmd-util.c | 936 ++++++++++++++
tools/ccmd.h | 144 +++
tools/create-commands.c | 3169 -----------------------------------------------
6 files changed, 3238 insertions(+), 3174 deletions(-)
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 887bc69..8f53851 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -1,3 +1,4 @@
+
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
@@ -140,6 +141,8 @@ all: device-mapper
CFLAGS_lvm.o += $(EXTRA_EXEC_CFLAGS)
CFLAGS_lvmcmdline.o += $(VALGRIND_CFLAGS)
+INCLUDES += -I$(top_builddir)/tools
+
lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
$(LVMLIBS) $(READLINE_LIBS) $(LIBS) -rdynamic
@@ -173,12 +176,35 @@ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX)
$(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \
egrep -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help|lastlog|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands
-ccmd: create-commands.c
- $(CC) create-commands.c -o ccmd
+ccmd: $(srcdir)/ccmd-main.c $(srcdir)/ccmd-util.c $(srcdir)/ccmd-man.c
+ $(CC) $(srcdir)/ccmd-main.c $(srcdir)/ccmd-util.c $(srcdir)/ccmd-man.c -o ccmd
+
+.DELETE_ON_ERROR:
+
+command-lines.h: $(srcdir)/command-lines.in ccmd
+ $(top_builddir)/tools/ccmd --output struct $(srcdir)/command-lines.in > $@
+
+command-lines-count.h: $(srcdir)/command-lines.in ccmd
+ $(top_builddir)/tools/ccmd --output count $(srcdir)/command-lines.in > $@
+
+# move properly to configure
+WC = /usr/bin/wc
+GREP = /bin/grep
+SORT = /bin/sort
+CUT = /bin/cut
+SED = /bin/sed
+
+# FIXME Add licence text from template file
+command-lines-count-new.h: $(srcdir)/command-lines.in ccmd Makefile
+ set -o pipefail && \
+ (echo -n "#define COMMAND_COUNT " && \
+ $(GREP) '^ID:' $(srcdir)/command-lines.in | $(WC) -l && \
+ echo -e "enum {\n\tno_CMD," && \
+ $(GREP) '^ID:' $(srcdir)/command-lines.in | $(CUT) -d\ -f2 | $(SORT) -u | $(SED) 's/\(.*\)/\t&_CMD,/' && \
+ echo -e "\tCOMMAND_ID_COUNT,\n};" \
+ ) > $@
-command-lines.h: ccmd
- ./ccmd --output struct command-lines.in > command-lines.h
- ./ccmd --output count command-lines.in > command-lines-count.h
+$(SOURCES:%.c=%.d): command-lines.h command-lines-count.h
ifneq ("$(CFLOW_CMD)", "")
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
diff --git a/tools/ccmd-main.c b/tools/ccmd-main.c
new file mode 100644
index 0000000..85d5656
--- /dev/null
+++ b/tools/ccmd-main.c
@@ -0,0 +1,1130 @@
+#include <asm/types.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sched.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <getopt.h>
+
+#include "ccmd.h"
+
+
+/* input util functions (in ccmd-util.c) */
+char *split_line(char *buf, int *argc, char **argv, char sep);
+int val_str_to_num(char *str);
+int opt_str_to_num(char *str);
+int lvp_name_to_enum(char *str);
+int lv_to_enum(char *name);
+uint64_t lv_to_bits(char *name);
+
+/* header output functions (in ccmd-util.c) */
+void print_header_struct(void);
+void print_header_count(void);
+void print_ambiguous(void);
+
+/* man page output (in ccmd-main.c) */
+void print_man(char *man_command_name, int include_primary, int include_secondary);
+
+
+/* create table of value names, e.g. String, and corresponding enum from vals.h */
+
+struct val_name val_names[VAL_COUNT + 1] = {
+#define val(a, b, c, d) { # a, a, b, c, d },
+#include "vals.h"
+#undef val
+};
+
+/* create table of option names, e.g. --foo, and corresponding enum from args.h */
+
+struct opt_name opt_names[ARG_COUNT + 1] = {
+#define arg(a, b, c, d, e, f, g) { # a, a, b, "", "--" c, d, e, f, g },
+#include "args.h"
+#undef arg
+};
+
+/* create table of lv property names, e.g. lv_is_foo, and corresponding enum from lv_props.h */
+
+struct lvp_name lvp_names[LVP_COUNT + 1] = {
+#define lvp(a, b, c) { # a, a, b },
+#include "lv_props.h"
+#undef lvp
+};
+
+/* create table of lv type names, e.g. linear and corresponding enum from lv_types.h */
+
+struct lvt_name lvt_names[LVT_COUNT + 1] = {
+#define lvt(a, b, c) { # a, a, b },
+#include "lv_types.h"
+#undef lvt
+};
+
+/* create table of command names, e.g. vgcreate */
+
+struct cmd_name cmd_names[MAX_CMD_NAMES] = {
+#define xx(a, b, c) { # a , b } ,
+#include "commands.h"
+#undef xx
+};
+
+/* array of pointers into opt_names[] that is sorted alphabetically (by long opt name) */
+
+struct opt_name *opt_names_alpha[ARG_COUNT + 1];
+
+/* lvm_all is for recording options that are common for all lvm commands */
+
+struct command lvm_all;
+
+/* saves OO_FOO lines (groups of optional options) to include in multiple defs */
+
+static int oo_line_count;
+#define MAX_OO_LINES 256
+
+struct oo_line {
+ char *name;
+ char *line;
+};
+static struct oo_line oo_lines[MAX_OO_LINES];
+
+#define REQUIRED 1 /* required option */
+#define OPTIONAL 0 /* optional option */
+#define IGNORE -1 /* ignore option */
+
+/* control man page output */
+
+static int include_man_secondary = 1; /* include SECONDARY forms in man output */
+static int include_man_primary = 1; /* include primary forms in man output */
+static char *man_command_name = NULL; /* print man page for a single command name */
+
+
+static void add_optional_opt_line(struct command *cmd, int argc, char *argv[]);
+
+/*
+ * Parse command-lines.in and record those definitions
+ * in an array of struct command: cmd_array[].
+ */
+
+static const char *is_command_name(char *str)
+{
+ int i;
+
+ for (i = 0; i < MAX_CMD_NAMES; i++) {
+ if (!cmd_names[i].name)
+ break;
+ if (!strcmp(cmd_names[i].name, str))
+ return cmd_names[i].name;
+ }
+ return NULL;
+}
+
+struct cmd_name *find_command_name(const char *str)
+{
+ int i;
+
+ for (i = 0; i < MAX_CMD_NAMES; i++) {
+ if (!cmd_names[i].name)
+ break;
+ if (!strcmp(cmd_names[i].name, str))
+ return &cmd_names[i];
+ }
+ return NULL;
+}
+
+static int is_opt_name(char *str)
+{
+ if (!strncmp(str, "--", 2))
+ return 1;
+
+ if ((str[0] == '-') && (str[1] != '-')) {
+ printf("Options must be specified in long form: %s\n", str);
+ exit(1);
+ }
+
+ return 0;
+}
+
+/*
+ * "Select" as a pos name means that the position
+ * can be empty if the --select option is used.
+ */
+
+static int is_pos_name(char *str)
+{
+ if (!strncmp(str, "VG", 2))
+ return 1;
+ if (!strncmp(str, "LV", 2))
+ return 1;
+ if (!strncmp(str, "PV", 2))
+ return 1;
+ if (!strncmp(str, "Tag", 3))
+ return 1;
+ if (!strncmp(str, "String", 6))
+ return 1;
+ if (!strncmp(str, "Select", 6))
+ return 1;
+ return 0;
+}
+
+static int is_oo_definition(char *str)
+{
+ if (!strncmp(str, "OO_", 3) && strstr(str, ":"))
+ return 1;
+ return 0;
+}
+
+static int is_oo_line(char *str)
+{
+ if (!strncmp(str, "OO:", 3))
+ return 1;
+ return 0;
+}
+
+static int is_io_line(char *str)
+{
+ if (!strncmp(str, "IO:", 3))
+ return 1;
+ return 0;
+}
+
+static int is_op_line(char *str)
+{
+ if (!strncmp(str, "OP:", 3))
+ return 1;
+ return 0;
+}
+
+static int is_desc_line(char *str)
+{
+ if (!strncmp(str, "DESC:", 5))
+ return 1;
+ return 0;
+}
+
+static int is_flags_line(char *str)
+{
+ if (!strncmp(str, "FLAGS:", 6))
+ return 1;
+ return 0;
+}
+
+static int is_rule_line(char *str)
+{
+ if (!strncmp(str, "RULE:", 5))
+ return 1;
+ return 0;
+}
+
+static int is_id_line(char *str)
+{
+ if (!strncmp(str, "ID:", 3))
+ return 1;
+ return 0;
+}
+
+/*
+ * Save a positional arg in a struct arg_def.
+ * Parse str for anything that can appear in a position,
+ * like VG, VG|LV, VG|LV_linear|LV_striped, etc.
+ */
+
+static void set_pos_def(struct command *cmd, char *str, struct arg_def *def)
+{
+ char *argv[MAX_LINE_ARGC];
+ int argc;
+ char *name;
+ int val_enum;
+ int i;
+
+ split_line(str, &argc, argv, '|');
+
+ for (i = 0; i < argc; i++) {
+ name = argv[i];
+
+ val_enum = val_str_to_num(name);
+
+ if (!val_enum) {
+ printf("Unknown pos arg: %s\n", name);
+ exit(1);
+ }
+
+ def->val_bits |= val_enum_to_bit(val_enum);
+
+ if ((val_enum == lv_VAL) && strstr(name, "_"))
+ def->lvt_bits = lv_to_bits(name);
+
+ if (strstr(name, "_new")) {
+ if (val_enum == lv_VAL)
+ def->flags |= ARG_DEF_FLAG_NEW_LV;
+ else if (val_enum == vg_VAL)
+ def->flags |= ARG_DEF_FLAG_NEW_VG;
+ }
+ }
+}
+
+/*
+ * Save an option arg in a struct arg_def.
+ * Parse str for anything that can follow --option.
+ */
+
+static void set_opt_def(struct command *cmd, char *str, struct arg_def *def)
+{
+ char *argv[MAX_LINE_ARGC];
+ int argc;
+ char *name;
+ int val_enum;
+ int i, j;
+
+ split_line(str, &argc, argv, '|');
+
+ for (i = 0; i < argc; i++) {
+ name = argv[i];
+
+ val_enum = val_str_to_num(name);
+
+ if (!val_enum) {
+ /* a literal number or string */
+
+ if (isdigit(name[0]))
+ val_enum = constnum_VAL;
+
+ else if (isalpha(name[0]))
+ val_enum = conststr_VAL;
+
+ else {
+ printf("Unknown opt arg: %s\n", name);
+ exit(0);
+ }
+ }
+
+
+ def->val_bits |= val_enum_to_bit(val_enum);
+
+ if (val_enum == constnum_VAL)
+ def->num = (uint64_t)atoi(name);
+
+ if (val_enum == conststr_VAL)
+ def->str = strdup(name);
+
+ if (val_enum == lv_VAL) {
+ if (strstr(name, "_"))
+ def->lvt_bits = lv_to_bits(name);
+ }
+
+ if (strstr(name, "_new")) {
+ if (val_enum == lv_VAL)
+ def->flags |= ARG_DEF_FLAG_NEW_LV;
+ else if (val_enum == vg_VAL)
+ def->flags |= ARG_DEF_FLAG_NEW_VG;
+
+ }
+ }
+}
+
+/*
+ * Save a set of common options so they can be included in
+ * multiple command defs.
+ *
+ * OO_FOO: --opt1 ...
+ *
+ * oo->name = "OO_FOO";
+ * oo->line = "--opt1 ...";
+ */
+
+static void add_oo_definition_line(const char *name, const char *line)
+{
+ struct oo_line *oo;
+ char *colon;
+ char *start;
+
+ oo = &oo_lines[oo_line_count++];
+ oo->name = strdup(name);
+
+ if ((colon = strstr(oo->name, ":")))
+ *colon = '\0';
+ else {
+ printf("invalid OO definition\n");
+ exit(1);
+ }
+
+ start = strstr(line, ":") + 2;
+ oo->line = strdup(start);
+}
+
+/* Support OO_FOO: continuing on multiple lines. */
+
+static void append_oo_definition_line(const char *new_line)
+{
+ struct oo_line *oo;
+ char *old_line;
+ char *line;
+ int len;
+
+ oo = &oo_lines[oo_line_count-1];
+
+ old_line = oo->line;
+
+ /* +2 = 1 space between old and new + 1 terminating \0 */
+ len = strlen(old_line) + strlen(new_line) + 2;
+ line = malloc(len);
+ memset(line, 0, len);
+
+ strcat(line, old_line);
+ strcat(line, " ");
+ strcat(line, new_line);
+
+ free(oo->line);
+ oo->line = line;
+}
+
+/* Find a saved OO_FOO definition. */
+
+char *get_oo_line(char *str)
+{
+ char *name;
+ char *end;
+ char str2[64];
+ int i;
+
+ strcpy(str2, str);
+ if ((end = strstr(str2, ":")))
+ *end = '\0';
+ if ((end = strstr(str2, ",")))
+ *end = '\0';
+
+ for (i = 0; i < oo_line_count; i++) {
+ name = oo_lines[i].name;
+ if (!strcmp(name, str2))
+ return oo_lines[i].line;
+ }
+ return NULL;
+}
+
+/*
+ * Add optional_opt_args entries when OO_FOO appears on OO: line,
+ * i.e. include common options from an OO_FOO definition.
+ */
+
+static void include_optional_opt_args(struct command *cmd, char *str)
+{
+ char *oo_line;
+ char *line;
+ char *line_argv[MAX_LINE_ARGC];
+ int line_argc;
+
+ if (!(oo_line = get_oo_line(str))) {
+ printf("No OO line found for %s\n", str);
+ exit(1);
+ }
+
+ if (!(line = strdup(oo_line)))
+ exit(1);
+
+ split_line(line, &line_argc, line_argv, ' ');
+ add_optional_opt_line(cmd, line_argc, line_argv);
+ free(line);
+}
+
+/*
+ * When an --option is seen, add a new opt_args entry for it.
+ * This function sets the opt_args.opt value for it.
+ */
+
+static void add_opt_arg(struct command *cmd, char *str, int *takes_arg, int required)
+{
+ char *comma;
+ int opt;
+
+ /* opt_arg.opt set here */
+ /* opt_arg.def will be set in update_prev_opt_arg() if needed */
+
+ if ((comma = strstr(str, ",")))
+ *comma = '\0';
+
+ /*
+ * Work around nasty hack where --uuid is used for both uuid_ARG
+ * and uuidstr_ARG. The input uses --uuidstr, where an actual
+ * command uses --uuid string.
+ */
+ if (!strcmp(str, "--uuidstr")) {
+ opt = uuidstr_ARG;
+ goto skip;
+ }
+
+ opt = opt_str_to_num(str);
+skip:
+ if (required > 0)
+ cmd->required_opt_args[cmd->ro_count++].opt = opt;
+ else if (!required)
+ cmd->optional_opt_args[cmd->oo_count++].opt = opt;
+ else if (required < 0)
+ cmd->ignore_opt_args[cmd->io_count++].opt = opt;
+ else
+ exit(1);
+
+ *takes_arg = opt_names[opt].val_enum ? 1 : 0;
+}
+
+/*
+ * After --option has been seen, this function sets opt_args.def value
+ * for the value that appears after --option.
+ */
+
+static void update_prev_opt_arg(struct command *cmd, char *str, int required)
+{
+ struct arg_def def = { 0 };
+ char *comma;
+
+ if (str[0] == '-') {
+ printf("Option %s must be followed by an arg.\n", str);
+ exit(1);
+ }
+
+ /* opt_arg.def set here */
+ /* opt_arg.opt was previously set in add_opt_arg() when --foo was read */
+
+ if ((comma = strstr(str, ",")))
+ *comma = '\0';
+
+ set_opt_def(cmd, str, &def);
+
+ if (required > 0)
+ cmd->required_opt_args[cmd->ro_count-1].def = def;
+ else if (!required)
+ cmd->optional_opt_args[cmd->oo_count-1].def = def;
+ else if (required < 0)
+ cmd->ignore_opt_args[cmd->io_count-1].def = def;
+ else
+ exit(1);
+}
+
+/*
+ * When an position arg is seen, add a new pos_args entry for it.
+ * This function sets the pos_args.pos and pos_args.def.
+ */
+
+static void add_pos_arg(struct command *cmd, char *str, int required)
+{
+ struct arg_def def = { 0 };
+
+ /* pos_arg.pos and pos_arg.def are set here */
+
+ set_pos_def(cmd, str, &def);
+
+ if (required) {
+ cmd->required_pos_args[cmd->rp_count].pos = cmd->pos_count++;
+ cmd->required_pos_args[cmd->rp_count].def = def;
+ cmd->rp_count++;
+ } else {
+ cmd->optional_pos_args[cmd->op_count].pos = cmd->pos_count++;;
+ cmd->optional_pos_args[cmd->op_count].def = def;
+ cmd->op_count++;
+ }
+}
+
+/* Process something that follows a pos arg, which is not a new pos arg. */
+
+static void update_prev_pos_arg(struct command *cmd, char *str, int required)
+{
+ struct arg_def *def;
+
+ /* a previous pos_arg.def is modified here */
+
+ if (required)
+ def = &cmd->required_pos_args[cmd->rp_count-1].def;
+ else
+ def = &cmd->optional_pos_args[cmd->op_count-1].def;
+
+ if (!strcmp(str, "..."))
+ def->flags |= ARG_DEF_FLAG_MAY_REPEAT;
+ else {
+ printf("Unknown pos arg: %s\n", str);
+ exit(1);
+ }
+}
+
+/* Process what follows OO:, which are the optional opt args for the cmd def. */
+
+static void add_optional_opt_line(struct command *cmd, int argc, char *argv[])
+{
+ int takes_arg;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (!i && !strncmp(argv[i], "OO:", 3))
+ continue;
+ if (is_opt_name(argv[i]))
+ add_opt_arg(cmd, argv[i], &takes_arg, OPTIONAL);
+ else if (!strncmp(argv[i], "OO_", 3))
+ include_optional_opt_args(cmd, argv[i]);
+ else if (takes_arg)
+ update_prev_opt_arg(cmd, argv[i], OPTIONAL);
+ else
+ printf("Can't parse argc %d argv %s prev %s\n",
+ i, argv[i], argv[i-1]);
+ }
+}
+
+/* Process what follows IO:, which are the ignore options for the cmd def. */
+
+static void add_ignore_opt_line(struct command *cmd, int argc, char *argv[])
+{
+ int takes_arg;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (!i && !strncmp(argv[i], "IO:", 3))
+ continue;
+ if (is_opt_name(argv[i]))
+ add_opt_arg(cmd, argv[i], &takes_arg, IGNORE);
+ else if (takes_arg)
+ update_prev_opt_arg(cmd, argv[i], IGNORE);
+ else
+ printf("Can't parse argc %d argv %s prev %s\n",
+ i, argv[i], argv[i-1]);
+ }
+}
+
+/* Process what follows OP:, which are optional pos args for the cmd def. */
+
+static void add_optional_pos_line(struct command *cmd, int argc, char *argv[])
+{
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (!i && !strncmp(argv[i], "OP:", 3))
+ continue;
+ if (is_pos_name(argv[i]))
+ add_pos_arg(cmd, argv[i], OPTIONAL);
+ else
+ update_prev_pos_arg(cmd, argv[i], OPTIONAL);
+ }
+}
+
+static void add_required_opt_line(struct command *cmd, int argc, char *argv[])
+{
+ int takes_arg;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (is_opt_name(argv[i]))
+ add_opt_arg(cmd, argv[i], &takes_arg, REQUIRED);
+ else if (takes_arg)
+ update_prev_opt_arg(cmd, argv[i], REQUIRED);
+ else
+ printf("Can't parse argc %d argv %s prev %s\n",
+ i, argv[i], argv[i-1]);
+ }
+}
+
+/*
+ * Add to required_opt_args from an OO_FOO definition.
+ * (This is the special case of vgchange/lvchange where one
+ * optional option is required, and others are then optional.)
+ * The set of options from OO_FOO are saved in required_opt_args,
+ * and flag CMD_FLAG_ONE_REQUIRED_OPT is set on the cmd indicating
+ * this special case.
+ */
+
+static void include_required_opt_args(struct command *cmd, char *str)
+{
+ char *oo_line;
+ char *line;
+ char *line_argv[MAX_LINE_ARGC];
+ int line_argc;
+
+ if (!(oo_line = get_oo_line(str))) {
+ printf("No OO line found for %s\n", str);
+ exit(1);
+ }
+
+ if (!(line = strdup(oo_line)))
+ exit(1);
+
+ split_line(line, &line_argc, line_argv, ' ');
+ add_required_opt_line(cmd, line_argc, line_argv);
+ free(line);
+}
+
+/* Process what follows command_name, which are required opt/pos args. */
+
+static void add_required_line(struct command *cmd, int argc, char *argv[])
+{
+ int i;
+ int takes_arg;
+ int prev_was_opt = 0, prev_was_pos = 0;
+
+ /* argv[0] is command name */
+
+ for (i = 1; i < argc; i++) {
+
+ if (is_opt_name(argv[i])) {
+ /* add new required_opt_arg */
+ add_opt_arg(cmd, argv[i], &takes_arg, REQUIRED);
+ prev_was_opt = 1;
+ prev_was_pos = 0;
+
+ } else if (prev_was_opt && takes_arg) {
+ /* set value for previous required_opt_arg */
+ update_prev_opt_arg(cmd, argv[i], REQUIRED);
+ prev_was_opt = 0;
+ prev_was_pos = 0;
+
+ } else if (is_pos_name(argv[i])) {
+ /* add new required_pos_arg */
+ add_pos_arg(cmd, argv[i], REQUIRED);
+ prev_was_opt = 0;
+ prev_was_pos = 1;
+
+ } else if (!strncmp(argv[i], "OO_", 3)) {
+ /* one required_opt_arg is required, special case lv/vgchange */
+ cmd->cmd_flags |= CMD_FLAG_ONE_REQUIRED_OPT;
+ include_required_opt_args(cmd, argv[i]);
+
+ } else if (prev_was_pos) {
+ /* set property for previous required_pos_arg */
+ update_prev_pos_arg(cmd, argv[i], REQUIRED);
+ } else
+ printf("Can't parse argc %d argv %s prev %s\n",
+ i, argv[i], argv[i-1]);
+
+ }
+}
+
+static void add_flags(struct command *cmd, char *line)
+{
+ if (strstr(line, "SECONDARY_SYNTAX"))
+ cmd->cmd_flags |= CMD_FLAG_SECONDARY_SYNTAX;
+}
+
+#define MAX_RULE_OPTS 64
+
+static void add_rule(struct command *cmd, char *line)
+{
+ struct cmd_rule *rule;
+ char *line_argv[MAX_LINE_ARGC];
+ char *arg;
+ int line_argc;
+ int i, lvt_enum, lvp_enum;
+ int check = 0;
+
+ if (cmd->rule_count == CMD_MAX_RULES) {
+ printf("too many rules for cmd\n");
+ exit(1);
+ }
+
+ rule = &cmd->rules[cmd->rule_count++];
+
+ split_line(line, &line_argc, line_argv, ' ');
+
+ for (i = 0; i < line_argc; i++) {
+ arg = line_argv[i];
+
+ if (!strcmp(arg, "not")) {
+ rule->rule = RULE_INVALID;
+ check = 1;
+ }
+
+ else if (!strcmp(arg, "and")) {
+ rule->rule = RULE_REQUIRE;
+ check = 1;
+ }
+
+ else if (!strncmp(arg, "all", 3)) {
+ /* opt/lvt_bits/lvp_bits all remain 0 to mean all */
+ continue;
+ }
+
+ else if (!strncmp(arg, "--", 2)) {
+ if (!rule->opts) {
+ if (!(rule->opts = malloc(MAX_RULE_OPTS * sizeof(int)))) {
+ printf("no mem\n");
+ exit(1);
+ }
+ memset(rule->opts, 0, MAX_RULE_OPTS * sizeof(int));
+ }
+
+ if (!rule->check_opts) {
+ if (!(rule->check_opts = malloc(MAX_RULE_OPTS * sizeof(int)))) {
+ printf("no mem\n");
+ exit(1);
+ }
+ memset(rule->check_opts, 0, MAX_RULE_OPTS * sizeof(int));
+ }
+
+ if (check)
+ rule->check_opts[rule->check_opts_count++] = opt_str_to_num(arg);
+ else
+ rule->opts[rule->opts_count++] = opt_str_to_num(arg);
+ }
+
+ else if (!strncmp(arg, "LV_", 3)) {
+ lvt_enum = lv_to_enum(arg);
+
+ if (check)
+ rule->check_lvt_bits |= lvt_enum_to_bit(lvt_enum);
+ else
+ rule->lvt_bits |= lvt_enum_to_bit(lvt_enum);
+ }
+
+ else if (!strncmp(arg, "lv_is_", 6)) {
+ lvp_enum = lvp_name_to_enum(arg);
+
+ if (check)
+ rule->check_lvp_bits |= lvp_enum_to_bit(lvp_enum);
+ else
+ rule->lvp_bits |= lvp_enum_to_bit(lvp_enum);
+ }
+ }
+}
+
+/* The given option is common to all lvm commands (set in lvm_all). */
+
+int is_lvm_all_opt(int opt)
+{
+ int oo;
+
+ for (oo = 0; oo < lvm_all.oo_count; oo++) {
+ if (lvm_all.optional_opt_args[oo].opt == opt)
+ return 1;
+ }
+ return 0;
+}
+
+/* Find common options for all variants of each command name. */
+
+static void factor_common_options(void)
+{
+ int cn, opt_enum, ci, oo, ro, found;
+ struct command *cmd;
+
+ for (cn = 0; cn < MAX_CMD_NAMES; cn++) {
+ if (!cmd_names[cn].name)
+ break;
+
+ for (ci = 0; ci < cmd_count; ci++) {
+ cmd = &cmd_array[ci];
+
+ if (strcmp(cmd->name, cmd_names[cn].name))
+ continue;
+
+ cmd_names[cn].variants++;
+ }
+
+ for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
+
+ for (ci = 0; ci < cmd_count; ci++) {
+ cmd = &cmd_array[ci];
+
+ if (strcmp(cmd->name, cmd_names[cn].name))
+ continue;
+
+ if (cmd->ro_count)
+ cmd_names[cn].variant_has_ro = 1;
+ if (cmd->rp_count)
+ cmd_names[cn].variant_has_rp = 1;
+ if (cmd->oo_count)
+ cmd_names[cn].variant_has_oo = 1;
+ if (cmd->op_count)
+ cmd_names[cn].variant_has_op = 1;
+
+ for (ro = 0; ro < cmd->ro_count; ro++) {
+ cmd_names[cn].all_options[cmd->required_opt_args[ro].opt] = 1;
+
+ if ((cmd->required_opt_args[ro].opt == size_ARG) && !strncmp(cmd->name, "lv", 2))
+ cmd_names[cn].all_options[extents_ARG] = 1;
+ }
+ for (oo = 0; oo < cmd->oo_count; oo++)
+ cmd_names[cn].all_options[cmd->optional_opt_args[oo].opt] = 1;
+
+ found = 0;
+
+ for (oo = 0; oo < cmd->oo_count; oo++) {
+ if (cmd->optional_opt_args[oo].opt == opt_enum) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ goto next_opt;
+ }
+
+ /* all commands starting with this name use this option */
+ cmd_names[cn].common_options[opt_enum] = 1;
+ next_opt:
+ ;
+ }
+ }
+}
+
+static int long_name_compare(const void *on1, const void *on2)
+{
+ struct opt_name **optname1 = (void *)on1;
+ struct opt_name **optname2 = (void *)on2;
+ return strcmp((*optname1)->long_opt + 2, (*optname2)->long_opt + 2);
+}
+
+/* Create list of option names for printing alphabetically. */
+
+static void create_opt_names_alpha(void)
+{
+ int i;
+
+ for (i = 0; i < ARG_COUNT; i++)
+ opt_names_alpha[i] = &opt_names[i];
+
+ qsort(opt_names_alpha, ARG_COUNT, sizeof(long), long_name_compare);
+}
+
+static void print_help(int argc, char *argv[])
+{
+ printf("%s [options] --output <format> <filename>\n", argv[0]);
+ printf("\n");
+ printf("output formats:\n");
+ printf("struct: print C structures for command-lines.h\n");
+ printf("count: print defines and enums for command-lines-count.h\n");
+ printf("ambiguous: print commands differing only by LV types\n");
+ printf("man: print man page format.\n");
+ printf("\n");
+ printf("options:\n");
+ printf("-c|--man-command <commandname> man output for one command name\n");
+}
+
+int main(int argc, char *argv[])
+{
+ char *outputformat = NULL;
+ char *inputfile = NULL;
+ FILE *file;
+ struct command *cmd;
+ char line[MAX_LINE];
+ char line_orig[MAX_LINE];
+ const char *name;
+ char *line_argv[MAX_LINE_ARGC];
+ char *n;
+ int line_argc;
+ int prev_was_oo_def = 0;
+ int prev_was_oo = 0;
+ int prev_was_op = 0;
+
+ if (argc < 2) {
+ print_help(argc, argv);
+ exit(EXIT_FAILURE);
+ }
+
+ create_opt_names_alpha();
+
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h' },
+ {"output", required_argument, 0, 'o' },
+ {"man-primary", required_argument, 0, 'p' },
+ {"man-secondary", required_argument, 0, 's' },
+ {"man-command", required_argument, 0, 'c' },
+ {0, 0, 0, 0 }
+ };
+
+ while (1) {
+ int c;
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "ho:p:s:c:",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case '0':
+ break;
+ case 'h':
+ print_help(argc, argv);
+ exit(EXIT_SUCCESS);
+ case 'o':
+ outputformat = strdup(optarg);
+ break;
+ case 'p':
+ include_man_primary = atoi(optarg);
+ break;
+ case 's':
+ include_man_secondary = atoi(optarg);
+ break;
+ case 'c':
+ man_command_name = strdup(optarg);
+ break;
+ }
+ }
+
+ if (optind < argc)
+ inputfile = argv[optind];
+ else {
+ printf("Missing filename.\n");
+ return 0;
+ }
+
+ if (!(file = fopen(inputfile, "r"))) {
+ printf("Cannot open %s\n", argv[1]);
+ return -1;
+ }
+
+ /* Process each line of input file. */
+
+ while (fgets(line, MAX_LINE, file)) {
+ if (line[0] == '#')
+ continue;
+ if (line[0] == '\n')
+ continue;
+ if (line[0] == '-' && line[1] == '-' && line[2] == '-')
+ continue;
+
+ if ((n = strchr(line, '\n')))
+ *n = '\0';
+
+ memcpy(line_orig, line, sizeof(line));
+ split_line(line, &line_argc, line_argv, ' ');
+
+ if (!line_argc)
+ continue;
+
+ /* command ... */
+ if ((name = is_command_name(line_argv[0]))) {
+ if (cmd_count >= MAX_CMDS) {
+ printf("MAX_CMDS too small\n");
+ return -1;
+ }
+ cmd = &cmd_array[cmd_count++];
+ cmd->name = name;
+ cmd->pos_count = 1;
+ add_required_line(cmd, line_argc, line_argv);
+
+ /* Every cmd gets the OO_ALL options */
+ include_optional_opt_args(cmd, "OO_ALL:");
+ continue;
+ }
+
+ if (is_desc_line(line_argv[0])) {
+ char *desc = strdup(line_orig);
+ if (cmd->desc) {
+ int newlen = strlen(cmd->desc) + strlen(desc) + 2;
+ char *newdesc = malloc(newlen);
+ memset(newdesc, 0, newlen);
+ snprintf(newdesc, newlen, "%s %s", cmd->desc, desc);
+ cmd->desc = newdesc;
+ free(desc);
+ } else
+ cmd->desc = desc;
+ continue;
+ }
+
+ if (is_flags_line(line_argv[0])) {
+ add_flags(cmd, line_orig);
+ continue;
+ }
+
+ if (is_rule_line(line_argv[0])) {
+ add_rule(cmd, line_orig);
+ continue;
+ }
+
+ if (is_id_line(line_argv[0])) {
+ cmd->command_line_id = strdup(line_argv[1]);
+ continue;
+ }
+
+ /* OO_FOO: ... */
+ if (is_oo_definition(line_argv[0])) {
+ add_oo_definition_line(line_argv[0], line_orig);
+ prev_was_oo_def = 1;
+ prev_was_oo = 0;
+ prev_was_op = 0;
+ continue;
+ }
+
+ /* OO: ... */
+ if (is_oo_line(line_argv[0])) {
+ add_optional_opt_line(cmd, line_argc, line_argv);
+ prev_was_oo_def = 0;
+ prev_was_oo = 1;
+ prev_was_op = 0;
+ continue;
+ }
+
+ /* OP: ... */
+ if (is_op_line(line_argv[0])) {
+ add_optional_pos_line(cmd, line_argc, line_argv);
+ prev_was_oo_def = 0;
+ prev_was_oo = 0;
+ prev_was_op = 1;
+ continue;
+ }
+
+ /* IO: ... */
+ if (is_io_line(line_argv[0])) {
+ add_ignore_opt_line(cmd, line_argc, line_argv);
+ prev_was_oo = 0;
+ prev_was_op = 0;
+ continue;
+ }
+
+ /* handle OO_FOO:, OO:, OP: continuing on multiple lines */
+
+ if (prev_was_oo_def) {
+ append_oo_definition_line(line_orig);
+ continue;
+ }
+
+ if (prev_was_oo) {
+ add_optional_opt_line(cmd, line_argc, line_argv);
+ continue;
+ }
+
+ if (prev_was_op) {
+ add_optional_pos_line(cmd, line_argc, line_argv);
+ continue;
+ }
+ }
+
+ fclose(file);
+
+ /*
+ * Looks at all variants of each command name and figures out
+ * which options are common to all variants (for compact output)
+ */
+ factor_common_options();
+
+ /*
+ * Predefined string of options common to all commands
+ * (for compact output)
+ */
+ include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON");
+
+ /*
+ * Print output.
+ */
+
+ if (!strcmp(outputformat, "struct"))
+ print_header_struct();
+
+ else if (!strcmp(outputformat, "count"))
+ print_header_count();
+
+ else if (!strcmp(outputformat, "ambiguous"))
+ print_ambiguous();
+
+ else if (!strcmp(outputformat, "man"))
+ print_man(man_command_name, include_man_primary, include_man_secondary);
+ else
+ print_help(argc, argv);
+
+ return 0;
+}
+
diff --git a/tools/ccmd-man.c b/tools/ccmd-man.c
new file mode 100644
index 0000000..34a9c38
--- /dev/null
+++ b/tools/ccmd-man.c
@@ -0,0 +1,997 @@
+#include <asm/types.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sched.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include "ccmd.h"
+
+char *split_line(char *buf, int *argc, char **argv, char sep);
+struct cmd_name *find_command_name(const char *str);
+int is_lvm_all_opt(int opt);
+const char *lvt_enum_to_name(int lvt_enum);
+
+extern struct val_name val_names[VAL_COUNT + 1];
+extern struct opt_name opt_names[ARG_COUNT + 1];
+extern struct lvp_name lvp_names[LVP_COUNT + 1];
+extern struct lvt_name lvt_names[LVT_COUNT + 1];
+extern struct cmd_name cmd_names[MAX_CMD_NAMES];
+extern struct opt_name *opt_names_alpha[ARG_COUNT + 1];
+extern struct command lvm_all;
+
+static const char *cmd_name_desc(const char *name)
+{
+ int i;
+
+ for (i = 0; i < MAX_CMD_NAMES; i++) {
+ if (!cmd_names[i].name)
+ break;
+ if (!strcmp(cmd_names[i].name, name))
+ return cmd_names[i].desc;
+ }
+ return NULL;
+}
+
+static void print_val_man(const char *str)
+{
+ char *line;
+ char *line_argv[MAX_LINE_ARGC];
+ int line_argc;
+ int i;
+
+ if (!strcmp(str, "Number") ||
+ !strcmp(str, "String") ||
+ !strncmp(str, "VG", 2) ||
+ !strncmp(str, "LV", 2) ||
+ !strncmp(str, "PV", 2) ||
+ !strcmp(str, "Tag")) {
+ printf("\\fI%s\\fP", str);
+ return;
+ }
+
+ if (strstr(str, "Number[") || strstr(str, "]Number")) {
+ for (i = 0; i < strlen(str); i++) {
+ if (str[i] == 'N')
+ printf("\\fI");
+ if (str[i] == 'r') {
+ printf("%c", str[i]);
+ printf("\\fP");
+ continue;
+ }
+ printf("%c", str[i]);
+ }
+ return;
+ }
+
+ if (strstr(str, "|")) {
+ int len = strlen(str);
+ line = strdup(str);
+ split_line(line, &line_argc, line_argv, '|');
+ for (i = 0; i < line_argc; i++) {
+ if (i) {
+ printf("|");
+
+ /* this is a hack to add a line break for
+ a long string of opt values */
+ if ((len > 40) && (i >= (line_argc / 2) + 1)) {
+ printf("\n");
+ printf(" ");
+ len = 0;
+ }
+ }
+ if (strstr(line_argv[i], "Number"))
+ printf("\\fI%s\\fP", line_argv[i]);
+ else
+ printf("\\fB%s\\fP", line_argv[i]);
+ }
+ return;
+ }
+
+ printf("\\fB%s\\fP", str);
+}
+
+static void print_def_man(struct arg_def *def, int usage)
+{
+ int val_enum;
+ int lvt_enum;
+ int sep = 0;
+ int i;
+
+ for (val_enum = 0; val_enum < VAL_COUNT; val_enum++) {
+ if (def->val_bits & val_enum_to_bit(val_enum)) {
+
+ if (val_enum == conststr_VAL) {
+ printf("\\fB");
+ printf("%s", def->str);
+ printf("\\fP");
+ }
+
+ else if (val_enum == constnum_VAL) {
+ printf("\\fB");
+ printf("%llu", (unsigned long long)def->num);
+ printf("\\fP");
+ }
+
+ else {
+ if (sep) printf("|");
+
+ if (!usage || !val_names[val_enum].usage) {
+ printf("\\fI");
+ printf("%s", val_names[val_enum].name);
+ printf("\\fP");
+ } else {
+ print_val_man(val_names[val_enum].usage);
+ }
+
+ sep = 1;
+ }
+
+ if (val_enum == lv_VAL && def->lvt_bits) {
+ printf("\\fI");
+ for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
+ if (lvt_bit_is_set(def->lvt_bits, lvt_enum))
+ printf("_%s", lvt_enum_to_name(lvt_enum));
+ }
+ printf("\\fP");
+ }
+
+ if ((val_enum == vg_VAL) && (def->flags & ARG_DEF_FLAG_NEW_VG)) {
+ printf("\\fI");
+ printf("_new");
+ printf("\\fP");
+ }
+ if ((val_enum == lv_VAL) && (def->flags & ARG_DEF_FLAG_NEW_LV)) {
+ printf("\\fI");
+ printf("_new");
+ printf("\\fP");
+ }
+ }
+ }
+
+ if (def->flags & ARG_DEF_FLAG_MAY_REPEAT)
+ printf(" ...");
+}
+
+static char *man_long_opt_name(const char *cmdname, int opt_enum)
+{
+ static char long_opt_name[64];
+
+ memset(&long_opt_name, 0, sizeof(long_opt_name));
+
+ switch (opt_enum) {
+ case syncaction_ARG:
+ strncpy(long_opt_name, "--[raid]syncaction", 63);
+ break;
+ case writemostly_ARG:
+ strncpy(long_opt_name, "--[raid]writemostly", 63);
+ break;
+ case minrecoveryrate_ARG:
+ strncpy(long_opt_name, "--[raid]minrecoveryrate", 63);
+ break;
+ case maxrecoveryrate_ARG:
+ strncpy(long_opt_name, "--[raid]maxrecoveryrate", 63);
+ break;
+ case writebehind_ARG:
+ strncpy(long_opt_name, "--[raid]writebehind", 63);
+ break;
+ case vgmetadatacopies_ARG:
+ if (!strncmp(cmdname, "vg", 2))
+ strncpy(long_opt_name, "--[vg]metadatacopies", 63);
+ else
+ strncpy(long_opt_name, "--vgmetadatacopies", 63);
+ break;
+ case pvmetadatacopies_ARG:
+ if (!strncmp(cmdname, "pv", 2))
+ strncpy(long_opt_name, "--[pv]metadatacopies", 63);
+ else
+ strncpy(long_opt_name, "--pvmetadatacopies", 63);
+ break;
+ default:
+ strncpy(long_opt_name, opt_names[opt_enum].long_opt, 63);
+ break;
+ }
+
+ return long_opt_name;
+}
+
+void print_man_usage(struct command *cmd)
+{
+ struct cmd_name *cname;
+ int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
+ int i, sep, ro, rp, oo, op, opt_enum;
+
+ if (!(cname = find_command_name(cmd->name)))
+ return;
+
+ printf("\\fB%s\\fP", cmd->name);
+
+ if (!onereq)
+ goto ro_normal;
+
+ /*
+ * one required option in a set, print as:
+ * ( -a|--a,
+ * -b|--b,
+ * --c,
+ * --d )
+ *
+ * First loop through ro prints those with short opts,
+ * and the second loop prints those without short opts.
+ */
+
+ if (cmd->ro_count) {
+ printf("\n");
+ printf(".RS 4\n");
+ printf("(");
+
+ sep = 0;
+
+ /* print required options with a short opt */
+ for (ro = 0; ro < cmd->ro_count; ro++) {
+ opt_enum = cmd->required_opt_args[ro].opt;
+
+ if (!opt_names[opt_enum].short_opt)
+ continue;
+
+ if (sep) {
+ printf(",");
+ printf("\n.br\n");
+ printf(" ");
+ }
+
+ if (opt_names[opt_enum].short_opt) {
+ printf(" \\fB-%c\\fP|\\fB%s\\fP",
+ opt_names[opt_enum].short_opt,
+ man_long_opt_name(cmd->name, opt_enum));
+ } else {
+ printf(" ");
+ printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
+ }
+
+ if (cmd->required_opt_args[ro].def.val_bits) {
+ printf(" ");
+ print_def_man(&cmd->required_opt_args[ro].def, 1);
+ }
+
+ sep = 1;
+ }
+
+ /* print required options without a short opt */
+ for (ro = 0; ro < cmd->ro_count; ro++) {
+ opt_enum = cmd->required_opt_args[ro].opt;
+
+ if (opt_names[opt_enum].short_opt)
+ continue;
+
+ if (sep) {
+ printf(",");
+ printf("\n.br\n");
+ printf(" ");
+ }
+
+ printf(" ");
+ printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
+
+ if (cmd->required_opt_args[ro].def.val_bits) {
+ printf(" ");
+ print_def_man(&cmd->required_opt_args[ro].def, 1);
+ }
+
+ sep = 1;
+ }
+
+ printf(" )\n");
+ printf(".RE\n");
+ }
+
+ /* print required position args on a new line after the onereq set */
+ if (cmd->rp_count) {
+ printf(".RS 4\n");
+ for (rp = 0; rp < cmd->rp_count; rp++) {
+ if (cmd->required_pos_args[rp].def.val_bits) {
+ printf(" ");
+ print_def_man(&cmd->required_pos_args[rp].def, 1);
+ }
+ }
+
+ printf("\n");
+ printf(".RE\n");
+ } else {
+ /* printf("\n"); */
+ }
+
+ printf(".br\n");
+ goto oo_count;
+
+ ro_normal:
+
+ /*
+ * all are required options, print as:
+ * -a|--aaa <val> -b|--bbb <val>
+ */
+
+ if (cmd->ro_count) {
+ for (ro = 0; ro < cmd->ro_count; ro++) {
+ opt_enum = cmd->required_opt_args[ro].opt;
+
+ if (opt_names[opt_enum].short_opt) {
+ printf(" \\fB-%c\\fP|\\fB%s\\fP",
+ opt_names[opt_enum].short_opt,
+ man_long_opt_name(cmd->name, opt_enum));
+ } else {
+ printf(" \\fB%s\\fP", opt_names[cmd->required_opt_args[ro].opt].long_opt);
+ }
+
+ if (cmd->required_opt_args[ro].def.val_bits) {
+ printf(" ");
+ print_def_man(&cmd->required_opt_args[ro].def, 1);
+ }
+ }
+ }
+
+ /* print required position args on the same line as the required options */
+ if (cmd->rp_count) {
+ for (rp = 0; rp < cmd->rp_count; rp++) {
+ if (cmd->required_pos_args[rp].def.val_bits) {
+ printf(" ");
+ print_def_man(&cmd->required_pos_args[rp].def, 1);
+ }
+ }
+
+ printf("\n");
+ } else {
+ printf("\n");
+ }
+
+ printf(".br\n");
+
+ oo_count:
+ if (!cmd->oo_count)
+ goto op_count;
+
+ sep = 0;
+
+ if (cmd->oo_count) {
+ printf(".RS 4\n");
+ printf("[");
+
+ /* print optional options with short opts */
+
+ for (oo = 0; oo < cmd->oo_count; oo++) {
+ opt_enum = cmd->optional_opt_args[oo].opt;
+
+ if (!opt_names[opt_enum].short_opt)
+ continue;
+
+ /*
+ * Skip common opts which are in the usage_common string.
+ * The common opts are those in lvm_all and in
+ * cname->common_options.
+ */
+
+ if (is_lvm_all_opt(opt_enum))
+ continue;
+
+ if ((cname->variants > 1) && cname->common_options[opt_enum])
+ continue;
+
+ if (sep) {
+ printf(",");
+ printf("\n.br\n");
+ printf(" ");
+ }
+
+ printf(" \\fB-%c\\fP|\\fB%s\\fP",
+ opt_names[opt_enum].short_opt,
+ man_long_opt_name(cmd->name, opt_enum));
+
+ if (cmd->optional_opt_args[oo].def.val_bits) {
+ printf(" ");
+ print_def_man(&cmd->optional_opt_args[oo].def, 1);
+ }
+ sep = 1;
+ }
+
+ /* print optional options without short opts */
+
+ for (oo = 0; oo < cmd->oo_count; oo++) {
+ opt_enum = cmd->optional_opt_args[oo].opt;
+
+ if (opt_names[opt_enum].short_opt)
+ continue;
+
+ /*
+ * Skip common opts which are in the usage_common string.
+ * The common opts are those in lvm_all and in
+ * cname->common_options.
+ */
+
+ if (is_lvm_all_opt(opt_enum))
+ continue;
+
+ if ((cname->variants > 1) && cname->common_options[opt_enum])
+ continue;
+
+ if (sep) {
+ printf(",");
+ printf("\n.br\n");
+ printf(" ");
+ }
+
+ /* space alignment without short opt */
+ printf(" ");
+
+ printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
+
+ if (cmd->optional_opt_args[oo].def.val_bits) {
+ printf(" ");
+ print_def_man(&cmd->optional_opt_args[oo].def, 1);
+ }
+ sep = 1;
+ }
+
+ if (sep) {
+ printf(",");
+ printf("\n.br\n");
+ printf(" ");
+ /* space alignment without short opt */
+ printf(" ");
+ }
+ printf(" COMMON_OPTIONS");
+ printf(" ]\n");
+ printf(".RE\n");
+ printf(".br\n");
+ }
+
+ op_count:
+ if (!cmd->op_count)
+ goto done;
+
+ printf(".RS 4\n");
+ printf("[");
+
+ if (cmd->op_count) {
+ for (op = 0; op < cmd->op_count; op++) {
+ if (cmd->optional_pos_args[op].def.val_bits) {
+ printf(" ");
+ print_def_man(&cmd->optional_pos_args[op].def, 1);
+ }
+ }
+ }
+
+ printf(" ]\n");
+ printf(".RE\n");
+
+ done:
+ printf("\n");
+}
+
+/*
+ * common options listed in the usage section.
+ *
+ * For commands with only one variant, this is only
+ * the options which are common to all lvm commands
+ * (in lvm_all, see is_lvm_all_opt).
+ *
+ * For commands with more than one variant, this
+ * is the set of options common to all variants
+ * (in cname->common_options), (which obviously
+ * includes the options common to all lvm commands.)
+ *
+ * List ordering:
+ * options with short+long names, alphabetically,
+ * then options with only long names, alphabetically
+ */
+
+void print_man_usage_common(struct command *cmd)
+{
+ struct cmd_name *cname;
+ int i, sep, ro, rp, oo, op, opt_enum;
+
+ if (!(cname = find_command_name(cmd->name)))
+ return;
+
+ sep = 0;
+
+ printf(".RS 4\n");
+ printf("[");
+
+ /* print those with short opts */
+ for (i = 0; i < ARG_COUNT; i++) {
+ opt_enum = opt_names_alpha[i]->opt_enum;
+
+ if (!cname->common_options[opt_enum])
+ continue;
+
+ if (!opt_names[opt_enum].short_opt)
+ continue;
+
+ if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
+ continue;
+
+ if (sep) {
+ printf(",");
+ printf("\n.br\n");
+ printf(" ");
+ }
+
+ for (oo = 0; oo < cmd->oo_count; oo++) {
+ if (cmd->optional_opt_args[oo].opt != opt_enum)
+ continue;
+
+ printf(" \\fB-%c\\fP|\\fB%s\\fP",
+ opt_names[opt_enum].short_opt,
+ man_long_opt_name(cmd->name, opt_enum));
+
+ if (cmd->optional_opt_args[oo].def.val_bits) {
+ printf(" ");
+ print_def_man(&cmd->optional_opt_args[oo].def, 1);
+ }
+ sep = 1;
+ break;
+ }
+
+ }
+
+ /* print those without short opts */
+ for (i = 0; i < ARG_COUNT; i++) {
+ opt_enum = opt_names_alpha[i]->opt_enum;
+
+ if (!cname->common_options[opt_enum])
+ continue;
+
+ if (opt_names[opt_enum].short_opt)
+ continue;
+
+ if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
+ continue;
+
+ if (sep) {
+ printf(",");
+ printf("\n.br\n");
+ printf(" ");
+ }
+
+ for (oo = 0; oo < cmd->oo_count; oo++) {
+ if (cmd->optional_opt_args[oo].opt != opt_enum)
+ continue;
+
+ /* space alignment without short opt */
+ printf(" ");
+
+ printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
+
+ if (cmd->optional_opt_args[oo].def.val_bits) {
+ printf(" ");
+ print_def_man(&cmd->optional_opt_args[oo].def, 1);
+ }
+ sep = 1;
+ break;
+ }
+ }
+
+ printf(" ]\n");
+ return;
+}
+
+/*
+ * Format of description, when different command names have
+ * different descriptions:
+ *
+ * "#cmdname1"
+ * "text foo goes here"
+ * "a second line of text."
+ * "#cmdname2"
+ * "text bar goes here"
+ * "another line of text."
+ *
+ * When called for cmdname2, this function should just print:
+ *
+ * "text bar goes here"
+ * "another line of text."
+ */
+
+static void print_man_option_desc(struct cmd_name *cname, int opt_enum)
+{
+ const char *desc = opt_names[opt_enum].desc;
+ char buf[DESC_LINE];
+ int started_cname = 0;
+ int line_count = 0;
+ int di, bi = 0;
+
+ if (desc[0] != '#') {
+ printf("%s", desc);
+ return;
+ }
+
+ for (di = 0; di < strlen(desc); di++) {
+ buf[bi++] = desc[di];
+
+ if (bi == DESC_LINE) {
+ printf("print_man_option_desc line too long\n");
+ return;
+ }
+
+ if (buf[bi-1] != '\n')
+ continue;
+
+ if (buf[0] != '#') {
+ if (started_cname) {
+ printf("%s", buf);
+ line_count++;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ bi = 0;
+ continue;
+ }
+
+ /* Line starting with #cmdname */
+
+ /*
+ * Must be starting a new command name.
+ * If no lines have been printed, multiple command names
+ * are using the same text. If lines have been printed,
+ * then the start of a new command name means the end
+ * of text for the current command name.
+ */
+ if (line_count && started_cname)
+ return;
+
+ if (!strncmp(buf + 1, cname->name, strlen(cname->name))) {
+ /* The start of our command name. */
+ started_cname = 1;
+ memset(buf, 0, sizeof(buf));
+ bi = 0;
+ } else {
+ /* The start of another command name. */
+ memset(buf, 0, sizeof(buf));
+ bi = 0;
+ }
+ }
+
+ if (bi && started_cname)
+ printf("%s", buf);
+}
+
+/*
+ * Print a list of all options names for a given
+ * command name, listed by:
+ * options with short+long names, alphabetically,
+ * then options with only long names, alphabetically
+ */
+
+void print_man_all_options_list(struct cmd_name *cname)
+{
+ int opt_enum, val_enum;
+ int sep = 0;
+ int i;
+
+ /* print those with both short and long opts */
+ for (i = 0; i < ARG_COUNT; i++) {
+ opt_enum = opt_names_alpha[i]->opt_enum;
+
+
+ if (!cname->all_options[opt_enum])
+ continue;
+
+ if (!opt_names[opt_enum].short_opt)
+ continue;
+
+ if (sep)
+ printf("\n.br\n");
+
+ printf(" \\fB-%c\\fP|\\fB%s\\fP",
+ opt_names[opt_enum].short_opt,
+ man_long_opt_name(cname->name, opt_enum));
+
+ val_enum = opt_names[opt_enum].val_enum;
+
+ if (!val_names[val_enum].fn) {
+ /* takes no arg */
+ } else if (!val_names[val_enum].usage) {
+ printf(" ");
+ printf("\\fI");
+ printf("%s", val_names[val_enum].name);
+ printf("\\fP");
+ } else {
+ printf(" ");
+ print_val_man(val_names[val_enum].usage);
+ }
+
+ sep = 1;
+ }
+
+ /* print those without short opts */
+ for (i = 0; i < ARG_COUNT; i++) {
+ opt_enum = opt_names_alpha[i]->opt_enum;
+
+ if (!cname->all_options[opt_enum])
+ continue;
+
+ if (opt_names[opt_enum].short_opt)
+ continue;
+
+ if (sep)
+ printf("\n.br\n");
+
+ /* space alignment without short opt */
+ printf(" ");
+
+ printf(" \\fB%s\\fP", man_long_opt_name(cname->name, opt_enum));
+
+ val_enum = opt_names[opt_enum].val_enum;
+
+ if (!val_names[val_enum].fn) {
+ /* takes no arg */
+ } else if (!val_names[val_enum].usage) {
+ printf(" ");
+ printf("\\fI");
+ printf("%s", val_names[val_enum].name);
+ printf("\\fP");
+ } else {
+ printf(" ");
+ print_val_man(val_names[val_enum].usage);
+ }
+
+ sep = 1;
+ }
+}
+
+/*
+ * All options used for a given command name, along with descriptions.
+ * listed in order of:
+ * 1. options that are not common to all lvm commands, alphabetically
+ * 2. options common to all lvm commands, alphabetically
+ */
+
+void print_man_all_options_desc(struct cmd_name *cname)
+{
+ int opt_enum, val_enum;
+ int print_common = 0;
+ int sep = 0;
+ int i;
+
+ again:
+ /*
+ * Loop 1: print options that are not common to all lvm commands.
+ * Loop 2: print options common to all lvm commands (lvm_all)
+ */
+
+ for (i = 0; i < ARG_COUNT; i++) {
+ opt_enum = opt_names_alpha[i]->opt_enum;
+
+ if (!cname->all_options[opt_enum])
+ continue;
+
+ if (!print_common && is_lvm_all_opt(opt_enum))
+ continue;
+
+ if (print_common && !is_lvm_all_opt(opt_enum))
+ continue;
+
+ if (sep)
+ printf("\n.br\n");
+
+ printf("\n.TP\n");
+
+ if (opt_names[opt_enum].short_opt) {
+ printf("\\fB-%c\\fP|\\fB%s\\fP",
+ opt_names[opt_enum].short_opt,
+ man_long_opt_name(cname->name, opt_enum));
+ } else {
+ printf("\\fB%s\\fP", man_long_opt_name(cname->name, opt_enum));
+ }
+
+ val_enum = opt_names[opt_enum].val_enum;
+
+ if (!val_names[val_enum].fn) {
+ /* takes no arg */
+ } else if (!val_names[val_enum].usage) {
+ printf(" ");
+ printf("\\fI");
+ printf("%s", val_names[val_enum].name);
+ printf("\\fP");
+ } else {
+ printf(" ");
+ print_val_man(val_names[val_enum].usage);
+ }
+
+ if (opt_names[opt_enum].desc) {
+ printf("\n");
+ printf(".br\n");
+ print_man_option_desc(cname, opt_enum);
+ }
+
+ sep = 1;
+ }
+
+ if (!print_common) {
+ print_common = 1;
+ goto again;
+ }
+}
+
+void print_desc_man(const char *desc)
+{
+ char buf[DESC_LINE] = {0};
+ int di = 0;
+ int bi = 0;
+
+ for (di = 0; di < strlen(desc); di++) {
+ if (desc[di] == '\0')
+ break;
+ if (desc[di] == '\n')
+ continue;
+
+ if (!strncmp(&desc[di], "DESC:", 5)) {
+ if (bi) {
+ printf("%s\n", buf);
+ printf(".br\n");
+ memset(buf, 0, sizeof(buf));
+ bi = 0;
+ }
+ di += 5;
+ continue;
+ }
+
+ if (!bi && desc[di] == ' ')
+ continue;
+
+ buf[bi++] = desc[di];
+
+ if (bi == (DESC_LINE - 1))
+ break;
+ }
+
+ if (bi) {
+ printf("%s\n", buf);
+ printf(".br\n");
+ }
+}
+
+static char *upper_command_name(char *str)
+{
+ static char str_upper[32];
+ int i = 0;
+
+ while (*str) {
+ str_upper[i++] = toupper(*str);
+ str++;
+ }
+ str_upper[i] = '\0';
+ return str_upper;
+}
+
+void print_man(char *man_command_name, int include_primary, int include_secondary)
+{
+ struct cmd_name *cname;
+ struct command *cmd, *prev_cmd = NULL;
+ const char *desc;
+ int i, j, ro, rp, oo, op;
+
+ printf(".TH %s 8 \"LVM TOOLS #VERSION#\" \"Sistina Software UK\"\n",
+ man_command_name ? upper_command_name(man_command_name) : "LVM_COMMANDS");
+
+ for (i = 0; i < cmd_count; i++) {
+
+ cmd = &cmd_array[i];
+
+ if (prev_cmd && strcmp(prev_cmd->name, cmd->name)) {
+ printf("Common options:\n");
+ printf(".\n");
+ print_man_usage_common(prev_cmd);
+
+ printf("\n");
+ printf(".SH OPTIONS\n");
+ printf(".br\n");
+ print_man_all_options_desc(cname);
+
+ prev_cmd = NULL;
+ }
+
+ if ((cmd->cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && !include_secondary)
+ continue;
+
+ if (!(cmd->cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && !include_primary)
+ continue;
+
+ if (man_command_name && strcmp(man_command_name, cmd->name))
+ continue;
+
+ if (!prev_cmd || strcmp(prev_cmd->name, cmd->name)) {
+ printf(".SH NAME\n");
+ printf(".\n");
+ if ((desc = cmd_name_desc(cmd->name)))
+ printf("%s \\- %s\n", cmd->name, desc);
+ else
+ printf("%s\n", cmd->name);
+ printf(".br\n");
+ printf(".P\n");
+ printf(".\n");
+ printf(".SH SYNOPSIS\n");
+ printf(".br\n");
+ printf(".P\n");
+ printf(".\n");
+ prev_cmd = cmd;
+
+ if (!(cname = find_command_name(cmd->name)))
+ return;
+
+ if (cname->variant_has_ro && cname->variant_has_rp)
+ printf("\\fB%s\\fP \\fIrequired_option_args\\fP \\fIrequired_position_args\\fP\n", cmd->name);
+ else if (cname->variant_has_ro && !cname->variant_has_rp)
+ printf("\\fB%s\\fP \\fIrequired_option_args\\fP\n", cmd->name);
+ else if (!cname->variant_has_ro && cname->variant_has_rp)
+ printf("\\fB%s\\fP \\fIrequired_position_args\\fP\n", cmd->name);
+ else if (!cname->variant_has_ro && !cname->variant_has_rp)
+ printf("\\fB%s\\fP\n", cmd->name);
+
+ printf(".br\n");
+
+ if (cname->variant_has_oo) {
+ printf(" [ \\fIoptional_option_args\\fP ]\n");
+ printf(".br\n");
+ }
+
+ if (cname->variant_has_op) {
+ printf(" [ \\fIoptional_position_args\\fP ]\n");
+ printf(".br\n");
+ }
+
+ printf(".P\n");
+ printf("\n");
+
+ /* listing them all when there's only 1 or 2 is just repetative */
+ if (cname->variants > 2) {
+ printf(".P\n");
+ print_man_all_options_list(cname);
+ printf("\n");
+ printf(".P\n");
+ printf("\n");
+ }
+
+ printf(".SH USAGE\n");
+ printf(".br\n");
+ printf(".P\n");
+ printf(".\n");
+ }
+
+ if (cmd->desc) {
+ print_desc_man(cmd->desc);
+ printf(".P\n");
+ }
+
+ print_man_usage(cmd);
+
+ if (i == (cmd_count - 1)) {
+ printf("Common options:\n");
+ printf(".\n");
+ print_man_usage_common(cmd);
+
+ printf("\n");
+ printf(".SH OPTIONS\n");
+ printf(".br\n");
+ print_man_all_options_desc(cname);
+
+ }
+
+ printf("\n");
+ continue;
+ }
+}
+
diff --git a/tools/ccmd-util.c b/tools/ccmd-util.c
new file mode 100644
index 0000000..15b2f96
--- /dev/null
+++ b/tools/ccmd-util.c
@@ -0,0 +1,936 @@
+#include <asm/types.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sched.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include "ccmd.h"
+
+struct cmd_name *find_command_name(const char *str);
+int is_lvm_all_opt(int opt);
+
+extern struct val_name val_names[VAL_COUNT + 1];
+extern struct opt_name opt_names[ARG_COUNT + 1];
+extern struct lvp_name lvp_names[LVP_COUNT + 1];
+extern struct lvt_name lvt_names[LVT_COUNT + 1];
+extern struct cmd_name cmd_names[MAX_CMD_NAMES];
+extern struct command lvm_all;
+
+/*
+ * modifies buf, replacing the sep characters with \0
+ * argv pointers point to positions in buf
+ */
+
+char *split_line(char *buf, int *argc, char **argv, char sep)
+{
+ char *p = buf, *rp = NULL;
+ int i;
+
+ argv[0] = p;
+
+ for (i = 1; i < MAX_LINE_ARGC; i++) {
+ p = strchr(buf, sep);
+ if (!p)
+ break;
+ *p = '\0';
+
+ argv[i] = p + 1;
+ buf = p + 1;
+ }
+ *argc = i;
+
+ /* we ended by hitting \0, return the point following that */
+ if (!rp)
+ rp = strchr(buf, '\0') + 1;
+
+ return rp;
+}
+
+/* convert value string, e.g. Number, to foo_VAL enum */
+
+int val_str_to_num(char *str)
+{
+ char name[32] = { 0 };
+ char *new;
+ int i;
+
+ /* compare the name before any suffix like _new or _<lvtype> */
+
+ strncpy(name, str, 31);
+ if ((new = strstr(name, "_")))
+ *new = '\0';
+
+ for (i = 0; i < VAL_COUNT; i++) {
+ if (!val_names[i].name)
+ break;
+ if (!strncmp(name, val_names[i].name, strlen(val_names[i].name)))
+ return val_names[i].val_enum;
+ }
+
+ return 0;
+}
+
+/* convert "--option" to foo_ARG enum */
+
+int opt_str_to_num(char *str)
+{
+ char long_name[32];
+ char *p;
+ int i;
+
+ /*
+ * --foo_long means there are two args entries
+ * for --foo, one with a short option and one
+ * without, and we want the one without the
+ * short option.
+ */
+ if (strstr(str, "_long")) {
+ strcpy(long_name, str);
+ p = strstr(long_name, "_long");
+ *p = '\0';
+
+ for (i = 0; i < ARG_COUNT; i++) {
+ if (!opt_names[i].long_opt)
+ continue;
+ /* skip anything with a short opt */
+ if (opt_names[i].short_opt)
+ continue;
+ if (!strcmp(opt_names[i].long_opt, long_name))
+ return opt_names[i].opt_enum;
+ }
+
+ printf("Unknown opt str: %s %s\n", str, long_name);
+ exit(1);
+ }
+
+ for (i = 0; i < ARG_COUNT; i++) {
+ if (!opt_names[i].long_opt)
+ continue;
+ /* These are only selected using --foo_long */
+ if (strstr(opt_names[i].name, "_long_ARG"))
+ continue;
+ if (!strcmp(opt_names[i].long_opt, str))
+ return opt_names[i].opt_enum;
+ }
+
+ printf("Unknown opt str: \"%s\"\n", str);
+ exit(1);
+}
+
+/* "lv_is_prop" to is_prop_LVP */
+
+int lvp_name_to_enum(char *str)
+{
+ int i;
+
+ for (i = 1; i < LVP_COUNT; i++) {
+ if (!strcmp(str, lvp_names[i].name))
+ return lvp_names[i].lvp_enum;
+ }
+ printf("unknown lv property %s\n", str);
+ exit(1);
+}
+
+/* type_LVT to "type" */
+
+const char *lvt_enum_to_name(int lvt_enum)
+{
+ return lvt_names[lvt_enum].name;
+}
+
+/* "type" to type_LVT */
+
+static int lvt_name_to_enum(char *str)
+{
+ int i;
+
+ for (i = 1; i < LVT_COUNT; i++) {
+ if (!strcmp(str, lvt_names[i].name))
+ return lvt_names[i].lvt_enum;
+ }
+ printf("unknown lv type %s\n", str);
+ exit(1);
+}
+
+/* LV_<type> to <type>_LVT */
+
+int lv_to_enum(char *name)
+{
+ return lvt_name_to_enum(name + 3);
+}
+
+/*
+ * LV_<type1>_<type2> to lvt_bits
+ *
+ * type1 to lvt_enum
+ * lvt_bits |= lvt_enum_to_bit(lvt_enum)
+ * type2 to lvt_enum
+ * lvt_bits |= lvt_enum_to_bit(lvt_enum)
+ */
+
+uint64_t lv_to_bits(char *name)
+{
+ char buf[64];
+ char *argv[MAX_LINE_ARGC];
+ uint64_t lvt_bits = 0;
+ int lvt_enum;
+ int argc;
+ int i;
+
+ strcpy(buf, name);
+
+ split_line(buf, &argc, argv, '_');
+
+ /* 0 is "LV" */
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "new"))
+ continue;
+ lvt_enum = lvt_name_to_enum(argv[i]);
+ lvt_bits |= lvt_enum_to_bit(lvt_enum);
+ }
+
+ return lvt_bits;
+}
+
+/* output for struct/count */
+
+static char *val_bits_to_str(uint64_t val_bits)
+{
+ static char buf[1024];
+ int i;
+ int or = 0;
+
+ memset(buf, 0, sizeof(buf));
+
+ for (i = 0; i < VAL_COUNT; i++) {
+ if (val_bits & val_enum_to_bit(i)) {
+ if (or) strcat(buf, " | ");
+ strcat(buf, "val_enum_to_bit(");
+ strcat(buf, val_names[i].enum_name);
+ strcat(buf, ")");
+ or = 1;
+ }
+ }
+
+ return buf;
+}
+
+/*
+ * When bits for foo_LVP and bar_LVP are both set in bits, print:
+ * lvp_enum_to_bit(foo_LVP) | lvp_enum_to_bit(bar_LVP)
+ */
+
+static char *lvp_bits_to_str(uint64_t bits)
+{
+ static char lvp_buf[1024];
+ int i;
+ int or = 0;
+
+ memset(lvp_buf, 0, sizeof(lvp_buf));
+
+ for (i = 0; i < LVP_COUNT; i++) {
+ if (bits & lvp_enum_to_bit(i)) {
+ if (or) strcat(lvp_buf, " | ");
+ strcat(lvp_buf, "lvp_enum_to_bit(");
+ strcat(lvp_buf, lvp_names[i].enum_name);
+ strcat(lvp_buf, ")");
+ or = 1;
+ }
+ }
+
+ return lvp_buf;
+}
+
+/*
+ * When bits for foo_LVT and bar_LVT are both set in bits, print:
+ * lvt_enum_to_bit(foo_LVT) | lvt_enum_to_bit(bar_LVT)
+ */
+
+static char *lvt_bits_to_str(uint64_t bits)
+{
+ static char lvt_buf[1024];
+ int i;
+ int or = 0;
+
+ memset(lvt_buf, 0, sizeof(lvt_buf));
+
+ for (i = 1; i < LVT_COUNT; i++) {
+ if (bits & lvt_enum_to_bit(i)) {
+ if (or) strcat(lvt_buf, " | ");
+ strcat(lvt_buf, "lvt_enum_to_bit(");
+ strcat(lvt_buf, lvt_names[i].enum_name);
+ strcat(lvt_buf, ")");
+ or = 1;
+ }
+ }
+
+ return lvt_buf;
+}
+
+static void print_def(struct arg_def *def, int usage)
+{
+ int val_enum;
+ int lvt_enum;
+ int sep = 0;
+ int i;
+
+ for (val_enum = 0; val_enum < VAL_COUNT; val_enum++) {
+ if (def->val_bits & val_enum_to_bit(val_enum)) {
+
+ if (val_enum == conststr_VAL)
+ printf("%s", def->str);
+
+ else if (val_enum == constnum_VAL)
+ printf("%llu", (unsigned long long)def->num);
+
+ else {
+ if (sep) printf("|");
+
+ if (!usage || !val_names[val_enum].usage)
+ printf("%s", val_names[val_enum].name);
+ else
+ printf("%s", val_names[val_enum].usage);
+
+ sep = 1;
+ }
+
+ if (val_enum == lv_VAL && def->lvt_bits) {
+ for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
+ if (lvt_bit_is_set(def->lvt_bits, lvt_enum))
+ printf("_%s", lvt_enum_to_name(lvt_enum));
+ }
+ }
+
+ if ((val_enum == vg_VAL) && (def->flags & ARG_DEF_FLAG_NEW_VG))
+ printf("_new");
+ if ((val_enum == lv_VAL) && (def->flags & ARG_DEF_FLAG_NEW_LV))
+ printf("_new");
+ }
+ }
+
+ if (def->flags & ARG_DEF_FLAG_MAY_REPEAT)
+ printf(" ...");
+}
+
+static int opt_arg_matches(struct opt_arg *oa1, struct opt_arg *oa2)
+{
+ if (oa1->opt != oa2->opt)
+ return 0;
+
+ /* FIXME: some cases may need more specific val_bits checks */
+ if (oa1->def.val_bits != oa2->def.val_bits)
+ return 0;
+
+ if (oa1->def.str && oa2->def.str && strcmp(oa1->def.str, oa2->def.str))
+ return 0;
+
+ if (oa1->def.num != oa2->def.num)
+ return 0;
+
+ /*
+ * Do NOT compare lv_types because we are checking if two
+ * command lines are ambiguous before the LV type is known.
+ */
+
+ return 1;
+}
+
+static int pos_arg_matches(struct pos_arg *pa1, struct pos_arg *pa2)
+{
+ if (pa1->pos != pa2->pos)
+ return 0;
+
+ /* FIXME: some cases may need more specific val_bits checks */
+ if (pa1->def.val_bits != pa2->def.val_bits)
+ return 0;
+
+ if (pa1->def.str && pa2->def.str && strcmp(pa1->def.str, pa2->def.str))
+ return 0;
+
+ if (pa1->def.num != pa2->def.num)
+ return 0;
+
+ /*
+ * Do NOT compare lv_types because we are checking if two
+ * command lines are ambiguous before the LV type is known.
+ */
+
+ return 1;
+}
+
+static const char *opt_to_enum_str(int opt)
+{
+ return opt_names[opt].name;
+}
+
+static char *flags_to_str(int flags)
+{
+ static char buf_flags[32];
+
+ memset(buf_flags, 0, sizeof(buf_flags));
+
+ if (flags & ARG_DEF_FLAG_MAY_REPEAT) {
+ if (buf_flags[0])
+ strcat(buf_flags, " | ");
+ strcat(buf_flags, "ARG_DEF_FLAG_MAY_REPEAT");
+ }
+ if (flags & ARG_DEF_FLAG_NEW_VG) {
+ if (buf_flags[0])
+ strcat(buf_flags, " | ");
+ strcat(buf_flags, "ARG_DEF_FLAG_NEW_VG");
+ }
+ if (flags & ARG_DEF_FLAG_NEW_LV) {
+ if (buf_flags[0])
+ strcat(buf_flags, " | ");
+ strcat(buf_flags, "ARG_DEF_FLAG_NEW_LV");
+ }
+
+ return buf_flags;
+}
+
+static char *rule_to_define_str(int rule_type)
+{
+ switch (rule_type) {
+ case RULE_INVALID:
+ return "RULE_INVALID";
+ case RULE_REQUIRE:
+ return "RULE_REQUIRE";
+ }
+}
+
+static char *cmd_flags_to_str(uint32_t flags)
+{
+ static char buf_cmd_flags[32];
+
+ memset(buf_cmd_flags, 0, sizeof(buf_cmd_flags));
+
+ if (flags & CMD_FLAG_SECONDARY_SYNTAX) {
+ if (buf_cmd_flags[0])
+ strcat(buf_cmd_flags, " | ");
+ strcat(buf_cmd_flags, "CMD_FLAG_SECONDARY_SYNTAX");
+ }
+ if (flags & CMD_FLAG_ONE_REQUIRED_OPT) {
+ if (buf_cmd_flags[0])
+ strcat(buf_cmd_flags, " | ");
+ strcat(buf_cmd_flags, "CMD_FLAG_ONE_REQUIRED_OPT");
+ }
+
+ return buf_cmd_flags;
+}
+
+static void print_usage_common(struct command *cmd)
+{
+ struct cmd_name *cname;
+ int i, sep, ro, rp, oo, op, opt_enum;
+
+ if (!(cname = find_command_name(cmd->name)))
+ return;
+
+ sep = 0;
+
+ /*
+ * when there's more than one variant, options that
+ * are common to all commands with a common name.
+ */
+
+ if (cname->variants < 2)
+ goto all;
+
+ for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
+ if (!cname->common_options[opt_enum])
+ continue;
+
+ if (is_lvm_all_opt(opt_enum))
+ continue;
+
+ if (!sep) {
+ printf("\n");
+ printf("\" [");
+ } else {
+ printf(",");
+ }
+
+ for (oo = 0; oo < cmd->oo_count; oo++) {
+ if (cmd->optional_opt_args[oo].opt != opt_enum)
+ continue;
+
+ printf(" %s", opt_names[opt_enum].long_opt);
+ if (cmd->optional_opt_args[oo].def.val_bits) {
+ printf(" ");
+ print_def(&cmd->optional_opt_args[oo].def, 1);
+ }
+ sep = 1;
+ break;
+ }
+ }
+
+ all:
+ /* options that are common to all lvm commands */
+
+ for (oo = 0; oo < lvm_all.oo_count; oo++) {
+ opt_enum = lvm_all.optional_opt_args[oo].opt;
+
+ if (!sep) {
+ printf("\n");
+ printf("\" [");
+ } else {
+ printf(",");
+ }
+
+ printf(" %s", opt_names[opt_enum].long_opt);
+ if (lvm_all.optional_opt_args[oo].def.val_bits) {
+ printf(" ");
+ print_def(&lvm_all.optional_opt_args[oo].def, 1);
+ }
+ sep = 1;
+ }
+
+ printf(" ]\"");
+ printf(";\n");
+}
+
+static void print_usage(struct command *cmd)
+{
+ struct cmd_name *cname;
+ int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
+ int i, sep, ro, rp, oo, op, opt_enum;
+
+ if (!(cname = find_command_name(cmd->name)))
+ return;
+
+ printf("\"%s", cmd->name);
+
+ if (cmd->ro_count) {
+ if (onereq)
+ printf(" (");
+ for (ro = 0; ro < cmd->ro_count; ro++) {
+ if (ro && onereq)
+ printf(",");
+ printf(" %s", opt_names[cmd->required_opt_args[ro].opt].long_opt);
+
+ if (cmd->required_opt_args[ro].def.val_bits) {
+ printf(" ");
+ print_def(&cmd->required_opt_args[ro].def, 1);
+ }
+ }
+ if (onereq)
+ printf(" )");
+ }
+
+ if (cmd->rp_count) {
+ for (rp = 0; rp < cmd->rp_count; rp++) {
+ if (cmd->required_pos_args[rp].def.val_bits) {
+ printf(" ");
+ print_def(&cmd->required_pos_args[rp].def, 1);
+ }
+ }
+ }
+
+ printf("\"");
+
+ oo_count:
+ if (!cmd->oo_count)
+ goto op_count;
+
+ sep = 0;
+
+ if (cmd->oo_count) {
+ printf("\n");
+ printf("\" [");
+
+ for (oo = 0; oo < cmd->oo_count; oo++) {
+ opt_enum = cmd->optional_opt_args[oo].opt;
+
+ /*
+ * Skip common opts which are in the usage_common string.
+ * The common opts are those in lvm_all and in
+ * cname->common_options.
+ */
+
+ if (is_lvm_all_opt(opt_enum))
+ continue;
+
+ if ((cname->variants > 1) && cname->common_options[opt_enum])
+ continue;
+
+ if (sep)
+ printf(",");
+
+ printf(" %s", opt_names[opt_enum].long_opt);
+ if (cmd->optional_opt_args[oo].def.val_bits) {
+ printf(" ");
+ print_def(&cmd->optional_opt_args[oo].def, 1);
+ }
+ sep = 1;
+ }
+
+ if (sep)
+ printf(",");
+ printf(" COMMON_OPTIONS");
+ printf(" ]\"");
+ }
+
+ op_count:
+ if (!cmd->op_count)
+ goto done;
+
+ printf("\n");
+ printf("\" [");
+
+ if (cmd->op_count) {
+ for (op = 0; op < cmd->op_count; op++) {
+ if (cmd->optional_pos_args[op].def.val_bits) {
+ printf(" ");
+ print_def(&cmd->optional_pos_args[op].def, 1);
+ }
+ }
+ }
+
+ printf(" ]\"");
+
+ done:
+ printf(";\n");
+}
+
+void print_header_struct(void)
+{
+ struct command *cmd;
+ int i, j, ro, rp, oo, op, ru, ruo, io;
+
+ printf("/* Do not edit. This file is generated by tools/create-commands */\n");
+ printf("/* using command definitions from tools/command-lines.in */\n");
+ printf("\n");
+
+ for (i = 0; i < cmd_count; i++) {
+ cmd = &cmd_array[i];
+
+ printf("commands[%d].name = \"%s\";\n", i, cmd->name);
+ printf("commands[%d].command_line_id = \"%s\";\n", i, cmd->command_line_id);
+ printf("commands[%d].command_line_enum = %s_CMD;\n", i, cmd->command_line_id);
+ printf("commands[%d].fn = %s;\n", i, cmd->name);
+ printf("commands[%d].ro_count = %d;\n", i, cmd->ro_count);
+ printf("commands[%d].rp_count = %d;\n", i, cmd->rp_count);
+ printf("commands[%d].oo_count = %d;\n", i, cmd->oo_count);
+ printf("commands[%d].op_count = %d;\n", i, cmd->op_count);
+ printf("commands[%d].io_count = %d;\n", i, cmd->io_count);
+ printf("commands[%d].rule_count = %d;\n", i, cmd->rule_count);
+
+ if (cmd->cmd_flags)
+ printf("commands[%d].cmd_flags = %s;\n", i, cmd_flags_to_str(cmd->cmd_flags));
+ else
+ printf("commands[%d].cmd_flags = 0;\n", i, cmd_flags_to_str(cmd->cmd_flags));
+
+ printf("commands[%d].desc = \"%s\";\n", i, cmd->desc ?: "");
+ printf("commands[%d].usage = ", i);
+ print_usage(cmd);
+
+ if (cmd->oo_count) {
+ printf("commands[%d].usage_common = ", i);
+ print_usage_common(cmd);
+ } else {
+ printf("commands[%d].usage_common = \"NULL\";\n", i);
+ }
+
+ if (cmd->ro_count) {
+ for (ro = 0; ro < cmd->ro_count; ro++) {
+ printf("commands[%d].required_opt_args[%d].opt = %s;\n",
+ i, ro, opt_to_enum_str(cmd->required_opt_args[ro].opt));
+
+ if (!cmd->required_opt_args[ro].def.val_bits)
+ continue;
+
+ printf("commands[%d].required_opt_args[%d].def.val_bits = %s;\n",
+ i, ro, val_bits_to_str(cmd->required_opt_args[ro].def.val_bits));
+
+ if (cmd->required_opt_args[ro].def.lvt_bits)
+ printf("commands[%d].required_opt_args[%d].def.lvt_bits = %s;\n",
+ i, ro, lvt_bits_to_str(cmd->required_opt_args[ro].def.lvt_bits));
+
+ if (cmd->required_opt_args[ro].def.flags)
+ printf("commands[%d].required_opt_args[%d].def.flags = %s;\n",
+ i, ro, flags_to_str(cmd->required_opt_args[ro].def.flags));
+
+ if (val_bit_is_set(cmd->required_opt_args[ro].def.val_bits, constnum_VAL))
+ printf("commands[%d].required_opt_args[%d].def.num = %d;\n",
+ i, ro, cmd->required_opt_args[ro].def.num);
+
+ if (val_bit_is_set(cmd->required_opt_args[ro].def.val_bits, conststr_VAL))
+ printf("commands[%d].required_opt_args[%d].def.str = \"%s\";\n",
+ i, ro, cmd->required_opt_args[ro].def.str ?: "NULL");
+ }
+ }
+
+ if (cmd->rp_count) {
+ for (rp = 0; rp < cmd->rp_count; rp++) {
+ printf("commands[%d].required_pos_args[%d].pos = %d;\n",
+ i, rp, cmd->required_pos_args[rp].pos);
+
+ if (!cmd->required_pos_args[rp].def.val_bits)
+ continue;
+
+ printf("commands[%d].required_pos_args[%d].def.val_bits = %s;\n",
+ i, rp, val_bits_to_str(cmd->required_pos_args[rp].def.val_bits));
+
+ if (cmd->required_pos_args[rp].def.lvt_bits)
+ printf("commands[%d].required_pos_args[%d].def.lvt_bits = %s;\n",
+ i, rp, lvt_bits_to_str(cmd->required_pos_args[rp].def.lvt_bits));
+
+ if (cmd->required_pos_args[rp].def.flags)
+ printf("commands[%d].required_pos_args[%d].def.flags = %s;\n",
+ i, rp, flags_to_str(cmd->required_pos_args[rp].def.flags));
+
+ if (val_bit_is_set(cmd->required_pos_args[rp].def.val_bits, constnum_VAL))
+ printf("commands[%d].required_pos_args[%d].def.num = %d;\n",
+ i, rp, cmd->required_pos_args[rp].def.num);
+
+ if (val_bit_is_set(cmd->required_pos_args[rp].def.val_bits, conststr_VAL))
+ printf("commands[%d].required_pos_args[%d].def.str = \"%s\";\n",
+ i, rp, cmd->required_pos_args[rp].def.str ?: "NULL");
+ }
+ }
+
+ if (cmd->oo_count) {
+ for (oo = 0; oo < cmd->oo_count; oo++) {
+ printf("commands[%d].optional_opt_args[%d].opt = %s;\n",
+ i, oo, opt_to_enum_str(cmd->optional_opt_args[oo].opt));
+
+ if (!cmd->optional_opt_args[oo].def.val_bits)
+ continue;
+
+ printf("commands[%d].optional_opt_args[%d].def.val_bits = %s;\n",
+ i, oo, val_bits_to_str(cmd->optional_opt_args[oo].def.val_bits));
+
+ if (cmd->optional_opt_args[oo].def.lvt_bits)
+ printf("commands[%d].optional_opt_args[%d].def.lvt_bits = %s;\n",
+ i, oo, lvt_bits_to_str(cmd->optional_opt_args[oo].def.lvt_bits));
+
+ if (cmd->optional_opt_args[oo].def.flags)
+ printf("commands[%d].optional_opt_args[%d].def.flags = %s;\n",
+ i, oo, flags_to_str(cmd->optional_opt_args[oo].def.flags));
+
+ if (val_bit_is_set(cmd->optional_opt_args[oo].def.val_bits, constnum_VAL))
+ printf("commands[%d].optional_opt_args[%d].def.num = %d;\n",
+ i, oo, cmd->optional_opt_args[oo].def.num);
+
+ if (val_bit_is_set(cmd->optional_opt_args[oo].def.val_bits, conststr_VAL))
+ printf("commands[%d].optional_opt_args[%d].def.str = \"%s\";\n",
+ i, oo, cmd->optional_opt_args[oo].def.str ?: "NULL");
+ }
+ }
+
+ if (cmd->io_count) {
+ for (io = 0; io < cmd->io_count; io++) {
+ printf("commands[%d].ignore_opt_args[%d].opt = %s;\n",
+ i, io, opt_to_enum_str(cmd->ignore_opt_args[io].opt));
+
+ if (!cmd->ignore_opt_args[io].def.val_bits)
+ continue;
+
+ printf("commands[%d].ignore_opt_args[%d].def.val_bits = %s;\n",
+ i, io, val_bits_to_str(cmd->ignore_opt_args[io].def.val_bits));
+
+ if (cmd->ignore_opt_args[io].def.lvt_bits)
+ printf("commands[%d].ignore_opt_args[%d].def.lvt_bits = %s;\n",
+ i, io, lvt_bits_to_str(cmd->ignore_opt_args[io].def.lvt_bits));
+
+ if (cmd->ignore_opt_args[io].def.flags)
+ printf("commands[%d].ignore_opt_args[%d].def.flags = %s;\n",
+ i, io, flags_to_str(cmd->ignore_opt_args[io].def.flags));
+
+ if (val_bit_is_set(cmd->ignore_opt_args[io].def.val_bits, constnum_VAL))
+ printf("commands[%d].ignore_opt_args[%d].def.num = %d;\n",
+ i, io, cmd->ignore_opt_args[io].def.num);
+
+ if (val_bit_is_set(cmd->ignore_opt_args[io].def.val_bits, conststr_VAL))
+ printf("commands[%d].ignore_opt_args[%d].def.str = \"%s\";\n",
+ i, io, cmd->ignore_opt_args[io].def.str ?: "NULL");
+ }
+ }
+
+ if (cmd->op_count) {
+ for (op = 0; op < cmd->op_count; op++) {
+ printf("commands[%d].optional_pos_args[%d].pos = %d;\n",
+ i, op, cmd->optional_pos_args[op].pos);
+
+ if (!cmd->optional_pos_args[op].def.val_bits)
+ continue;
+
+ printf("commands[%d].optional_pos_args[%d].def.val_bits = %s;\n",
+ i, op, val_bits_to_str(cmd->optional_pos_args[op].def.val_bits));
+
+ if (cmd->optional_pos_args[op].def.lvt_bits)
+ printf("commands[%d].optional_pos_args[%d].def.lvt_bits = %s;\n",
+ i, op, lvt_bits_to_str(cmd->optional_pos_args[op].def.lvt_bits));
+
+ if (cmd->optional_pos_args[op].def.flags)
+ printf("commands[%d].optional_pos_args[%d].def.flags = %s;\n",
+ i, op, flags_to_str(cmd->optional_pos_args[op].def.flags));
+
+ if (val_bit_is_set(cmd->optional_pos_args[op].def.val_bits, constnum_VAL))
+ printf("commands[%d].optional_pos_args[%d].def.num = %d;\n",
+ i, op, cmd->optional_pos_args[op].def.num);
+
+ if (val_bit_is_set(cmd->optional_pos_args[op].def.val_bits, conststr_VAL))
+ printf("commands[%d].optional_pos_args[%d].def.str = \"%s\";\n",
+ i, op, cmd->optional_pos_args[op].def.str ?: "NULL");
+ }
+ }
+
+ if (cmd->rule_count) {
+ for (ru = 0; ru < cmd->rule_count; ru++) {
+
+ printf("commands[%d].rules[%d].opts_count = %d;\n", i, ru, cmd->rules[ru].opts_count);
+
+ if (cmd->rules[ru].opts_count) {
+ printf("static int _command%d_rule%d_opts[] = { ", i, ru);
+ for (ruo = 0; ruo < cmd->rules[ru].opts_count; ruo++) {
+ if (ruo)
+ printf(", ");
+ printf("%s", opt_to_enum_str(cmd->rules[ru].opts[ruo]));
+ }
+ printf(" };\n");
+ printf("commands[%d].rules[%d].opts = _command%d_rule%d_opts;\n", i, ru, i, ru);
+ } else {
+ printf("commands[%d].rules[%d].opts = NULL;\n", i, ru);
+ }
+
+ printf("commands[%d].rules[%d].check_opts_count = %d;\n", i, ru, cmd->rules[ru].check_opts_count);
+
+ if (cmd->rules[ru].check_opts_count) {
+ printf("static int _command%d_rule%d_check_opts[] = { ", i, ru);
+ for (ruo = 0; ruo < cmd->rules[ru].check_opts_count; ruo++) {
+ if (ruo)
+ printf(",");
+ printf("%s ", opt_to_enum_str(cmd->rules[ru].check_opts[ruo]));
+ }
+ printf(" };\n");
+ printf("commands[%d].rules[%d].check_opts = _command%d_rule%d_check_opts;\n", i, ru, i, ru);
+ } else {
+ printf("commands[%d].rules[%d].check_opts = NULL;\n", i, ru);
+ }
+
+ printf("commands[%d].rules[%d].lvt_bits = %s;\n", i, ru,
+ cmd->rules[ru].lvt_bits ? lvt_bits_to_str(cmd->rules[ru].lvt_bits) : "0");
+
+ printf("commands[%d].rules[%d].lvp_bits = %s;\n", i, ru,
+ cmd->rules[ru].lvp_bits ? lvp_bits_to_str(cmd->rules[ru].lvp_bits) : "0");
+
+ printf("commands[%d].rules[%d].rule = %s;\n", i, ru,
+ rule_to_define_str(cmd->rules[ru].rule));
+
+ printf("commands[%d].rules[%d].check_lvt_bits = %s;\n", i, ru,
+ cmd->rules[ru].check_lvt_bits ? lvt_bits_to_str(cmd->rules[ru].check_lvt_bits) : "0");
+
+ printf("commands[%d].rules[%d].check_lvp_bits = %s;\n", i, ru,
+ cmd->rules[ru].check_lvp_bits ? lvp_bits_to_str(cmd->rules[ru].check_lvp_bits) : "0");
+ }
+ }
+
+ printf("\n");
+ }
+}
+
+void print_header_count(void)
+{
+ struct command *cmd;
+ int i, j;
+
+ printf("/* Do not edit. This file is generated by tools/create-commands */\n");
+ printf("/* using command definitions from tools/command-lines.in */\n");
+ printf("#define COMMAND_COUNT %d\n", cmd_count);
+
+ printf("enum {\n");
+ printf("\tno_CMD,\n"); /* enum value 0 is not used */
+
+ for (i = 0; i < cmd_count; i++) {
+ cmd = &cmd_array[i];
+
+ if (!cmd->command_line_id) {
+ printf("Missing ID: at %d\n", i);
+ exit(1);
+ }
+
+ for (j = 0; j < i; j++) {
+ if (!strcmp(cmd->command_line_id, cmd_array[j].command_line_id))
+ goto next;
+ }
+
+ printf("\t%s_CMD,\n", cmd->command_line_id);
+ next:
+ ;
+ }
+ printf("\tCOMMAND_ID_COUNT,\n");
+ printf("};\n");
+}
+
+struct cmd_pair {
+ int i, j;
+};
+
+void print_ambiguous(void)
+{
+ struct command *cmd, *dup;
+ struct cmd_pair dups[64] = { 0 };
+ int found = 0;
+ int i, j, f, ro, rp;
+
+ for (i = 0; i < cmd_count; i++) {
+ cmd = &cmd_array[i];
+
+ for (j = 0; j < cmd_count; j++) {
+ dup = &cmd_array[j];
+
+ if (i == j)
+ continue;
+ if (strcmp(cmd->name, dup->name))
+ continue;
+ if (cmd->ro_count != dup->ro_count)
+ continue;
+ if (cmd->rp_count != dup->rp_count)
+ continue;
+
+ for (ro = 0; ro < cmd->ro_count; ro++) {
+ if (!opt_arg_matches(&cmd->required_opt_args[ro],
+ &dup->required_opt_args[ro]))
+ goto next;
+ }
+
+ for (rp = 0; rp < cmd->rp_count; rp++) {
+ if (!pos_arg_matches(&cmd->required_pos_args[rp],
+ &dup->required_pos_args[rp]))
+ goto next;
+ }
+
+ for (f = 0; f < found; f++) {
+ if ((dups[f].i == j) && (dups[f].j == i))
+ goto next;
+ }
+
+ printf("Ambiguous commands %d and %d:\n", i, j);
+ print_usage(cmd);
+ print_usage(dup);
+ printf("\n");
+
+ dups[found].i = i;
+ dups[found].j = j;
+ found++;
+next:
+ ;
+ }
+ }
+}
+
diff --git a/tools/ccmd.h b/tools/ccmd.h
new file mode 100644
index 0000000..1e18125
--- /dev/null
+++ b/tools/ccmd.h
@@ -0,0 +1,144 @@
+
+#ifndef __CCMD_H__
+#define __CCMD_H__
+
+/* needed to include args.h */
+#define ARG_COUNTABLE 0x00000001
+#define ARG_GROUPABLE 0x00000002
+struct cmd_context;
+struct arg_values;
+
+/* needed to include args.h */
+static inline int yes_no_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int activation_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int cachemode_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int discards_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int mirrorlog_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int size_kb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int size_mb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int int_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int uint32_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int major_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int minor_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int string_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int tag_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int permission_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int metadatatype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int units_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int segtype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int alloc_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int locktype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int readahead_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+static inline int vgmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
+static inline int pvmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
+static inline int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
+static inline int polloperation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
+static inline int writemostly_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
+static inline int syncaction_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
+static inline int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
+static inline int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
+static inline int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
+
+/* also see arg_props in tools.h and args.h */
+struct opt_name {
+ const char *name; /* "foo_ARG" */
+ int opt_enum; /* foo_ARG */
+ const char short_opt; /* -f */
+ char _padding[7];
+ const char *long_opt; /* --foo */
+ int val_enum; /* xyz_VAL when --foo takes a val like "--foo xyz" */
+ uint32_t unused1;
+ uint32_t unused2;
+ const char *desc;
+};
+
+/* also see val_props in tools.h and vals.h */
+struct val_name {
+ const char *enum_name; /* "foo_VAL" */
+ int val_enum; /* foo_VAL */
+ int (*fn) (struct cmd_context *cmd, struct arg_values *av); /* foo_arg() */
+ const char *name; /* FooVal */
+ const char *usage;
+};
+
+/* also see lv_props in tools.h and lv_props.h */
+struct lvp_name {
+ const char *enum_name; /* "is_foo_LVP" */
+ int lvp_enum; /* is_foo_LVP */
+ const char *name; /* "lv_is_foo" */
+};
+
+/* also see lv_types in tools.h and lv_types.h */
+struct lvt_name {
+ const char *enum_name; /* "foo_LVT" */
+ int lvt_enum; /* foo_LVT */
+ const char *name; /* "foo" */
+};
+
+/* create foo_VAL enums for option and position values */
+
+enum {
+#define val(a, b, c, d) a ,
+#include "vals.h"
+#undef val
+};
+
+/* create foo_ARG enums for --option's */
+
+enum {
+#define arg(a, b, c, d, e, f, g) a ,
+#include "args.h"
+#undef arg
+};
+
+/* create foo_LVP enums for LV properties */
+
+enum {
+#define lvp(a, b, c) a,
+#include "lv_props.h"
+#undef lvp
+};
+
+/* create foo_LVT enums for LV types */
+
+enum {
+#define lvt(a, b, c) a,
+#include "lv_types.h"
+#undef lvt
+};
+
+/* one for each command name, see cmd_names[] */
+
+#define MAX_CMD_NAMES 128
+struct cmd_name {
+ const char *name;
+ const char *desc;
+ int common_options[ARG_COUNT + 1]; /* options common to all defs */
+ int all_options[ARG_COUNT + 1]; /* union of options from all defs */
+ int variants; /* number of command defs with this command name */
+ int variant_has_ro; /* do variants use required_opt_args ? */
+ int variant_has_rp; /* do variants use required_pos_args ? */
+ int variant_has_oo; /* do variants use optional_opt_args ? */
+ int variant_has_op; /* do variants use optional_pos_args ? */
+};
+
+/* struct command */
+
+#include "command.h"
+
+/* one for each command defininition (command-lines.in as struct command) */
+
+#define MAX_CMDS 256
+int cmd_count;
+struct command cmd_array[MAX_CMDS];
+
+#define MAX_LINE 1024
+#define MAX_LINE_ARGC 256
+
+#define DESC_LINE 256
+
+#endif
+
diff --git a/tools/create-commands.c b/tools/create-commands.c
deleted file mode 100644
index f9ff800..0000000
--- a/tools/create-commands.c
+++ /dev/null
@@ -1,3169 +0,0 @@
-#include <asm/types.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <sched.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <getopt.h>
-
-/* needed to include args.h */
-#define ARG_COUNTABLE 0x00000001
-#define ARG_GROUPABLE 0x00000002
-struct cmd_context;
-struct arg_values;
-
-int yes_no_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int activation_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int cachemode_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int discards_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int mirrorlog_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int size_kb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int size_mb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int int_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int uint32_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int major_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int minor_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int string_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int tag_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int permission_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int metadatatype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int units_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int segtype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int alloc_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int locktype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int readahead_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
-int vgmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
-int pvmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
-int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
-int polloperation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
-int writemostly_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
-int syncaction_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
-int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
-int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
-int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
-
-/* also see arg_props in tools.h and args.h */
-struct opt_name {
- const char *name; /* "foo_ARG" */
- int opt_enum; /* foo_ARG */
- const char short_opt; /* -f */
- char _padding[7];
- const char *long_opt; /* --foo */
- int val_enum; /* xyz_VAL when --foo takes a val like "--foo xyz" */
- uint32_t unused1;
- uint32_t unused2;
- const char *desc;
-};
-
-/* also see val_props in tools.h and vals.h */
-struct val_name {
- const char *enum_name; /* "foo_VAL" */
- int val_enum; /* foo_VAL */
- int (*fn) (struct cmd_context *cmd, struct arg_values *av); /* foo_arg() */
- const char *name; /* FooVal */
- const char *usage;
-};
-
-/* also see lv_props in tools.h and lv_props.h */
-struct lvp_name {
- const char *enum_name; /* "is_foo_LVP" */
- int lvp_enum; /* is_foo_LVP */
- const char *name; /* "lv_is_foo" */
-};
-
-/* also see lv_types in tools.h and lv_types.h */
-struct lvt_name {
- const char *enum_name; /* "foo_LVT" */
- int lvt_enum; /* foo_LVT */
- const char *name; /* "foo" */
-};
-
-/* create foo_VAL enums for option and position values */
-
-enum {
-#define val(a, b, c, d) a ,
-#include "vals.h"
-#undef val
-};
-
-/* create foo_ARG enums for --option's */
-
-enum {
-#define arg(a, b, c, d, e, f, g) a ,
-#include "args.h"
-#undef arg
-};
-
-/* create foo_LVP enums for LV properties */
-
-enum {
-#define lvp(a, b, c) a,
-#include "lv_props.h"
-#undef lvp
-};
-
-/* create foo_LVT enums for LV types */
-
-enum {
-#define lvt(a, b, c) a,
-#include "lv_types.h"
-#undef lvt
-};
-
-/* create table of value names, e.g. String, and corresponding enum from vals.h */
-
-static struct val_name val_names[VAL_COUNT + 1] = {
-#define val(a, b, c, d) { # a, a, b, c, d },
-#include "vals.h"
-#undef val
-};
-
-/* create table of option names, e.g. --foo, and corresponding enum from args.h */
-
-static struct opt_name opt_names[ARG_COUNT + 1] = {
-#define arg(a, b, c, d, e, f, g) { # a, a, b, "", "--" c, d, e, f, g },
-#include "args.h"
-#undef arg
-};
-
-/* create table of lv property names, e.g. lv_is_foo, and corresponding enum from lv_props.h */
-
-static struct lvp_name lvp_names[LVP_COUNT + 1] = {
-#define lvp(a, b, c) { # a, a, b },
-#include "lv_props.h"
-#undef lvp
-};
-
-/* create table of lv type names, e.g. linear and corresponding enum from lv_types.h */
-
-static struct lvt_name lvt_names[LVT_COUNT + 1] = {
-#define lvt(a, b, c) { # a, a, b },
-#include "lv_types.h"
-#undef lvt
-};
-
-#include "command.h"
-
-#define MAX_CMD_NAMES 128
-struct cmd_name {
- const char *name;
- const char *desc;
- int common_options[ARG_COUNT + 1];
- int all_options[ARG_COUNT + 1];
- int variants;
- int variant_has_ro;
- int variant_has_rp;
- int variant_has_oo;
- int variant_has_op;
-};
-
-/* create table of command names, e.g. vgcreate */
-
-static struct cmd_name cmd_names[MAX_CMD_NAMES] = {
-#define xx(a, b, c) { # a , b } ,
-#include "commands.h"
-#undef xx
-};
-
-/* array of pointers into opt_names[] that is sorted alphabetically (by long opt name) */
-
-static struct opt_name *opt_names_alpha[ARG_COUNT + 1];
-
-#define MAX_LINE 1024
-#define MAX_LINE_ARGC 256
-
-#define DESC_LINE 256
-
-#define REQUIRED 1 /* required option */
-#define OPTIONAL 0 /* optional option */
-#define IGNORE -1 /* ignore option */
-
-struct oo_line {
- char *name;
- char *line;
-};
-
-#define MAX_CMDS 256
-int cmd_count;
-struct command cmd_array[MAX_CMDS];
-
-struct command lvm_all; /* for printing common options for all lvm commands */
-
-#define MAX_OO_LINES 256
-int oo_line_count;
-struct oo_line oo_lines[MAX_OO_LINES];
-
-static int include_man_secondary = 1;
-static int include_man_primary = 1;
-static char *man_command_name = NULL;
-
-static void add_optional_opt_line(struct command *cmd, int argc, char *argv[]);
-
-/*
- * modifies buf, replacing the sep characters with \0
- * argv pointers point to positions in buf
- */
-
-static char *split_line(char *buf, int *argc, char **argv, char sep)
-{
- char *p = buf, *rp = NULL;
- int i;
-
- argv[0] = p;
-
- for (i = 1; i < MAX_LINE_ARGC; i++) {
- p = strchr(buf, sep);
- if (!p)
- break;
- *p = '\0';
-
- argv[i] = p + 1;
- buf = p + 1;
- }
- *argc = i;
-
- /* we ended by hitting \0, return the point following that */
- if (!rp)
- rp = strchr(buf, '\0') + 1;
-
- return rp;
-}
-
-/* convert value string, e.g. Number, to foo_VAL enum */
-
-static int val_str_to_num(char *str)
-{
- char name[32] = { 0 };
- char *new;
- int i;
-
- /* compare the name before any suffix like _new or _<lvtype> */
-
- strncpy(name, str, 31);
- if ((new = strstr(name, "_")))
- *new = '\0';
-
- for (i = 0; i < VAL_COUNT; i++) {
- if (!val_names[i].name)
- break;
- if (!strncmp(name, val_names[i].name, strlen(val_names[i].name)))
- return val_names[i].val_enum;
- }
-
- return 0;
-}
-
-/* convert "--option" to foo_ARG enum */
-
-static int opt_str_to_num(char *str)
-{
- char long_name[32];
- char *p;
- int i;
-
- /*
- * --foo_long means there are two args entries
- * for --foo, one with a short option and one
- * without, and we want the one without the
- * short option.
- */
- if (strstr(str, "_long")) {
- strcpy(long_name, str);
- p = strstr(long_name, "_long");
- *p = '\0';
-
- for (i = 0; i < ARG_COUNT; i++) {
- if (!opt_names[i].long_opt)
- continue;
- /* skip anything with a short opt */
- if (opt_names[i].short_opt)
- continue;
- if (!strcmp(opt_names[i].long_opt, long_name))
- return opt_names[i].opt_enum;
- }
-
- printf("Unknown opt str: %s %s\n", str, long_name);
- exit(1);
- }
-
- for (i = 0; i < ARG_COUNT; i++) {
- if (!opt_names[i].long_opt)
- continue;
- /* These are only selected using --foo_long */
- if (strstr(opt_names[i].name, "_long_ARG"))
- continue;
- if (!strcmp(opt_names[i].long_opt, str))
- return opt_names[i].opt_enum;
- }
-
- printf("Unknown opt str: \"%s\"\n", str);
- exit(1);
-}
-
-static char *val_bits_to_str(uint64_t val_bits)
-{
- static char buf[1024];
- int i;
- int or = 0;
-
- memset(buf, 0, sizeof(buf));
-
- for (i = 0; i < VAL_COUNT; i++) {
- if (val_bits & val_enum_to_bit(i)) {
- if (or) strcat(buf, " | ");
- strcat(buf, "val_enum_to_bit(");
- strcat(buf, val_names[i].enum_name);
- strcat(buf, ")");
- or = 1;
- }
- }
-
- return buf;
-}
-
-/*
- * When bits for foo_LVP and bar_LVP are both set in bits, print:
- * lvp_enum_to_bit(foo_LVP) | lvp_enum_to_bit(bar_LVP)
- */
-
-static char *lvp_bits_to_str(uint64_t bits)
-{
- static char lvp_buf[1024];
- int i;
- int or = 0;
-
- memset(lvp_buf, 0, sizeof(lvp_buf));
-
- for (i = 0; i < LVP_COUNT; i++) {
- if (bits & lvp_enum_to_bit(i)) {
- if (or) strcat(lvp_buf, " | ");
- strcat(lvp_buf, "lvp_enum_to_bit(");
- strcat(lvp_buf, lvp_names[i].enum_name);
- strcat(lvp_buf, ")");
- or = 1;
- }
- }
-
- return lvp_buf;
-}
-
-/*
- * When bits for foo_LVT and bar_LVT are both set in bits, print:
- * lvt_enum_to_bit(foo_LVT) | lvt_enum_to_bit(bar_LVT)
- */
-
-static char *lvt_bits_to_str(uint64_t bits)
-{
- static char lvt_buf[1024];
- int i;
- int or = 0;
-
- memset(lvt_buf, 0, sizeof(lvt_buf));
-
- for (i = 1; i < LVT_COUNT; i++) {
- if (bits & lvt_enum_to_bit(i)) {
- if (or) strcat(lvt_buf, " | ");
- strcat(lvt_buf, "lvt_enum_to_bit(");
- strcat(lvt_buf, lvt_names[i].enum_name);
- strcat(lvt_buf, ")");
- or = 1;
- }
- }
-
- return lvt_buf;
-}
-
-/* "lv_is_prop" to is_prop_LVP */
-
-static int lvp_name_to_enum(char *str)
-{
- int i;
-
- for (i = 1; i < LVP_COUNT; i++) {
- if (!strcmp(str, lvp_names[i].name))
- return lvp_names[i].lvp_enum;
- }
- printf("unknown lv property %s\n", str);
- exit(1);
-}
-
-/* type_LVT to "type" */
-
-static const char *lvt_enum_to_name(int lvt_enum)
-{
- return lvt_names[lvt_enum].name;
-}
-
-/* "type" to type_LVT */
-
-static int lvt_name_to_enum(char *str)
-{
- int i;
-
- for (i = 1; i < LVT_COUNT; i++) {
- if (!strcmp(str, lvt_names[i].name))
- return lvt_names[i].lvt_enum;
- }
- printf("unknown lv type %s\n", str);
- exit(1);
-}
-
-/* LV_<type> to <type>_LVT */
-
-int lv_to_enum(char *name)
-{
- return lvt_name_to_enum(name + 3);
-}
-
-/*
- * LV_<type1>_<type2> to lvt_bits
- *
- * type1 to lvt_enum
- * lvt_bits |= lvt_enum_to_bit(lvt_enum)
- * type2 to lvt_enum
- * lvt_bits |= lvt_enum_to_bit(lvt_enum)
- */
-
-uint64_t lv_to_bits(char *name)
-{
- char buf[64];
- char *argv[MAX_LINE_ARGC];
- uint64_t lvt_bits = 0;
- int lvt_enum;
- int argc;
- int i;
-
- strcpy(buf, name);
-
- split_line(buf, &argc, argv, '_');
-
- /* 0 is "LV" */
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "new"))
- continue;
- lvt_enum = lvt_name_to_enum(argv[i]);
- lvt_bits |= lvt_enum_to_bit(lvt_enum);
- }
-
- return lvt_bits;
-}
-
-static const char *is_command_name(char *str)
-{
- int i;
-
- for (i = 0; i < MAX_CMD_NAMES; i++) {
- if (!cmd_names[i].name)
- break;
- if (!strcmp(cmd_names[i].name, str))
- return cmd_names[i].name;
- }
- return NULL;
-}
-
-static const char *cmd_name_desc(const char *name)
-{
- int i;
-
- for (i = 0; i < MAX_CMD_NAMES; i++) {
- if (!cmd_names[i].name)
- break;
- if (!strcmp(cmd_names[i].name, name))
- return cmd_names[i].desc;
- }
- return NULL;
-}
-
-static struct cmd_name *find_command_name(const char *str)
-{
- int i;
-
- for (i = 0; i < MAX_CMD_NAMES; i++) {
- if (!cmd_names[i].name)
- break;
- if (!strcmp(cmd_names[i].name, str))
- return &cmd_names[i];
- }
- return NULL;
-}
-
-static int is_opt_name(char *str)
-{
- if (!strncmp(str, "--", 2))
- return 1;
-
- if ((str[0] == '-') && (str[1] != '-')) {
- printf("Options must be specified in long form: %s\n", str);
- exit(1);
- }
-
- return 0;
-}
-
-/*
- * "Select" as a pos name means that the position
- * can be empty if the --select option is used.
- */
-
-static int is_pos_name(char *str)
-{
- if (!strncmp(str, "VG", 2))
- return 1;
- if (!strncmp(str, "LV", 2))
- return 1;
- if (!strncmp(str, "PV", 2))
- return 1;
- if (!strncmp(str, "Tag", 3))
- return 1;
- if (!strncmp(str, "String", 6))
- return 1;
- if (!strncmp(str, "Select", 6))
- return 1;
- return 0;
-}
-
-static int is_oo_definition(char *str)
-{
- if (!strncmp(str, "OO_", 3) && strstr(str, ":"))
- return 1;
- return 0;
-}
-
-static int is_oo_line(char *str)
-{
- if (!strncmp(str, "OO:", 3))
- return 1;
- return 0;
-}
-
-static int is_io_line(char *str)
-{
- if (!strncmp(str, "IO:", 3))
- return 1;
- return 0;
-}
-
-static int is_op_line(char *str)
-{
- if (!strncmp(str, "OP:", 3))
- return 1;
- return 0;
-}
-
-static int is_desc_line(char *str)
-{
- if (!strncmp(str, "DESC:", 5))
- return 1;
- return 0;
-}
-
-static int is_flags_line(char *str)
-{
- if (!strncmp(str, "FLAGS:", 6))
- return 1;
- return 0;
-}
-
-static int is_rule_line(char *str)
-{
- if (!strncmp(str, "RULE:", 5))
- return 1;
- return 0;
-}
-
-static int is_id_line(char *str)
-{
- if (!strncmp(str, "ID:", 3))
- return 1;
- return 0;
-}
-
-/*
- * parse str for anything that can appear in a position,
- * like VG, VG|LV, VG|LV_linear|LV_striped, etc
- */
-
-static void set_pos_def(struct command *cmd, char *str, struct arg_def *def)
-{
- char *argv[MAX_LINE_ARGC];
- int argc;
- char *name;
- int val_enum;
- int i;
-
- split_line(str, &argc, argv, '|');
-
- for (i = 0; i < argc; i++) {
- name = argv[i];
-
- val_enum = val_str_to_num(name);
-
- if (!val_enum) {
- printf("Unknown pos arg: %s\n", name);
- exit(1);
- }
-
- def->val_bits |= val_enum_to_bit(val_enum);
-
- if ((val_enum == lv_VAL) && strstr(name, "_"))
- def->lvt_bits = lv_to_bits(name);
-
- if (strstr(name, "_new")) {
- if (val_enum == lv_VAL)
- def->flags |= ARG_DEF_FLAG_NEW_LV;
- else if (val_enum == vg_VAL)
- def->flags |= ARG_DEF_FLAG_NEW_VG;
- }
- }
-}
-
-/*
- * parse str for anything that can follow --option
- */
-
-static void set_opt_def(struct command *cmd, char *str, struct arg_def *def)
-{
- char *argv[MAX_LINE_ARGC];
- int argc;
- char *name;
- int val_enum;
- int i, j;
-
- split_line(str, &argc, argv, '|');
-
- for (i = 0; i < argc; i++) {
- name = argv[i];
-
- val_enum = val_str_to_num(name);
-
- if (!val_enum) {
- /* a literal number or string */
-
- if (isdigit(name[0]))
- val_enum = constnum_VAL;
-
- else if (isalpha(name[0]))
- val_enum = conststr_VAL;
-
- else {
- printf("Unknown opt arg: %s\n", name);
- exit(0);
- }
- }
-
-
- def->val_bits |= val_enum_to_bit(val_enum);
-
- if (val_enum == constnum_VAL)
- def->num = (uint64_t)atoi(name);
-
- if (val_enum == conststr_VAL)
- def->str = strdup(name);
-
- if (val_enum == lv_VAL) {
- if (strstr(name, "_"))
- def->lvt_bits = lv_to_bits(name);
- }
-
- if (strstr(name, "_new")) {
- if (val_enum == lv_VAL)
- def->flags |= ARG_DEF_FLAG_NEW_LV;
- else if (val_enum == vg_VAL)
- def->flags |= ARG_DEF_FLAG_NEW_VG;
-
- }
- }
-}
-
-
-/*
- * OO_FOO: --opt1 ...
- *
- * oo->name = "OO_FOO";
- * oo->line = "--opt1 ...";
- */
-
-static void add_oo_definition_line(const char *name, const char *line)
-{
- struct oo_line *oo;
- char *colon;
- char *start;
-
- oo = &oo_lines[oo_line_count++];
- oo->name = strdup(name);
-
- if ((colon = strstr(oo->name, ":")))
- *colon = '\0';
- else {
- printf("invalid OO definition\n");
- exit(1);
- }
-
- start = strstr(line, ":") + 2;
- oo->line = strdup(start);
-}
-
-/* when OO_FOO: continues on multiple lines */
-
-static void append_oo_definition_line(const char *new_line)
-{
- struct oo_line *oo;
- char *old_line;
- char *line;
- int len;
-
- oo = &oo_lines[oo_line_count-1];
-
- old_line = oo->line;
-
- /* +2 = 1 space between old and new + 1 terminating \0 */
- len = strlen(old_line) + strlen(new_line) + 2;
- line = malloc(len);
- memset(line, 0, len);
-
- strcat(line, old_line);
- strcat(line, " ");
- strcat(line, new_line);
-
- free(oo->line);
- oo->line = line;
-}
-
-char *get_oo_line(char *str)
-{
- char *name;
- char *end;
- char str2[64];
- int i;
-
- strcpy(str2, str);
- if ((end = strstr(str2, ":")))
- *end = '\0';
- if ((end = strstr(str2, ",")))
- *end = '\0';
-
- for (i = 0; i < oo_line_count; i++) {
- name = oo_lines[i].name;
- if (!strcmp(name, str2))
- return oo_lines[i].line;
- }
- return NULL;
-}
-
-/* add optional_opt_args entries when OO_FOO appears on OO: line */
-
-static void include_optional_opt_args(struct command *cmd, char *str)
-{
- char *oo_line;
- char *line;
- char *line_argv[MAX_LINE_ARGC];
- int line_argc;
-
- if (!(oo_line = get_oo_line(str))) {
- printf("No OO line found for %s\n", str);
- exit(1);
- }
-
- if (!(line = strdup(oo_line)))
- exit(1);
-
- split_line(line, &line_argc, line_argv, ' ');
- add_optional_opt_line(cmd, line_argc, line_argv);
- free(line);
-}
-
-static void add_opt_arg(struct command *cmd, char *str, int *takes_arg, int required)
-{
- char *comma;
- int opt;
-
- /* opt_arg.opt set here */
- /* opt_arg.def will be set in update_prev_opt_arg() if needed */
-
- if ((comma = strstr(str, ",")))
- *comma = '\0';
-
- /*
- * Work around nasty hack where --uuid is used for both uuid_ARG
- * and uuidstr_ARG. The input uses --uuidstr, where an actual
- * command uses --uuid string.
- */
- if (!strcmp(str, "--uuidstr")) {
- opt = uuidstr_ARG;
- goto skip;
- }
-
- opt = opt_str_to_num(str);
-skip:
- if (required > 0)
- cmd->required_opt_args[cmd->ro_count++].opt = opt;
- else if (!required)
- cmd->optional_opt_args[cmd->oo_count++].opt = opt;
- else if (required < 0)
- cmd->ignore_opt_args[cmd->io_count++].opt = opt;
- else
- exit(1);
-
- *takes_arg = opt_names[opt].val_enum ? 1 : 0;
-}
-
-static void update_prev_opt_arg(struct command *cmd, char *str, int required)
-{
- struct arg_def def = { 0 };
- char *comma;
-
- if (str[0] == '-') {
- printf("Option %s must be followed by an arg.\n", str);
- exit(1);
- }
-
- /* opt_arg.def set here */
- /* opt_arg.opt was previously set in add_opt_arg() when --foo was read */
-
- if ((comma = strstr(str, ",")))
- *comma = '\0';
-
- set_opt_def(cmd, str, &def);
-
- if (required > 0)
- cmd->required_opt_args[cmd->ro_count-1].def = def;
- else if (!required)
- cmd->optional_opt_args[cmd->oo_count-1].def = def;
- else if (required < 0)
- cmd->ignore_opt_args[cmd->io_count-1].def = def;
- else
- exit(1);
-}
-
-static void add_pos_arg(struct command *cmd, char *str, int required)
-{
- struct arg_def def = { 0 };
-
- /* pos_arg.pos and pos_arg.def are set here */
-
- set_pos_def(cmd, str, &def);
-
- if (required) {
- cmd->required_pos_args[cmd->rp_count].pos = cmd->pos_count++;
- cmd->required_pos_args[cmd->rp_count].def = def;
- cmd->rp_count++;
- } else {
- cmd->optional_pos_args[cmd->op_count].pos = cmd->pos_count++;;
- cmd->optional_pos_args[cmd->op_count].def = def;
- cmd->op_count++;
- }
-}
-
-/* process something that follows a pos arg, which is not a new pos arg */
-
-static void update_prev_pos_arg(struct command *cmd, char *str, int required)
-{
- struct arg_def *def;
-
- /* a previous pos_arg.def is modified here */
-
- if (required)
- def = &cmd->required_pos_args[cmd->rp_count-1].def;
- else
- def = &cmd->optional_pos_args[cmd->op_count-1].def;
-
- if (!strcmp(str, "..."))
- def->flags |= ARG_DEF_FLAG_MAY_REPEAT;
- else {
- printf("Unknown pos arg: %s\n", str);
- exit(1);
- }
-}
-
-/* process what follows OO:, which are optional opt args */
-
-static void add_optional_opt_line(struct command *cmd, int argc, char *argv[])
-{
- int takes_arg;
- int i;
-
- for (i = 0; i < argc; i++) {
- if (!i && !strncmp(argv[i], "OO:", 3))
- continue;
- if (is_opt_name(argv[i]))
- add_opt_arg(cmd, argv[i], &takes_arg, OPTIONAL);
- else if (!strncmp(argv[i], "OO_", 3))
- include_optional_opt_args(cmd, argv[i]);
- else if (takes_arg)
- update_prev_opt_arg(cmd, argv[i], OPTIONAL);
- else
- printf("Can't parse argc %d argv %s prev %s\n",
- i, argv[i], argv[i-1]);
- }
-}
-
-static void add_ignore_opt_line(struct command *cmd, int argc, char *argv[])
-{
- int takes_arg;
- int i;
-
- for (i = 0; i < argc; i++) {
- if (!i && !strncmp(argv[i], "IO:", 3))
- continue;
- if (is_opt_name(argv[i]))
- add_opt_arg(cmd, argv[i], &takes_arg, IGNORE);
- else if (takes_arg)
- update_prev_opt_arg(cmd, argv[i], IGNORE);
- else
- printf("Can't parse argc %d argv %s prev %s\n",
- i, argv[i], argv[i-1]);
- }
-}
-
-/* process what follows OP:, which are optional pos args */
-
-static void add_optional_pos_line(struct command *cmd, int argc, char *argv[])
-{
- int i;
-
- for (i = 0; i < argc; i++) {
- if (!i && !strncmp(argv[i], "OP:", 3))
- continue;
- if (is_pos_name(argv[i]))
- add_pos_arg(cmd, argv[i], OPTIONAL);
- else
- update_prev_pos_arg(cmd, argv[i], OPTIONAL);
- }
-}
-
-/* add required opt args from OO_FOO definition */
-
-static void add_required_opt_line(struct command *cmd, int argc, char *argv[])
-{
- int takes_arg;
- int i;
-
- for (i = 0; i < argc; i++) {
- if (is_opt_name(argv[i]))
- add_opt_arg(cmd, argv[i], &takes_arg, REQUIRED);
- else if (takes_arg)
- update_prev_opt_arg(cmd, argv[i], REQUIRED);
- else
- printf("Can't parse argc %d argv %s prev %s\n",
- i, argv[i], argv[i-1]);
- }
-}
-
-/* add to required_opt_args when OO_FOO appears on required line */
-
-static void include_required_opt_args(struct command *cmd, char *str)
-{
- char *oo_line;
- char *line;
- char *line_argv[MAX_LINE_ARGC];
- int line_argc;
-
- if (!(oo_line = get_oo_line(str))) {
- printf("No OO line found for %s\n", str);
- exit(1);
- }
-
- if (!(line = strdup(oo_line)))
- exit(1);
-
- split_line(line, &line_argc, line_argv, ' ');
- add_required_opt_line(cmd, line_argc, line_argv);
- free(line);
-}
-
-/* process what follows command_name, which are required opt/pos args */
-
-static void add_required_line(struct command *cmd, int argc, char *argv[])
-{
- int i;
- int takes_arg;
- int prev_was_opt = 0, prev_was_pos = 0;
-
- /* argv[0] is command name */
-
- for (i = 1; i < argc; i++) {
- if (is_opt_name(argv[i])) {
- add_opt_arg(cmd, argv[i], &takes_arg, REQUIRED);
- prev_was_opt = 1;
- prev_was_pos = 0;
- } else if (prev_was_opt && takes_arg) {
- update_prev_opt_arg(cmd, argv[i], REQUIRED);
- prev_was_opt = 0;
- prev_was_pos = 0;
- } else if (is_pos_name(argv[i])) {
- add_pos_arg(cmd, argv[i], REQUIRED);
- prev_was_opt = 0;
- prev_was_pos = 1;
- } else if (!strncmp(argv[i], "OO_", 3)) {
- cmd->cmd_flags |= CMD_FLAG_ONE_REQUIRED_OPT;
- include_required_opt_args(cmd, argv[i]);
- } else if (prev_was_pos) {
- update_prev_pos_arg(cmd, argv[i], REQUIRED);
- } else
- printf("Can't parse argc %d argv %s prev %s\n",
- i, argv[i], argv[i-1]);
-
- }
-}
-
-static void print_def(struct arg_def *def, int usage)
-{
- int val_enum;
- int lvt_enum;
- int sep = 0;
- int i;
-
- for (val_enum = 0; val_enum < VAL_COUNT; val_enum++) {
- if (def->val_bits & val_enum_to_bit(val_enum)) {
-
- if (val_enum == conststr_VAL)
- printf("%s", def->str);
-
- else if (val_enum == constnum_VAL)
- printf("%llu", (unsigned long long)def->num);
-
- else {
- if (sep) printf("|");
-
- if (!usage || !val_names[val_enum].usage)
- printf("%s", val_names[val_enum].name);
- else
- printf("%s", val_names[val_enum].usage);
-
- sep = 1;
- }
-
- if (val_enum == lv_VAL && def->lvt_bits) {
- for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
- if (lvt_bit_is_set(def->lvt_bits, lvt_enum))
- printf("_%s", lvt_enum_to_name(lvt_enum));
- }
- }
-
- if ((val_enum == vg_VAL) && (def->flags & ARG_DEF_FLAG_NEW_VG))
- printf("_new");
- if ((val_enum == lv_VAL) && (def->flags & ARG_DEF_FLAG_NEW_LV))
- printf("_new");
- }
- }
-
- if (def->flags & ARG_DEF_FLAG_MAY_REPEAT)
- printf(" ...");
-}
-
-void print_expanded(void)
-{
- struct command *cmd;
- int onereq;
- int i, ro, rp, oo, op;
-
- for (i = 0; i < cmd_count; i++) {
- cmd = &cmd_array[i];
- printf("%s", cmd->name);
-
- onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
-
- if (cmd->ro_count) {
- if (onereq)
- printf(" (");
-
- for (ro = 0; ro < cmd->ro_count; ro++) {
- if (ro && onereq)
- printf(",");
- printf(" %s", opt_names[cmd->required_opt_args[ro].opt].long_opt);
- if (cmd->required_opt_args[ro].def.val_bits) {
- printf(" ");
- print_def(&cmd->required_opt_args[ro].def, 0);
- }
- }
- if (onereq)
- printf(" )");
- }
-
- if (cmd->rp_count) {
- for (rp = 0; rp < cmd->rp_count; rp++) {
- if (cmd->required_pos_args[rp].def.val_bits) {
- printf(" ");
- print_def(&cmd->required_pos_args[rp].def, 0);
- }
- }
- }
-
- if (cmd->oo_count) {
- printf("\n");
- printf("OO:");
- for (oo = 0; oo < cmd->oo_count; oo++) {
- if (oo)
- printf(",");
- printf(" %s", opt_names[cmd->optional_opt_args[oo].opt].long_opt);
- if (cmd->optional_opt_args[oo].def.val_bits) {
- printf(" ");
- print_def(&cmd->optional_opt_args[oo].def, 0);
- }
- }
- }
-
- if (cmd->op_count) {
- printf("\n");
- printf("OP:");
- for (op = 0; op < cmd->op_count; op++) {
- if (cmd->optional_pos_args[op].def.val_bits) {
- printf(" ");
- print_def(&cmd->optional_pos_args[op].def, 0);
- }
- }
- }
-
- printf("\n\n");
- }
-}
-
-static int opt_arg_matches(struct opt_arg *oa1, struct opt_arg *oa2)
-{
- if (oa1->opt != oa2->opt)
- return 0;
-
- /* FIXME: some cases may need more specific val_bits checks */
- if (oa1->def.val_bits != oa2->def.val_bits)
- return 0;
-
- if (oa1->def.str && oa2->def.str && strcmp(oa1->def.str, oa2->def.str))
- return 0;
-
- if (oa1->def.num != oa2->def.num)
- return 0;
-
- /*
- * Do NOT compare lv_types because we are checking if two
- * command lines are ambiguous before the LV type is known.
- */
-
- return 1;
-}
-
-static int pos_arg_matches(struct pos_arg *pa1, struct pos_arg *pa2)
-{
- if (pa1->pos != pa2->pos)
- return 0;
-
- /* FIXME: some cases may need more specific val_bits checks */
- if (pa1->def.val_bits != pa2->def.val_bits)
- return 0;
-
- if (pa1->def.str && pa2->def.str && strcmp(pa1->def.str, pa2->def.str))
- return 0;
-
- if (pa1->def.num != pa2->def.num)
- return 0;
-
- /*
- * Do NOT compare lv_types because we are checking if two
- * command lines are ambiguous before the LV type is known.
- */
-
- return 1;
-}
-
-static const char *opt_to_enum_str(int opt)
-{
- return opt_names[opt].name;
-}
-
-static char *flags_to_str(int flags)
-{
- static char buf_flags[32];
-
- memset(buf_flags, 0, sizeof(buf_flags));
-
- if (flags & ARG_DEF_FLAG_MAY_REPEAT) {
- if (buf_flags[0])
- strcat(buf_flags, " | ");
- strcat(buf_flags, "ARG_DEF_FLAG_MAY_REPEAT");
- }
- if (flags & ARG_DEF_FLAG_NEW_VG) {
- if (buf_flags[0])
- strcat(buf_flags, " | ");
- strcat(buf_flags, "ARG_DEF_FLAG_NEW_VG");
- }
- if (flags & ARG_DEF_FLAG_NEW_LV) {
- if (buf_flags[0])
- strcat(buf_flags, " | ");
- strcat(buf_flags, "ARG_DEF_FLAG_NEW_LV");
- }
-
- return buf_flags;
-}
-
-static void add_flags(struct command *cmd, char *line)
-{
- if (strstr(line, "SECONDARY_SYNTAX"))
- cmd->cmd_flags |= CMD_FLAG_SECONDARY_SYNTAX;
-}
-
-#define MAX_RULE_OPTS 64
-
-static void add_rule(struct command *cmd, char *line)
-{
- struct cmd_rule *rule;
- char *line_argv[MAX_LINE_ARGC];
- char *arg;
- int line_argc;
- int i, lvt_enum, lvp_enum;
- int check = 0;
-
- if (cmd->rule_count == CMD_MAX_RULES) {
- printf("too many rules for cmd\n");
- exit(1);
- }
-
- rule = &cmd->rules[cmd->rule_count++];
-
- split_line(line, &line_argc, line_argv, ' ');
-
- for (i = 0; i < line_argc; i++) {
- arg = line_argv[i];
-
- if (!strcmp(arg, "not")) {
- rule->rule = RULE_INVALID;
- check = 1;
- }
-
- else if (!strcmp(arg, "and")) {
- rule->rule = RULE_REQUIRE;
- check = 1;
- }
-
- else if (!strncmp(arg, "all", 3)) {
- /* opt/lvt_bits/lvp_bits all remain 0 to mean all */
- continue;
- }
-
- else if (!strncmp(arg, "--", 2)) {
- if (!rule->opts) {
- if (!(rule->opts = malloc(MAX_RULE_OPTS * sizeof(int)))) {
- printf("no mem\n");
- exit(1);
- }
- memset(rule->opts, 0, MAX_RULE_OPTS * sizeof(int));
- }
-
- if (!rule->check_opts) {
- if (!(rule->check_opts = malloc(MAX_RULE_OPTS * sizeof(int)))) {
- printf("no mem\n");
- exit(1);
- }
- memset(rule->check_opts, 0, MAX_RULE_OPTS * sizeof(int));
- }
-
- if (check)
- rule->check_opts[rule->check_opts_count++] = opt_str_to_num(arg);
- else
- rule->opts[rule->opts_count++] = opt_str_to_num(arg);
- }
-
- else if (!strncmp(arg, "LV_", 3)) {
- lvt_enum = lv_to_enum(arg);
-
- if (check)
- rule->check_lvt_bits |= lvt_enum_to_bit(lvt_enum);
- else
- rule->lvt_bits |= lvt_enum_to_bit(lvt_enum);
- }
-
- else if (!strncmp(arg, "lv_is_", 6)) {
- lvp_enum = lvp_name_to_enum(arg);
-
- if (check)
- rule->check_lvp_bits |= lvp_enum_to_bit(lvp_enum);
- else
- rule->lvp_bits |= lvp_enum_to_bit(lvp_enum);
- }
- }
-}
-
-static char *rule_to_define_str(int rule_type)
-{
- switch (rule_type) {
- case RULE_INVALID:
- return "RULE_INVALID";
- case RULE_REQUIRE:
- return "RULE_REQUIRE";
- }
-}
-
-static char *cmd_flags_to_str(uint32_t flags)
-{
- static char buf_cmd_flags[32];
-
- memset(buf_cmd_flags, 0, sizeof(buf_cmd_flags));
-
- if (flags & CMD_FLAG_SECONDARY_SYNTAX) {
- if (buf_cmd_flags[0])
- strcat(buf_cmd_flags, " | ");
- strcat(buf_cmd_flags, "CMD_FLAG_SECONDARY_SYNTAX");
- }
- if (flags & CMD_FLAG_ONE_REQUIRED_OPT) {
- if (buf_cmd_flags[0])
- strcat(buf_cmd_flags, " | ");
- strcat(buf_cmd_flags, "CMD_FLAG_ONE_REQUIRED_OPT");
- }
-
- return buf_cmd_flags;
-}
-
-void print_command_count(void)
-{
- struct command *cmd;
- int i, j;
-
- printf("/* Do not edit. This file is generated by tools/create-commands */\n");
- printf("/* using command definitions from tools/command-lines.in */\n");
- printf("#define COMMAND_COUNT %d\n", cmd_count);
-
- printf("enum {\n");
- printf("\tno_CMD,\n"); /* enum value 0 is not used */
-
- for (i = 0; i < cmd_count; i++) {
- cmd = &cmd_array[i];
-
- if (!cmd->command_line_id) {
- printf("Missing ID: at %d\n", i);
- exit(1);
- }
-
- for (j = 0; j < i; j++) {
- if (!strcmp(cmd->command_line_id, cmd_array[j].command_line_id))
- goto next;
- }
-
- printf("\t%s_CMD,\n", cmd->command_line_id);
- next:
- ;
- }
- printf("\tCOMMAND_ID_COUNT,\n");
- printf("};\n");
-}
-
-static int is_lvm_all_opt(int opt)
-{
- int oo;
-
- for (oo = 0; oo < lvm_all.oo_count; oo++) {
- if (lvm_all.optional_opt_args[oo].opt == opt)
- return 1;
- }
- return 0;
-}
-
-static void factor_common_options(void)
-{
- int cn, opt_enum, ci, oo, ro, found;
- struct command *cmd;
-
- for (cn = 0; cn < MAX_CMD_NAMES; cn++) {
- if (!cmd_names[cn].name)
- break;
-
- for (ci = 0; ci < cmd_count; ci++) {
- cmd = &cmd_array[ci];
-
- if (strcmp(cmd->name, cmd_names[cn].name))
- continue;
-
- cmd_names[cn].variants++;
- }
-
- for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
-
- for (ci = 0; ci < cmd_count; ci++) {
- cmd = &cmd_array[ci];
-
- if (strcmp(cmd->name, cmd_names[cn].name))
- continue;
-
- if (cmd->ro_count)
- cmd_names[cn].variant_has_ro = 1;
- if (cmd->rp_count)
- cmd_names[cn].variant_has_rp = 1;
- if (cmd->oo_count)
- cmd_names[cn].variant_has_oo = 1;
- if (cmd->op_count)
- cmd_names[cn].variant_has_op = 1;
-
- for (ro = 0; ro < cmd->ro_count; ro++) {
- cmd_names[cn].all_options[cmd->required_opt_args[ro].opt] = 1;
-
- if ((cmd->required_opt_args[ro].opt == size_ARG) && !strncmp(cmd->name, "lv", 2))
- cmd_names[cn].all_options[extents_ARG] = 1;
- }
- for (oo = 0; oo < cmd->oo_count; oo++)
- cmd_names[cn].all_options[cmd->optional_opt_args[oo].opt] = 1;
-
- found = 0;
-
- for (oo = 0; oo < cmd->oo_count; oo++) {
- if (cmd->optional_opt_args[oo].opt == opt_enum) {
- found = 1;
- break;
- }
- }
-
- if (!found)
- goto next_opt;
- }
-
- /* all commands starting with this name use this option */
- cmd_names[cn].common_options[opt_enum] = 1;
- next_opt:
- ;
- }
- }
-
- /*
- for (cn = 0; cn < MAX_CMD_NAMES; cn++) {
- if (!cmd_names[cn].name)
- break;
-
- printf("%s (%d)\n", cmd_names[cn].name, cmd_names[cn].variants);
- for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
- if (cmd_names[cn].common_options[opt_enum])
- printf(" %s\n", opt_names[opt_enum].long_opt);
- }
- }
- */
-}
-
-void print_usage_common(struct command *cmd)
-{
- struct cmd_name *cname;
- int i, sep, ro, rp, oo, op, opt_enum;
-
- if (!(cname = find_command_name(cmd->name)))
- return;
-
- sep = 0;
-
- /*
- * when there's more than one variant, options that
- * are common to all commands with a common name.
- */
-
- if (cname->variants < 2)
- goto all;
-
- for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
- if (!cname->common_options[opt_enum])
- continue;
-
- if (is_lvm_all_opt(opt_enum))
- continue;
-
- if (!sep) {
- printf("\n");
- printf("\" [");
- } else {
- printf(",");
- }
-
- for (oo = 0; oo < cmd->oo_count; oo++) {
- if (cmd->optional_opt_args[oo].opt != opt_enum)
- continue;
-
- printf(" %s", opt_names[opt_enum].long_opt);
- if (cmd->optional_opt_args[oo].def.val_bits) {
- printf(" ");
- print_def(&cmd->optional_opt_args[oo].def, 1);
- }
- sep = 1;
- break;
- }
- }
-
- all:
- /* options that are common to all lvm commands */
-
- for (oo = 0; oo < lvm_all.oo_count; oo++) {
- opt_enum = lvm_all.optional_opt_args[oo].opt;
-
- if (!sep) {
- printf("\n");
- printf("\" [");
- } else {
- printf(",");
- }
-
- printf(" %s", opt_names[opt_enum].long_opt);
- if (lvm_all.optional_opt_args[oo].def.val_bits) {
- printf(" ");
- print_def(&lvm_all.optional_opt_args[oo].def, 1);
- }
- sep = 1;
- }
-
- printf(" ]\"");
- printf(";\n");
-}
-
-void print_usage(struct command *cmd)
-{
- struct cmd_name *cname;
- int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
- int i, sep, ro, rp, oo, op, opt_enum;
-
- if (!(cname = find_command_name(cmd->name)))
- return;
-
- printf("\"%s", cmd->name);
-
- if (cmd->ro_count) {
- if (onereq)
- printf(" (");
- for (ro = 0; ro < cmd->ro_count; ro++) {
- if (ro && onereq)
- printf(",");
- printf(" %s", opt_names[cmd->required_opt_args[ro].opt].long_opt);
-
- if (cmd->required_opt_args[ro].def.val_bits) {
- printf(" ");
- print_def(&cmd->required_opt_args[ro].def, 1);
- }
- }
- if (onereq)
- printf(" )");
- }
-
- if (cmd->rp_count) {
- for (rp = 0; rp < cmd->rp_count; rp++) {
- if (cmd->required_pos_args[rp].def.val_bits) {
- printf(" ");
- print_def(&cmd->required_pos_args[rp].def, 1);
- }
- }
- }
-
- printf("\"");
-
- oo_count:
- if (!cmd->oo_count)
- goto op_count;
-
- sep = 0;
-
- if (cmd->oo_count) {
- printf("\n");
- printf("\" [");
-
- for (oo = 0; oo < cmd->oo_count; oo++) {
- opt_enum = cmd->optional_opt_args[oo].opt;
-
- /*
- * Skip common opts which are in the usage_common string.
- * The common opts are those in lvm_all and in
- * cname->common_options.
- */
-
- if (is_lvm_all_opt(opt_enum))
- continue;
-
- if ((cname->variants > 1) && cname->common_options[opt_enum])
- continue;
-
- if (sep)
- printf(",");
-
- printf(" %s", opt_names[opt_enum].long_opt);
- if (cmd->optional_opt_args[oo].def.val_bits) {
- printf(" ");
- print_def(&cmd->optional_opt_args[oo].def, 1);
- }
- sep = 1;
- }
-
- if (sep)
- printf(",");
- printf(" COMMON_OPTIONS");
- printf(" ]\"");
- }
-
- op_count:
- if (!cmd->op_count)
- goto done;
-
- printf("\n");
- printf("\" [");
-
- if (cmd->op_count) {
- for (op = 0; op < cmd->op_count; op++) {
- if (cmd->optional_pos_args[op].def.val_bits) {
- printf(" ");
- print_def(&cmd->optional_pos_args[op].def, 1);
- }
- }
- }
-
- printf(" ]\"");
-
- done:
- printf(";\n");
-}
-
-static void print_val_man(const char *str)
-{
- char *line;
- char *line_argv[MAX_LINE_ARGC];
- int line_argc;
- int i;
-
- if (!strcmp(str, "Number") ||
- !strcmp(str, "String") ||
- !strncmp(str, "VG", 2) ||
- !strncmp(str, "LV", 2) ||
- !strncmp(str, "PV", 2) ||
- !strcmp(str, "Tag")) {
- printf("\\fI%s\\fP", str);
- return;
- }
-
- if (strstr(str, "Number[") || strstr(str, "]Number")) {
- for (i = 0; i < strlen(str); i++) {
- if (str[i] == 'N')
- printf("\\fI");
- if (str[i] == 'r') {
- printf("%c", str[i]);
- printf("\\fP");
- continue;
- }
- printf("%c", str[i]);
- }
- return;
- }
-
- if (strstr(str, "|")) {
- int len = strlen(str);
- line = strdup(str);
- split_line(line, &line_argc, line_argv, '|');
- for (i = 0; i < line_argc; i++) {
- if (i) {
- printf("|");
-
- /* this is a hack to add a line break for
- a long string of opt values */
- if ((len > 40) && (i >= (line_argc / 2) + 1)) {
- printf("\n");
- printf(" ");
- len = 0;
- }
- }
- if (strstr(line_argv[i], "Number"))
- printf("\\fI%s\\fP", line_argv[i]);
- else
- printf("\\fB%s\\fP", line_argv[i]);
- }
- return;
- }
-
- printf("\\fB%s\\fP", str);
-}
-
-static void print_def_man(struct arg_def *def, int usage)
-{
- int val_enum;
- int lvt_enum;
- int sep = 0;
- int i;
-
- for (val_enum = 0; val_enum < VAL_COUNT; val_enum++) {
- if (def->val_bits & val_enum_to_bit(val_enum)) {
-
- if (val_enum == conststr_VAL) {
- printf("\\fB");
- printf("%s", def->str);
- printf("\\fP");
- }
-
- else if (val_enum == constnum_VAL) {
- printf("\\fB");
- printf("%llu", (unsigned long long)def->num);
- printf("\\fP");
- }
-
- else {
- if (sep) printf("|");
-
- if (!usage || !val_names[val_enum].usage) {
- printf("\\fI");
- printf("%s", val_names[val_enum].name);
- printf("\\fP");
- } else {
- print_val_man(val_names[val_enum].usage);
- }
-
- sep = 1;
- }
-
- if (val_enum == lv_VAL && def->lvt_bits) {
- printf("\\fI");
- for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
- if (lvt_bit_is_set(def->lvt_bits, lvt_enum))
- printf("_%s", lvt_enum_to_name(lvt_enum));
- }
- printf("\\fP");
- }
-
- if ((val_enum == vg_VAL) && (def->flags & ARG_DEF_FLAG_NEW_VG)) {
- printf("\\fI");
- printf("_new");
- printf("\\fP");
- }
- if ((val_enum == lv_VAL) && (def->flags & ARG_DEF_FLAG_NEW_LV)) {
- printf("\\fI");
- printf("_new");
- printf("\\fP");
- }
- }
- }
-
- if (def->flags & ARG_DEF_FLAG_MAY_REPEAT)
- printf(" ...");
-}
-
-static char *man_long_opt_name(const char *cmdname, int opt_enum)
-{
- static char long_opt_name[64];
-
- memset(&long_opt_name, 0, sizeof(long_opt_name));
-
- switch (opt_enum) {
- case syncaction_ARG:
- strncpy(long_opt_name, "--[raid]syncaction", 63);
- break;
- case writemostly_ARG:
- strncpy(long_opt_name, "--[raid]writemostly", 63);
- break;
- case minrecoveryrate_ARG:
- strncpy(long_opt_name, "--[raid]minrecoveryrate", 63);
- break;
- case maxrecoveryrate_ARG:
- strncpy(long_opt_name, "--[raid]maxrecoveryrate", 63);
- break;
- case writebehind_ARG:
- strncpy(long_opt_name, "--[raid]writebehind", 63);
- break;
- case vgmetadatacopies_ARG:
- if (!strncmp(cmdname, "vg", 2))
- strncpy(long_opt_name, "--[vg]metadatacopies", 63);
- else
- strncpy(long_opt_name, "--vgmetadatacopies", 63);
- break;
- case pvmetadatacopies_ARG:
- if (!strncmp(cmdname, "pv", 2))
- strncpy(long_opt_name, "--[pv]metadatacopies", 63);
- else
- strncpy(long_opt_name, "--pvmetadatacopies", 63);
- break;
- default:
- strncpy(long_opt_name, opt_names[opt_enum].long_opt, 63);
- break;
- }
-
- return long_opt_name;
-}
-
-void print_man_usage(struct command *cmd)
-{
- struct cmd_name *cname;
- int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
- int i, sep, ro, rp, oo, op, opt_enum;
-
- if (!(cname = find_command_name(cmd->name)))
- return;
-
- printf("\\fB%s\\fP", cmd->name);
-
- if (!onereq)
- goto ro_normal;
-
- /*
- * one required option in a set, print as:
- * ( -a|--a,
- * -b|--b,
- * --c,
- * --d )
- *
- * First loop through ro prints those with short opts,
- * and the second loop prints those without short opts.
- */
-
- if (cmd->ro_count) {
- printf("\n");
- printf(".RS 4\n");
- printf("(");
-
- sep = 0;
-
- /* print required options with a short opt */
- for (ro = 0; ro < cmd->ro_count; ro++) {
- opt_enum = cmd->required_opt_args[ro].opt;
-
- if (!opt_names[opt_enum].short_opt)
- continue;
-
- if (sep) {
- printf(",");
- printf("\n.br\n");
- printf(" ");
- }
-
- if (opt_names[opt_enum].short_opt) {
- printf(" \\fB-%c\\fP|\\fB%s\\fP",
- opt_names[opt_enum].short_opt,
- man_long_opt_name(cmd->name, opt_enum));
- } else {
- printf(" ");
- printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
- }
-
- if (cmd->required_opt_args[ro].def.val_bits) {
- printf(" ");
- print_def_man(&cmd->required_opt_args[ro].def, 1);
- }
-
- sep = 1;
- }
-
- /* print required options without a short opt */
- for (ro = 0; ro < cmd->ro_count; ro++) {
- opt_enum = cmd->required_opt_args[ro].opt;
-
- if (opt_names[opt_enum].short_opt)
- continue;
-
- if (sep) {
- printf(",");
- printf("\n.br\n");
- printf(" ");
- }
-
- printf(" ");
- printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
-
- if (cmd->required_opt_args[ro].def.val_bits) {
- printf(" ");
- print_def_man(&cmd->required_opt_args[ro].def, 1);
- }
-
- sep = 1;
- }
-
- printf(" )\n");
- printf(".RE\n");
- }
-
- /* print required position args on a new line after the onereq set */
- if (cmd->rp_count) {
- printf(".RS 4\n");
- for (rp = 0; rp < cmd->rp_count; rp++) {
- if (cmd->required_pos_args[rp].def.val_bits) {
- printf(" ");
- print_def_man(&cmd->required_pos_args[rp].def, 1);
- }
- }
-
- printf("\n");
- printf(".RE\n");
- } else {
- /* printf("\n"); */
- }
-
- printf(".br\n");
- goto oo_count;
-
- ro_normal:
-
- /*
- * all are required options, print as:
- * -a|--aaa <val> -b|--bbb <val>
- */
-
- if (cmd->ro_count) {
- for (ro = 0; ro < cmd->ro_count; ro++) {
- opt_enum = cmd->required_opt_args[ro].opt;
-
- if (opt_names[opt_enum].short_opt) {
- printf(" \\fB-%c\\fP|\\fB%s\\fP",
- opt_names[opt_enum].short_opt,
- man_long_opt_name(cmd->name, opt_enum));
- } else {
- printf(" \\fB%s\\fP", opt_names[cmd->required_opt_args[ro].opt].long_opt);
- }
-
- if (cmd->required_opt_args[ro].def.val_bits) {
- printf(" ");
- print_def_man(&cmd->required_opt_args[ro].def, 1);
- }
- }
- }
-
- /* print required position args on the same line as the required options */
- if (cmd->rp_count) {
- for (rp = 0; rp < cmd->rp_count; rp++) {
- if (cmd->required_pos_args[rp].def.val_bits) {
- printf(" ");
- print_def_man(&cmd->required_pos_args[rp].def, 1);
- }
- }
-
- printf("\n");
- } else {
- printf("\n");
- }
-
- printf(".br\n");
-
- oo_count:
- if (!cmd->oo_count)
- goto op_count;
-
- sep = 0;
-
- if (cmd->oo_count) {
- printf(".RS 4\n");
- printf("[");
-
- /* print optional options with short opts */
-
- for (oo = 0; oo < cmd->oo_count; oo++) {
- opt_enum = cmd->optional_opt_args[oo].opt;
-
- if (!opt_names[opt_enum].short_opt)
- continue;
-
- /*
- * Skip common opts which are in the usage_common string.
- * The common opts are those in lvm_all and in
- * cname->common_options.
- */
-
- if (is_lvm_all_opt(opt_enum))
- continue;
-
- if ((cname->variants > 1) && cname->common_options[opt_enum])
- continue;
-
- if (sep) {
- printf(",");
- printf("\n.br\n");
- printf(" ");
- }
-
- printf(" \\fB-%c\\fP|\\fB%s\\fP",
- opt_names[opt_enum].short_opt,
- man_long_opt_name(cmd->name, opt_enum));
-
- if (cmd->optional_opt_args[oo].def.val_bits) {
- printf(" ");
- print_def_man(&cmd->optional_opt_args[oo].def, 1);
- }
- sep = 1;
- }
-
- /* print optional options without short opts */
-
- for (oo = 0; oo < cmd->oo_count; oo++) {
- opt_enum = cmd->optional_opt_args[oo].opt;
-
- if (opt_names[opt_enum].short_opt)
- continue;
-
- /*
- * Skip common opts which are in the usage_common string.
- * The common opts are those in lvm_all and in
- * cname->common_options.
- */
-
- if (is_lvm_all_opt(opt_enum))
- continue;
-
- if ((cname->variants > 1) && cname->common_options[opt_enum])
- continue;
-
- if (sep) {
- printf(",");
- printf("\n.br\n");
- printf(" ");
- }
-
- /* space alignment without short opt */
- printf(" ");
-
- printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
-
- if (cmd->optional_opt_args[oo].def.val_bits) {
- printf(" ");
- print_def_man(&cmd->optional_opt_args[oo].def, 1);
- }
- sep = 1;
- }
-
- if (sep) {
- printf(",");
- printf("\n.br\n");
- printf(" ");
- /* space alignment without short opt */
- printf(" ");
- }
- printf(" COMMON_OPTIONS");
- printf(" ]\n");
- printf(".RE\n");
- printf(".br\n");
- }
-
- op_count:
- if (!cmd->op_count)
- goto done;
-
- printf(".RS 4\n");
- printf("[");
-
- if (cmd->op_count) {
- for (op = 0; op < cmd->op_count; op++) {
- if (cmd->optional_pos_args[op].def.val_bits) {
- printf(" ");
- print_def_man(&cmd->optional_pos_args[op].def, 1);
- }
- }
- }
-
- printf(" ]\n");
- printf(".RE\n");
-
- done:
- printf("\n");
-}
-
-/*
- * common options listed in the usage section.
- *
- * For commands with only one variant, this is only
- * the options which are common to all lvm commands
- * (in lvm_all, see is_lvm_all_opt).
- *
- * For commands with more than one variant, this
- * is the set of options common to all variants
- * (in cname->common_options), (which obviously
- * includes the options common to all lvm commands.)
- *
- * List ordering:
- * options with short+long names, alphabetically,
- * then options with only long names, alphabetically
- */
-
-void print_man_usage_common(struct command *cmd)
-{
- struct cmd_name *cname;
- int i, sep, ro, rp, oo, op, opt_enum;
-
- if (!(cname = find_command_name(cmd->name)))
- return;
-
- sep = 0;
-
- printf(".RS 4\n");
- printf("[");
-
- /* print those with short opts */
- for (i = 0; i < ARG_COUNT; i++) {
- opt_enum = opt_names_alpha[i]->opt_enum;
-
- if (!cname->common_options[opt_enum])
- continue;
-
- if (!opt_names[opt_enum].short_opt)
- continue;
-
- if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
- continue;
-
- if (sep) {
- printf(",");
- printf("\n.br\n");
- printf(" ");
- }
-
- for (oo = 0; oo < cmd->oo_count; oo++) {
- if (cmd->optional_opt_args[oo].opt != opt_enum)
- continue;
-
- printf(" \\fB-%c\\fP|\\fB%s\\fP",
- opt_names[opt_enum].short_opt,
- man_long_opt_name(cmd->name, opt_enum));
-
- if (cmd->optional_opt_args[oo].def.val_bits) {
- printf(" ");
- print_def_man(&cmd->optional_opt_args[oo].def, 1);
- }
- sep = 1;
- break;
- }
-
- }
-
- /* print those without short opts */
- for (i = 0; i < ARG_COUNT; i++) {
- opt_enum = opt_names_alpha[i]->opt_enum;
-
- if (!cname->common_options[opt_enum])
- continue;
-
- if (opt_names[opt_enum].short_opt)
- continue;
-
- if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
- continue;
-
- if (sep) {
- printf(",");
- printf("\n.br\n");
- printf(" ");
- }
-
- for (oo = 0; oo < cmd->oo_count; oo++) {
- if (cmd->optional_opt_args[oo].opt != opt_enum)
- continue;
-
- /* space alignment without short opt */
- printf(" ");
-
- printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
-
- if (cmd->optional_opt_args[oo].def.val_bits) {
- printf(" ");
- print_def_man(&cmd->optional_opt_args[oo].def, 1);
- }
- sep = 1;
- break;
- }
- }
-
- printf(" ]\n");
- return;
-}
-
-/*
- * Format of description, when different command names have
- * different descriptions:
- *
- * "#cmdname1"
- * "text foo goes here"
- * "a second line of text."
- * "#cmdname2"
- * "text bar goes here"
- * "another line of text."
- *
- * When called for cmdname2, this function should just print:
- *
- * "text bar goes here"
- * "another line of text."
- */
-
-static void print_man_option_desc(struct cmd_name *cname, int opt_enum)
-{
- const char *desc = opt_names[opt_enum].desc;
- char buf[DESC_LINE];
- int started_cname = 0;
- int line_count = 0;
- int di, bi;
-
- if (desc[0] != '#') {
- printf("%s", desc);
- return;
- }
-
- for (di = 0; di < strlen(desc); di++) {
- buf[bi++] = desc[di];
-
- if (bi == DESC_LINE) {
- printf("print_man_option_desc line too long\n");
- return;
- }
-
- if (buf[bi-1] != '\n')
- continue;
-
- if (buf[0] != '#') {
- if (started_cname) {
- printf("%s", buf);
- line_count++;
- }
-
- memset(buf, 0, sizeof(buf));
- bi = 0;
- continue;
- }
-
- /* Line starting with #cmdname */
-
- /*
- * Must be starting a new command name.
- * If no lines have been printed, multiple command names
- * are using the same text. If lines have been printed,
- * then the start of a new command name means the end
- * of text for the current command name.
- */
- if (line_count && started_cname)
- return;
-
- if (!strncmp(buf + 1, cname->name, strlen(cname->name))) {
- /* The start of our command name. */
- started_cname = 1;
- memset(buf, 0, sizeof(buf));
- bi = 0;
- } else {
- /* The start of another command name. */
- memset(buf, 0, sizeof(buf));
- bi = 0;
- }
- }
-
- if (bi && started_cname)
- printf("%s", buf);
-}
-
-/*
- * Print a list of all options names for a given
- * command name, listed by:
- * options with short+long names, alphabetically,
- * then options with only long names, alphabetically
- */
-
-void print_man_all_options_list(struct cmd_name *cname)
-{
- int opt_enum, val_enum;
- int sep = 0;
- int i;
-
- /* print those with both short and long opts */
- for (i = 0; i < ARG_COUNT; i++) {
- opt_enum = opt_names_alpha[i]->opt_enum;
-
- if (!cname->all_options[opt_enum])
- continue;
-
- if (!opt_names[opt_enum].short_opt)
- continue;
-
- if (sep)
- printf("\n.br\n");
-
- printf(" \\fB-%c\\fP|\\fB%s\\fP",
- opt_names[opt_enum].short_opt,
- man_long_opt_name(cname->name, opt_enum));
-
- val_enum = opt_names[opt_enum].val_enum;
-
- if (!val_names[val_enum].fn) {
- /* takes no arg */
- } else if (!val_names[val_enum].usage) {
- printf(" ");
- printf("\\fI");
- printf("%s", val_names[val_enum].name);
- printf("\\fP");
- } else {
- printf(" ");
- print_val_man(val_names[val_enum].usage);
- }
-
- sep = 1;
- }
-
- /* print those without short opts */
- for (i = 0; i < ARG_COUNT; i++) {
- opt_enum = opt_names_alpha[i]->opt_enum;
-
- if (!cname->all_options[opt_enum])
- continue;
-
- if (opt_names[opt_enum].short_opt)
- continue;
-
- if (sep)
- printf("\n.br\n");
-
- /* space alignment without short opt */
- printf(" ");
-
- printf(" \\fB%s\\fP", man_long_opt_name(cname->name, opt_enum));
-
- val_enum = opt_names[opt_enum].val_enum;
-
- if (!val_names[val_enum].fn) {
- /* takes no arg */
- } else if (!val_names[val_enum].usage) {
- printf(" ");
- printf("\\fI");
- printf("%s", val_names[val_enum].name);
- printf("\\fP");
- } else {
- printf(" ");
- print_val_man(val_names[val_enum].usage);
- }
-
- sep = 1;
- }
-}
-
-/*
- * All options used for a given command name, along with descriptions.
- * listed in order of:
- * 1. options that are not common to all lvm commands, alphabetically
- * 2. options common to all lvm commands, alphabetically
- */
-
-void print_man_all_options_desc(struct cmd_name *cname)
-{
- int opt_enum, val_enum;
- int print_common = 0;
- int sep = 0;
- int i;
-
- again:
- /*
- * Loop 1: print options that are not common to all lvm commands.
- * Loop 2: print options common to all lvm commands (lvm_all)
- */
-
- for (i = 0; i < ARG_COUNT; i++) {
- opt_enum = opt_names_alpha[i]->opt_enum;
-
- if (!cname->all_options[opt_enum])
- continue;
-
- if (!print_common && is_lvm_all_opt(opt_enum))
- continue;
-
- if (print_common && !is_lvm_all_opt(opt_enum))
- continue;
-
- if (sep)
- printf("\n.br\n");
-
- printf("\n.TP\n");
-
- if (opt_names[opt_enum].short_opt) {
- printf("\\fB-%c\\fP|\\fB%s\\fP",
- opt_names[opt_enum].short_opt,
- man_long_opt_name(cname->name, opt_enum));
- } else {
- printf("\\fB%s\\fP", man_long_opt_name(cname->name, opt_enum));
- }
-
- val_enum = opt_names[opt_enum].val_enum;
-
- if (!val_names[val_enum].fn) {
- /* takes no arg */
- } else if (!val_names[val_enum].usage) {
- printf(" ");
- printf("\\fI");
- printf("%s", val_names[val_enum].name);
- printf("\\fP");
- } else {
- printf(" ");
- print_val_man(val_names[val_enum].usage);
- }
-
- if (opt_names[opt_enum].desc) {
- printf("\n");
- printf(".br\n");
- print_man_option_desc(cname, opt_enum);
- }
-
- sep = 1;
- }
-
- if (!print_common) {
- print_common = 1;
- goto again;
- }
-}
-
-void print_desc_man(const char *desc)
-{
- char buf[DESC_LINE] = {0};
- int di = 0;
- int bi = 0;
-
- for (di = 0; di < strlen(desc); di++) {
- if (desc[di] == '\0')
- break;
- if (desc[di] == '\n')
- continue;
-
- if (!strncmp(&desc[di], "DESC:", 5)) {
- if (bi) {
- printf("%s\n", buf);
- printf(".br\n");
- memset(buf, 0, sizeof(buf));
- bi = 0;
- }
- di += 5;
- continue;
- }
-
- if (!bi && desc[di] == ' ')
- continue;
-
- buf[bi++] = desc[di];
-
- if (bi == (DESC_LINE - 1))
- break;
- }
-
- if (bi) {
- printf("%s\n", buf);
- printf(".br\n");
- }
-}
-
-static char *upper_command_name(char *str)
-{
- static char str_upper[32];
- int i = 0;
-
- while (*str) {
- str_upper[i++] = toupper(*str);
- str++;
- }
- str_upper[i] = '\0';
- return str_upper;
-}
-
-void print_man_command(void)
-{
- struct cmd_name *cname;
- struct command *cmd, *prev_cmd = NULL;
- const char *desc;
- int i, j, ro, rp, oo, op;
-
- include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON");
-
- printf(".TH %s 8 \"LVM TOOLS #VERSION#\" \"Sistina Software UK\"\n",
- man_command_name ? upper_command_name(man_command_name) : "LVM_COMMANDS");
-
- for (i = 0; i < cmd_count; i++) {
-
- cmd = &cmd_array[i];
-
- if (prev_cmd && strcmp(prev_cmd->name, cmd->name)) {
- printf("Common options:\n");
- printf(".\n");
- print_man_usage_common(prev_cmd);
-
- printf("\n");
- printf(".SH OPTIONS\n");
- printf(".br\n");
- print_man_all_options_desc(cname);
-
- prev_cmd = NULL;
- }
-
- if ((cmd->cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && !include_man_secondary)
- continue;
-
- if (!(cmd->cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && !include_man_primary)
- continue;
-
- if (man_command_name && strcmp(man_command_name, cmd->name))
- continue;
-
- if (!prev_cmd || strcmp(prev_cmd->name, cmd->name)) {
- printf(".SH NAME\n");
- printf(".\n");
- if ((desc = cmd_name_desc(cmd->name)))
- printf("%s \\- %s\n", cmd->name, desc);
- else
- printf("%s\n", cmd->name);
- printf(".br\n");
- printf(".P\n");
- printf(".\n");
- printf(".SH SYNOPSIS\n");
- printf(".br\n");
- printf(".P\n");
- printf(".\n");
- prev_cmd = cmd;
-
- if (!(cname = find_command_name(cmd->name)))
- return;
-
- if (cname->variant_has_ro && cname->variant_has_rp)
- printf("\\fB%s\\fP \\fIrequired_option_args\\fP \\fIrequired_position_args\\fP\n", cmd->name);
- else if (cname->variant_has_ro && !cname->variant_has_rp)
- printf("\\fB%s\\fP \\fIrequired_option_args\\fP\n", cmd->name);
- else if (!cname->variant_has_ro && cname->variant_has_rp)
- printf("\\fB%s\\fP \\fIrequired_position_args\\fP\n", cmd->name);
- else if (!cname->variant_has_ro && !cname->variant_has_rp)
- printf("\\fB%s\\fP\n", cmd->name);
-
- printf(".br\n");
-
- if (cname->variant_has_oo) {
- printf(" [ \\fIoptional_option_args\\fP ]\n");
- printf(".br\n");
- }
-
- if (cname->variant_has_op) {
- printf(" [ \\fIoptional_position_args\\fP ]\n");
- printf(".br\n");
- }
-
- printf(".P\n");
- printf("\n");
-
- /* listing them all when there's only 1 or 2 is just repetative */
- if (cname->variants > 2) {
- printf(".P\n");
- print_man_all_options_list(cname);
- printf("\n");
- printf(".P\n");
- printf("\n");
- }
-
- printf(".SH USAGE\n");
- printf(".br\n");
- printf(".P\n");
- printf(".\n");
- }
-
- if (cmd->desc) {
- print_desc_man(cmd->desc);
- printf(".P\n");
- }
-
- print_man_usage(cmd);
-
- if (i == (cmd_count - 1)) {
- printf("Common options:\n");
- printf(".\n");
- print_man_usage_common(cmd);
-
- printf("\n");
- printf(".SH OPTIONS\n");
- printf(".br\n");
- print_man_all_options_desc(cname);
-
- }
-
- printf("\n");
- continue;
- }
-}
-
-void print_command_struct(int only_usage)
-{
- struct command *cmd;
- int i, j, ro, rp, oo, op, ru, ruo, io;
-
- include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON");
-
- printf("/* Do not edit. This file is generated by tools/create-commands */\n");
- printf("/* using command definitions from tools/command-lines.in */\n");
- printf("\n");
-
- for (i = 0; i < cmd_count; i++) {
- cmd = &cmd_array[i];
-
- if (only_usage) {
- print_usage(cmd);
- print_usage_common(cmd);
- printf("\n");
- continue;
- }
-
- printf("commands[%d].name = \"%s\";\n", i, cmd->name);
- printf("commands[%d].command_line_id = \"%s\";\n", i, cmd->command_line_id);
- printf("commands[%d].command_line_enum = %s_CMD;\n", i, cmd->command_line_id);
- printf("commands[%d].fn = %s;\n", i, cmd->name);
- printf("commands[%d].ro_count = %d;\n", i, cmd->ro_count);
- printf("commands[%d].rp_count = %d;\n", i, cmd->rp_count);
- printf("commands[%d].oo_count = %d;\n", i, cmd->oo_count);
- printf("commands[%d].op_count = %d;\n", i, cmd->op_count);
- printf("commands[%d].io_count = %d;\n", i, cmd->io_count);
- printf("commands[%d].rule_count = %d;\n", i, cmd->rule_count);
-
- if (cmd->cmd_flags)
- printf("commands[%d].cmd_flags = %s;\n", i, cmd_flags_to_str(cmd->cmd_flags));
- else
- printf("commands[%d].cmd_flags = 0;\n", i, cmd_flags_to_str(cmd->cmd_flags));
-
- printf("commands[%d].desc = \"%s\";\n", i, cmd->desc ?: "");
- printf("commands[%d].usage = ", i);
- print_usage(cmd);
-
- if (cmd->oo_count) {
- printf("commands[%d].usage_common = ", i);
- print_usage_common(cmd);
- } else {
- printf("commands[%d].usage_common = \"NULL\";\n", i);
- }
-
- if (cmd->ro_count) {
- for (ro = 0; ro < cmd->ro_count; ro++) {
- printf("commands[%d].required_opt_args[%d].opt = %s;\n",
- i, ro, opt_to_enum_str(cmd->required_opt_args[ro].opt));
-
- if (!cmd->required_opt_args[ro].def.val_bits)
- continue;
-
- printf("commands[%d].required_opt_args[%d].def.val_bits = %s;\n",
- i, ro, val_bits_to_str(cmd->required_opt_args[ro].def.val_bits));
-
- if (cmd->required_opt_args[ro].def.lvt_bits)
- printf("commands[%d].required_opt_args[%d].def.lvt_bits = %s;\n",
- i, ro, lvt_bits_to_str(cmd->required_opt_args[ro].def.lvt_bits));
-
- if (cmd->required_opt_args[ro].def.flags)
- printf("commands[%d].required_opt_args[%d].def.flags = %s;\n",
- i, ro, flags_to_str(cmd->required_opt_args[ro].def.flags));
-
- if (val_bit_is_set(cmd->required_opt_args[ro].def.val_bits, constnum_VAL))
- printf("commands[%d].required_opt_args[%d].def.num = %d;\n",
- i, ro, cmd->required_opt_args[ro].def.num);
-
- if (val_bit_is_set(cmd->required_opt_args[ro].def.val_bits, conststr_VAL))
- printf("commands[%d].required_opt_args[%d].def.str = \"%s\";\n",
- i, ro, cmd->required_opt_args[ro].def.str ?: "NULL");
- }
- }
-
- if (cmd->rp_count) {
- for (rp = 0; rp < cmd->rp_count; rp++) {
- printf("commands[%d].required_pos_args[%d].pos = %d;\n",
- i, rp, cmd->required_pos_args[rp].pos);
-
- if (!cmd->required_pos_args[rp].def.val_bits)
- continue;
-
- printf("commands[%d].required_pos_args[%d].def.val_bits = %s;\n",
- i, rp, val_bits_to_str(cmd->required_pos_args[rp].def.val_bits));
-
- if (cmd->required_pos_args[rp].def.lvt_bits)
- printf("commands[%d].required_pos_args[%d].def.lvt_bits = %s;\n",
- i, rp, lvt_bits_to_str(cmd->required_pos_args[rp].def.lvt_bits));
-
- if (cmd->required_pos_args[rp].def.flags)
- printf("commands[%d].required_pos_args[%d].def.flags = %s;\n",
- i, rp, flags_to_str(cmd->required_pos_args[rp].def.flags));
-
- if (val_bit_is_set(cmd->required_pos_args[rp].def.val_bits, constnum_VAL))
- printf("commands[%d].required_pos_args[%d].def.num = %d;\n",
- i, rp, cmd->required_pos_args[rp].def.num);
-
- if (val_bit_is_set(cmd->required_pos_args[rp].def.val_bits, conststr_VAL))
- printf("commands[%d].required_pos_args[%d].def.str = \"%s\";\n",
- i, rp, cmd->required_pos_args[rp].def.str ?: "NULL");
- }
- }
-
- if (cmd->oo_count) {
- for (oo = 0; oo < cmd->oo_count; oo++) {
- printf("commands[%d].optional_opt_args[%d].opt = %s;\n",
- i, oo, opt_to_enum_str(cmd->optional_opt_args[oo].opt));
-
- if (!cmd->optional_opt_args[oo].def.val_bits)
- continue;
-
- printf("commands[%d].optional_opt_args[%d].def.val_bits = %s;\n",
- i, oo, val_bits_to_str(cmd->optional_opt_args[oo].def.val_bits));
-
- if (cmd->optional_opt_args[oo].def.lvt_bits)
- printf("commands[%d].optional_opt_args[%d].def.lvt_bits = %s;\n",
- i, oo, lvt_bits_to_str(cmd->optional_opt_args[oo].def.lvt_bits));
-
- if (cmd->optional_opt_args[oo].def.flags)
- printf("commands[%d].optional_opt_args[%d].def.flags = %s;\n",
- i, oo, flags_to_str(cmd->optional_opt_args[oo].def.flags));
-
- if (val_bit_is_set(cmd->optional_opt_args[oo].def.val_bits, constnum_VAL))
- printf("commands[%d].optional_opt_args[%d].def.num = %d;\n",
- i, oo, cmd->optional_opt_args[oo].def.num);
-
- if (val_bit_is_set(cmd->optional_opt_args[oo].def.val_bits, conststr_VAL))
- printf("commands[%d].optional_opt_args[%d].def.str = \"%s\";\n",
- i, oo, cmd->optional_opt_args[oo].def.str ?: "NULL");
- }
- }
-
- if (cmd->io_count) {
- for (io = 0; io < cmd->io_count; io++) {
- printf("commands[%d].ignore_opt_args[%d].opt = %s;\n",
- i, io, opt_to_enum_str(cmd->ignore_opt_args[io].opt));
-
- if (!cmd->ignore_opt_args[io].def.val_bits)
- continue;
-
- printf("commands[%d].ignore_opt_args[%d].def.val_bits = %s;\n",
- i, io, val_bits_to_str(cmd->ignore_opt_args[io].def.val_bits));
-
- if (cmd->ignore_opt_args[io].def.lvt_bits)
- printf("commands[%d].ignore_opt_args[%d].def.lvt_bits = %s;\n",
- i, io, lvt_bits_to_str(cmd->ignore_opt_args[io].def.lvt_bits));
-
- if (cmd->ignore_opt_args[io].def.flags)
- printf("commands[%d].ignore_opt_args[%d].def.flags = %s;\n",
- i, io, flags_to_str(cmd->ignore_opt_args[io].def.flags));
-
- if (val_bit_is_set(cmd->ignore_opt_args[io].def.val_bits, constnum_VAL))
- printf("commands[%d].ignore_opt_args[%d].def.num = %d;\n",
- i, io, cmd->ignore_opt_args[io].def.num);
-
- if (val_bit_is_set(cmd->ignore_opt_args[io].def.val_bits, conststr_VAL))
- printf("commands[%d].ignore_opt_args[%d].def.str = \"%s\";\n",
- i, io, cmd->ignore_opt_args[io].def.str ?: "NULL");
- }
- }
-
- if (cmd->op_count) {
- for (op = 0; op < cmd->op_count; op++) {
- printf("commands[%d].optional_pos_args[%d].pos = %d;\n",
- i, op, cmd->optional_pos_args[op].pos);
-
- if (!cmd->optional_pos_args[op].def.val_bits)
- continue;
-
- printf("commands[%d].optional_pos_args[%d].def.val_bits = %s;\n",
- i, op, val_bits_to_str(cmd->optional_pos_args[op].def.val_bits));
-
- if (cmd->optional_pos_args[op].def.lvt_bits)
- printf("commands[%d].optional_pos_args[%d].def.lvt_bits = %s;\n",
- i, op, lvt_bits_to_str(cmd->optional_pos_args[op].def.lvt_bits));
-
- if (cmd->optional_pos_args[op].def.flags)
- printf("commands[%d].optional_pos_args[%d].def.flags = %s;\n",
- i, op, flags_to_str(cmd->optional_pos_args[op].def.flags));
-
- if (val_bit_is_set(cmd->optional_pos_args[op].def.val_bits, constnum_VAL))
- printf("commands[%d].optional_pos_args[%d].def.num = %d;\n",
- i, op, cmd->optional_pos_args[op].def.num);
-
- if (val_bit_is_set(cmd->optional_pos_args[op].def.val_bits, conststr_VAL))
- printf("commands[%d].optional_pos_args[%d].def.str = \"%s\";\n",
- i, op, cmd->optional_pos_args[op].def.str ?: "NULL");
- }
- }
-
- if (cmd->rule_count) {
- for (ru = 0; ru < cmd->rule_count; ru++) {
-
- printf("commands[%d].rules[%d].opts_count = %d;\n", i, ru, cmd->rules[ru].opts_count);
-
- if (cmd->rules[ru].opts_count) {
- printf("static int _command%d_rule%d_opts[] = { ", i, ru);
- for (ruo = 0; ruo < cmd->rules[ru].opts_count; ruo++) {
- if (ruo)
- printf(", ");
- printf("%s", opt_to_enum_str(cmd->rules[ru].opts[ruo]));
- }
- printf(" };\n");
- printf("commands[%d].rules[%d].opts = _command%d_rule%d_opts;\n", i, ru, i, ru);
- } else {
- printf("commands[%d].rules[%d].opts = NULL;\n", i, ru);
- }
-
- printf("commands[%d].rules[%d].check_opts_count = %d;\n", i, ru, cmd->rules[ru].check_opts_count);
-
- if (cmd->rules[ru].check_opts_count) {
- printf("static int _command%d_rule%d_check_opts[] = { ", i, ru);
- for (ruo = 0; ruo < cmd->rules[ru].check_opts_count; ruo++) {
- if (ruo)
- printf(",");
- printf("%s ", opt_to_enum_str(cmd->rules[ru].check_opts[ruo]));
- }
- printf(" };\n");
- printf("commands[%d].rules[%d].check_opts = _command%d_rule%d_check_opts;\n", i, ru, i, ru);
- } else {
- printf("commands[%d].rules[%d].check_opts = NULL;\n", i, ru);
- }
-
- printf("commands[%d].rules[%d].lvt_bits = %s;\n", i, ru,
- cmd->rules[ru].lvt_bits ? lvt_bits_to_str(cmd->rules[ru].lvt_bits) : "0");
-
- printf("commands[%d].rules[%d].lvp_bits = %s;\n", i, ru,
- cmd->rules[ru].lvp_bits ? lvp_bits_to_str(cmd->rules[ru].lvp_bits) : "0");
-
- printf("commands[%d].rules[%d].rule = %s;\n", i, ru,
- rule_to_define_str(cmd->rules[ru].rule));
-
- printf("commands[%d].rules[%d].check_lvt_bits = %s;\n", i, ru,
- cmd->rules[ru].check_lvt_bits ? lvt_bits_to_str(cmd->rules[ru].check_lvt_bits) : "0");
-
- printf("commands[%d].rules[%d].check_lvp_bits = %s;\n", i, ru,
- cmd->rules[ru].check_lvp_bits ? lvp_bits_to_str(cmd->rules[ru].check_lvp_bits) : "0");
- }
- }
-
- printf("\n");
- }
-}
-
-struct cmd_pair {
- int i, j;
-};
-
-static void print_ambiguous(void)
-{
- struct command *cmd, *dup;
- struct cmd_pair dups[64] = { 0 };
- int found = 0;
- int i, j, f, ro, rp;
-
- for (i = 0; i < cmd_count; i++) {
- cmd = &cmd_array[i];
-
- for (j = 0; j < cmd_count; j++) {
- dup = &cmd_array[j];
-
- if (i == j)
- continue;
- if (strcmp(cmd->name, dup->name))
- continue;
- if (cmd->ro_count != dup->ro_count)
- continue;
- if (cmd->rp_count != dup->rp_count)
- continue;
-
- for (ro = 0; ro < cmd->ro_count; ro++) {
- if (!opt_arg_matches(&cmd->required_opt_args[ro],
- &dup->required_opt_args[ro]))
- goto next;
- }
-
- for (rp = 0; rp < cmd->rp_count; rp++) {
- if (!pos_arg_matches(&cmd->required_pos_args[rp],
- &dup->required_pos_args[rp]))
- goto next;
- }
-
- for (f = 0; f < found; f++) {
- if ((dups[f].i == j) && (dups[f].j == i))
- goto next;
- }
-
- printf("Ambiguous commands %d and %d:\n", i, j);
- print_usage(cmd);
- print_usage(dup);
- printf("\n");
-
- dups[found].i = i;
- dups[found].j = j;
- found++;
-next:
- ;
- }
- }
-}
-
-static int long_name_compare(const void *on1, const void *on2)
-{
- struct opt_name **optname1 = (void *)on1;
- struct opt_name **optname2 = (void *)on2;
- return strcmp((*optname1)->long_opt + 2, (*optname2)->long_opt + 2);
-}
-
-static void create_opt_names_alpha(void)
-{
- int i;
-
- for (i = 0; i < ARG_COUNT; i++)
- opt_names_alpha[i] = &opt_names[i];
-
- qsort(opt_names_alpha, ARG_COUNT, sizeof(long), long_name_compare);
-}
-
-void print_command_list(void)
-{
- int i;
-
- for (i = 0; i < MAX_CMD_NAMES; i++) {
- if (!cmd_names[i].name) {
- printf("found %d command names\n", i);
- break;
- }
- printf("%s\n", cmd_names[i].name);
- }
-}
-
-void print_option_list(void)
-{
- int i;
-
- for (i = 0; i < ARG_COUNT; i++)
- printf("%d %s %s %c (%d)\n",
- opt_names[i].opt_enum, opt_names[i].name,
- opt_names[i].long_opt, opt_names[i].short_opt ?: ' ',
- opt_names[i].short_opt ? opt_names[i].short_opt : 0);
-}
-
-void print_option_alpha_list(void)
-{
- int i;
-
- for (i = 0; i < ARG_COUNT; i++)
- printf("%d %s %s %c (%d)\n",
- opt_names_alpha[i]->opt_enum, opt_names_alpha[i]->name,
- opt_names_alpha[i]->long_opt, opt_names_alpha[i]->short_opt ?: ' ',
- opt_names_alpha[i]->short_opt ? opt_names_alpha[i]->short_opt : 0);
-}
-
-static void print_help(int argc, char *argv[])
-{
- printf("%s [options] --output <format> <filename>\n", argv[0]);
- printf("\n");
- printf("output formats:\n");
- printf("struct: print C structures for command-lines.h\n");
- printf("count: print defines and enums for command-lines-count.h\n");
- printf("ambiguous: print commands differing only by LV types\n");
- printf("usage: print usage format.\n");
- printf("expanded: print expanded input format.\n");
- printf("man: print man page format.\n");
- printf("\n");
- printf("options:\n");
- printf("-c|--man-command <commandname> man output for one command name\n");
-}
-
-int main(int argc, char *argv[])
-{
- char *outputformat = NULL;
- char *inputfile = NULL;
- FILE *file;
- struct command *cmd;
- char line[MAX_LINE];
- char line_orig[MAX_LINE];
- const char *name;
- char *line_argv[MAX_LINE_ARGC];
- char *n;
- int line_argc;
- int prev_was_oo_def = 0;
- int prev_was_oo = 0;
- int prev_was_op = 0;
-
- if (argc < 2) {
- print_help(argc, argv);
- exit(EXIT_FAILURE);
- }
-
- create_opt_names_alpha();
-
- if (!strcmp(argv[1], "debug")) {
- print_command_list();
- print_option_list();
- print_option_alpha_list();
- return 0;
- }
-
- static struct option long_options[] = {
- {"help", no_argument, 0, 'h' },
- {"output", required_argument, 0, 'o' },
- {"man-primary", required_argument, 0, 'p' },
- {"man-secondary", required_argument, 0, 's' },
- {"man-command", required_argument, 0, 'c' },
- {0, 0, 0, 0 }
- };
-
- while (1) {
- int c;
- int option_index = 0;
-
- c = getopt_long(argc, argv, "ho:p:s:c:",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case '0':
- break;
- case 'h':
- print_help(argc, argv);
- exit(EXIT_SUCCESS);
- case 'o':
- outputformat = strdup(optarg);
- break;
- case 'p':
- include_man_primary = atoi(optarg);
- break;
- case 's':
- include_man_secondary = atoi(optarg);
- break;
- case 'c':
- man_command_name = strdup(optarg);
- break;
- }
- }
-
- if (optind < argc)
- inputfile = argv[optind];
- else {
- printf("Missing filename.\n");
- return 0;
- }
-
- if (!(file = fopen(inputfile, "r"))) {
- printf("Cannot open %s\n", argv[1]);
- return -1;
- }
-
- while (fgets(line, MAX_LINE, file)) {
- if (line[0] == '#')
- continue;
- if (line[0] == '\n')
- continue;
- if (line[0] == '-' && line[1] == '-' && line[2] == '-')
- continue;
-
- if ((n = strchr(line, '\n')))
- *n = '\0';
-
- memcpy(line_orig, line, sizeof(line));
- split_line(line, &line_argc, line_argv, ' ');
-
- if (!line_argc)
- continue;
-
- /* command ... */
- if ((name = is_command_name(line_argv[0]))) {
- if (cmd_count >= MAX_CMDS) {
- printf("MAX_CMDS too small\n");
- return -1;
- }
- cmd = &cmd_array[cmd_count++];
- cmd->name = name;
- cmd->pos_count = 1;
- add_required_line(cmd, line_argc, line_argv);
-
- /* Every cmd gets the OO_ALL options */
- include_optional_opt_args(cmd, "OO_ALL:");
- continue;
- }
-
- if (is_desc_line(line_argv[0])) {
- char *desc = strdup(line_orig);
- if (cmd->desc) {
- int newlen = strlen(cmd->desc) + strlen(desc) + 2;
- char *newdesc = malloc(newlen);
- memset(newdesc, 0, newlen);
- snprintf(newdesc, newlen, "%s %s", cmd->desc, desc);
- cmd->desc = newdesc;
- free(desc);
- } else
- cmd->desc = desc;
- continue;
- }
-
- if (is_flags_line(line_argv[0])) {
- add_flags(cmd, line_orig);
- continue;
- }
-
- if (is_rule_line(line_argv[0])) {
- add_rule(cmd, line_orig);
- continue;
- }
-
- if (is_id_line(line_argv[0])) {
- cmd->command_line_id = strdup(line_argv[1]);
- continue;
- }
-
- /* OO_FOO: ... */
- if (is_oo_definition(line_argv[0])) {
- add_oo_definition_line(line_argv[0], line_orig);
- prev_was_oo_def = 1;
- prev_was_oo = 0;
- prev_was_op = 0;
- continue;
- }
-
- /* OO: ... */
- if (is_oo_line(line_argv[0])) {
- add_optional_opt_line(cmd, line_argc, line_argv);
- prev_was_oo_def = 0;
- prev_was_oo = 1;
- prev_was_op = 0;
- continue;
- }
-
- /* OP: ... */
- if (is_op_line(line_argv[0])) {
- add_optional_pos_line(cmd, line_argc, line_argv);
- prev_was_oo_def = 0;
- prev_was_oo = 0;
- prev_was_op = 1;
- continue;
- }
-
- /* IO: ... */
- if (is_io_line(line_argv[0])) {
- add_ignore_opt_line(cmd, line_argc, line_argv);
- prev_was_oo = 0;
- prev_was_op = 0;
- continue;
- }
-
- /* handle OO_FOO:, OO:, OP: continuing on multiple lines */
-
- if (prev_was_oo_def) {
- append_oo_definition_line(line_orig);
- continue;
- }
-
- if (prev_was_oo) {
- add_optional_opt_line(cmd, line_argc, line_argv);
- continue;
- }
-
- if (prev_was_op) {
- add_optional_pos_line(cmd, line_argc, line_argv);
- continue;
- }
- }
-
- fclose(file);
-
- factor_common_options();
-
- if (!outputformat)
- print_command_struct(1);
- else if (!strcmp(outputformat, "struct")) {
- print_command_struct(0);
- print_ambiguous();
- }
- else if (!strcmp(outputformat, "count"))
- print_command_count();
- else if (!strcmp(outputformat, "usage"))
- print_command_struct(1);
- else if (!strcmp(outputformat, "expanded"))
- print_expanded();
- else if (!strcmp(outputformat, "ambiguous"))
- print_ambiguous();
- else if (!strcmp(outputformat, "man"))
- print_man_command();
- else
- print_help(argc, argv);
-
- return 0;
-}
-
7 years, 3 months
master - command struct: remove command name refs
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=013c080756dcc2...
Commit: 013c080756dcc2faaecc80b489d85d7ab1384cbf
Parent: d9d5b8414bb5ead7dbd223606a735497c0c069f9
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jan 13 15:08:51 2017 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Feb 13 08:20:10 2017 -0600
command struct: remove command name refs
Change run time access to the command_name struct
cmd->cname instead of indirectly through
cmd->command->cname. This removes the two run time
fields from struct command.
---
lib/commands/toolcontext.h | 1 +
tools/command.h | 4 ----
tools/lvconvert.c | 4 ++--
tools/lvmcmdline.c | 23 +++++++++++------------
tools/pvscan.c | 2 +-
tools/toollib.c | 18 +++++++++---------
tools/vgchange.c | 2 +-
tools/vgimportclone.c | 2 +-
8 files changed, 26 insertions(+), 30 deletions(-)
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index 2dc1c28..20b24f9 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -89,6 +89,7 @@ struct cmd_context {
*/
const char *cmd_line;
const char *name; /* needed before cmd->command is set */
+ struct command_name *cname;
struct command *command;
char **argv;
struct arg_values *opt_arg_values;
diff --git a/tools/command.h b/tools/command.h
index d66ec52..c9be260 100644
--- a/tools/command.h
+++ b/tools/command.h
@@ -164,13 +164,9 @@ struct command {
const char *command_line_id;
int command_line_enum; /* <command_line_id>_CMD */
- struct command_name *cname;
-
command_fn fn; /* old style */
struct command_function *functions; /* new style */
- unsigned int flags; /* copied from command_name.flags from commands.h */
-
unsigned int cmd_flags; /* CMD_FLAG_ */
/* definitions of opt/pos args */
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 757e8b4..1d7dc1b 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -4512,7 +4512,7 @@ static int _lvconvert_merge_mirror_images_single(struct cmd_context *cmd,
int lvconvert_merge_mirror_images_cmd(struct cmd_context *cmd, int argc, char **argv)
{
/* arg can be a VG name, which is the standard option usage */
- cmd->command->flags &= ~GET_VGNAME_FROM_OPTIONS;
+ cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
return process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
NULL, &_lvconvert_visible_check, &_lvconvert_merge_mirror_images_single);
@@ -4552,7 +4552,7 @@ int lvconvert_merge_cmd(struct cmd_context *cmd, int argc, char **argv)
handle->custom_handle = &lr;
- cmd->command->flags &= ~GET_VGNAME_FROM_OPTIONS;
+ cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
handle, NULL, &_lvconvert_merge_generic_single);
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index ddc87f9..dda4b16 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -1092,7 +1092,6 @@ static void _define_commands(void)
void lvm_register_commands(void)
{
- struct command_name *cname;
int i;
memset(&commands, 0, sizeof(commands));
@@ -1102,13 +1101,8 @@ void lvm_register_commands(void)
_cmdline.commands = commands;
_cmdline.num_commands = COMMAND_COUNT;
- for (i = 0; i < COMMAND_COUNT; i++) {
- if (!(cname = _find_command_name(commands[i].name)))
- log_error(INTERNAL_ERROR "Failed to find command name %s.", commands[i].name);
- commands[i].cname = cname;
- commands[i].flags = cname->flags;
+ for (i = 0; i < COMMAND_COUNT; i++)
commands[i].functions = _find_command_function(commands[i].command_line_enum);
- }
_cmdline.command_names = command_names;
@@ -2193,7 +2187,7 @@ static int _get_settings(struct cmd_context *cmd)
cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive);
cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup);
- cmd->current_settings.cache_vgmetadata = cmd->command->flags & CACHE_VGMETADATA ? 1 : 0;
+ cmd->current_settings.cache_vgmetadata = cmd->cname->flags & CACHE_VGMETADATA ? 1 : 0;
if (arg_is_set(cmd, readonly_ARG)) {
cmd->current_settings.activation = 0;
@@ -2201,7 +2195,7 @@ static int _get_settings(struct cmd_context *cmd)
cmd->current_settings.backup = 0;
}
- if (cmd->command->flags & LOCKD_VG_SH)
+ if (cmd->cname->flags & LOCKD_VG_SH)
cmd->lockd_vg_default_sh = 1;
cmd->partial_activation = 0;
@@ -2613,7 +2607,7 @@ static int _init_lvmlockd(struct cmd_context *cmd)
static int _cmd_no_meta_proc(struct cmd_context *cmd)
{
- return cmd->command->flags & NO_METADATA_PROCESSING;
+ return cmd->cname->flags & NO_METADATA_PROCESSING;
}
int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
@@ -2688,6 +2682,11 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
log_debug("Parsing: %s", cmd->cmd_line);
+ if (!(cmd->cname = _find_command_name(cmd->name))) {
+ log_error("Command name not found.\n");
+ return EINVALID_CMD_LINE;
+ }
+
if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv)))
return EINVALID_CMD_LINE;
@@ -2772,7 +2771,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
}
if (cmd->metadata_read_only &&
- !(cmd->command->flags & PERMITTED_READ_ONLY)) {
+ !(cmd->cname->flags & PERMITTED_READ_ONLY)) {
log_error("%s: Command not permitted while global/metadata_read_only "
"is set.", cmd->cmd_line);
goto out;
@@ -2832,7 +2831,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
* In this case, disable the *use* of lvmetad by this command, reverting to
* disk scanning.
*/
- if (lvmetad_used() && !(cmd->command->flags & NO_LVMETAD_AUTOSCAN)) {
+ if (lvmetad_used() && !(cmd->cname->flags & NO_LVMETAD_AUTOSCAN)) {
if (cmd->include_foreign_vgs || !lvmetad_token_matches(cmd)) {
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, cmd->include_foreign_vgs ? 1 : 0)) {
log_warn("WARNING: Not using lvmetad because cache update failed.");
diff --git a/tools/pvscan.c b/tools/pvscan.c
index e2b0a83..ca33a2a 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -284,7 +284,7 @@ static int _pvscan_autoactivate(struct cmd_context *cmd, struct pvscan_aa_params
handle->custom_handle = pp;
if (all_vgs) {
- cmd->command->flags |= ALL_VGS_IS_DEFAULT;
+ cmd->cname->flags |= ALL_VGS_IS_DEFAULT;
pp->refresh_all = 1;
}
diff --git a/tools/toollib.c b/tools/toollib.c
index 36599e0..2c0096f 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -2093,7 +2093,7 @@ static void _choose_vgs_to_process(struct cmd_context *cmd,
* matches the UUID of a VG. (--select should generally
* be used to select a VG by uuid instead.)
*/
- if (!found && (cmd->command->flags & ALLOW_UUID_AS_NAME))
+ if (!found && (cmd->cname->flags & ALLOW_UUID_AS_NAME))
arg_is_uuid = id_read_format_try(&id, sl->str);
if (!found && arg_is_uuid) {
@@ -2162,7 +2162,7 @@ int process_each_vg(struct cmd_context *cmd,
struct dm_list arg_vgnames; /* str_list */
struct dm_list vgnameids_on_system; /* vgnameid_list */
struct dm_list vgnameids_to_process; /* vgnameid_list */
- int enable_all_vgs = (cmd->command->flags & ALL_VGS_IS_DEFAULT);
+ int enable_all_vgs = (cmd->cname->flags & ALL_VGS_IS_DEFAULT);
int process_all_vgs_on_system = 0;
int ret_max = ECMD_PROCESSED;
int ret;
@@ -2209,7 +2209,7 @@ int process_each_vg(struct cmd_context *cmd,
* label scan to be done. get_vgnameids() will scan labels
* (when not using lvmetad).
*/
- if (cmd->command->flags & REQUIRES_FULL_LABEL_SCAN) {
+ if (cmd->cname->flags & REQUIRES_FULL_LABEL_SCAN) {
dev_cache_full_scan(cmd->full_filter);
lvmcache_force_next_label_scan();
}
@@ -3655,7 +3655,7 @@ int process_each_lv(struct cmd_context *cmd,
struct dm_list arg_lvnames; /* str_list */
struct dm_list vgnameids_on_system; /* vgnameid_list */
struct dm_list vgnameids_to_process; /* vgnameid_list */
- int enable_all_vgs = (cmd->command->flags & ALL_VGS_IS_DEFAULT);
+ int enable_all_vgs = (cmd->cname->flags & ALL_VGS_IS_DEFAULT);
int process_all_vgs_on_system = 0;
int ret_max = ECMD_PROCESSED;
int ret;
@@ -3674,7 +3674,7 @@ int process_each_lv(struct cmd_context *cmd,
/*
* Find any LVs, VGs or tags explicitly provided on the command line.
*/
- if (cmd->command->flags & GET_VGNAME_FROM_OPTIONS)
+ if (cmd->cname->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);
@@ -4032,7 +4032,7 @@ static int _process_duplicate_pvs(struct cmd_context *cmd,
if (!process_all_devices && !dil)
continue;
- if (!(cmd->command->flags & ENABLE_DUPLICATE_DEVS))
+ if (!(cmd->cname->flags & ENABLE_DUPLICATE_DEVS))
continue;
/*
@@ -4387,7 +4387,7 @@ int process_each_pv(struct cmd_context *cmd,
goto_out;
}
- if ((cmd->command->flags & DISALLOW_TAG_ARGS) && !dm_list_empty(&arg_tags)) {
+ if ((cmd->cname->flags & DISALLOW_TAG_ARGS) && !dm_list_empty(&arg_tags)) {
log_error("Tags cannot be used with this command.");
return ECMD_FAILED;
}
@@ -4396,7 +4396,7 @@ int process_each_pv(struct cmd_context *cmd,
process_all_pvs = dm_list_empty(&arg_pvnames) && dm_list_empty(&arg_tags);
- process_all_devices = process_all_pvs && (cmd->command->flags & ENABLE_ALL_DEVS) && all_is_set;
+ process_all_devices = process_all_pvs && (cmd->cname->flags & ENABLE_ALL_DEVS) && all_is_set;
/* Needed for a current listing of the global VG namespace. */
if (!only_this_vgname && !lockd_gl(cmd, "sh", 0)) {
@@ -5285,7 +5285,7 @@ int pvcreate_each_device(struct cmd_context *cmd,
struct pv_list *vgpvl;
const char *pv_name;
int consistent = 0;
- int must_use_all = (cmd->command->flags & MUST_USE_ALL_ARGS);
+ int must_use_all = (cmd->cname->flags & MUST_USE_ALL_ARGS);
int found;
unsigned i;
diff --git a/tools/vgchange.c b/tools/vgchange.c
index 4cf8a3c..2a8f868 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -1095,7 +1095,7 @@ static int _lockd_vgchange(struct cmd_context *cmd, int argc, char **argv)
*/
if (arg_is_set(cmd, systemid_ARG) || arg_is_set(cmd, locktype_ARG))
- cmd->command->flags &= ~ALL_VGS_IS_DEFAULT;
+ cmd->cname->flags &= ~ALL_VGS_IS_DEFAULT;
if (arg_is_set(cmd, systemid_ARG) || arg_is_set(cmd, locktype_ARG)) {
/*
diff --git a/tools/vgimportclone.c b/tools/vgimportclone.c
index b23b14e..1f86ad6 100644
--- a/tools/vgimportclone.c
+++ b/tools/vgimportclone.c
@@ -240,7 +240,7 @@ int vgimportclone(struct cmd_context *cmd, int argc, char **argv)
*/
log_debug("Finding devices to import.");
- cmd->command->flags |= ENABLE_DUPLICATE_DEVS;
+ cmd->cname->flags |= ENABLE_DUPLICATE_DEVS;
process_each_pv(cmd, argc, argv, NULL, 0, READ_ALLOW_EXPORTED, handle, _vgimportclone_pv_single);
if (vp.found_args != argc) {
7 years, 3 months
master - command.h comment tidying
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d9d5b8414bb5ea...
Commit: d9d5b8414bb5ead7dbd223606a735497c0c069f9
Parent: 9a0f0c70bf59a5cd07828ff39e5ff04b4a5411ad
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jan 13 14:51:50 2017 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Feb 13 08:20:10 2017 -0600
command.h comment tidying
---
tools/command.h | 14 ++++++--------
1 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/tools/command.h b/tools/command.h
index e4ce989..d66ec52 100644
--- a/tools/command.h
+++ b/tools/command.h
@@ -110,7 +110,6 @@ struct pos_arg {
};
/*
- *
* Commands using a given command definition must follow a set
* of rules. If a given command+LV matches the conditions in
* opts/lvt_bits/lvp_bits, then the checks are applied.
@@ -133,10 +132,11 @@ struct cmd_rule {
uint32_t rule; /* RULE_INVALID, RULE_REQUIRE: check values must [not] be true */
int opts_count; /* entries in opts[] */
int check_opts_count; /* entries in check_opts[] */
-
};
/*
+ * Array sizes
+ *
* CMD_RO_ARGS needs to accomodate a list of options,
* of which one is required after which the rest are
* optional.
@@ -152,8 +152,8 @@ struct cmd_rule {
* one or more from required_opt_args is required,
* then the rest are optional.
*/
-#define CMD_FLAG_ONE_REQUIRED_OPT 1
-#define CMD_FLAG_SECONDARY_SYNTAX 2
+#define CMD_FLAG_ONE_REQUIRED_OPT 1 /* lvchange/vgchage require one item from required_opt_args */
+#define CMD_FLAG_SECONDARY_SYNTAX 2 /* allows syntax variants to be suppressed in certain output */
/* a register of the lvm commands */
struct command {
@@ -197,11 +197,9 @@ struct command {
int rp_count;
int op_count;
int io_count;
-
- /* used for processing current position */
- int pos_count;
-
int rule_count;
+
+ int pos_count; /* temp counter used by create-command */
};
#endif
7 years, 3 months
master - lvm shell: clear argv for each command
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=9a0f0c70bf59a5...
Commit: 9a0f0c70bf59a5cd07828ff39e5ff04b4a5411ad
Parent: 23a1ced4397b699ae572570ec772683d7003de6f
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jan 13 12:02:06 2017 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Feb 13 08:20:10 2017 -0600
lvm shell: clear argv for each command
---
tools/lvm.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/tools/lvm.c b/tools/lvm.c
index aae6da0..5fd9918 100644
--- a/tools/lvm.c
+++ b/tools/lvm.c
@@ -210,7 +210,7 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
{
log_report_t saved_log_report_state = log_get_report_state();
char *orig_command_log_selection = NULL;
- int is_lastlog_cmd = 0, argc, ret;
+ int is_lastlog_cmd = 0, argc, ret, i;
char *input = NULL, *args[MAX_ARGS], **argv;
rl_readline_name = "lvm";
@@ -262,6 +262,9 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
add_history(input);
+ for (i = 0; i < MAX_ARGS; i++)
+ args[i] = NULL;
+
argv = args;
if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
7 years, 3 months
master - help: accept positional args
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=23a1ced4397b69...
Commit: 23a1ced4397b699ae572570ec772683d7003de6f
Parent: 3642deb4f3b7ade1109aeb0ef2cffb38f31ff7c6
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jan 13 11:31:49 2017 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Feb 13 08:20:10 2017 -0600
help: accept positional args
lvm help <commandname> ...
---
tools/command-lines.in | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/tools/command-lines.in b/tools/command-lines.in
index f99cb8c..81c70ba 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1589,6 +1589,7 @@ formats
ID: formats_general
help
+OP: String ...
ID: help_general
version
7 years, 3 months
master - fix lvmcmdline warning
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=3642deb4f3b7ad...
Commit: 3642deb4f3b7ade1109aeb0ef2cffb38f31ff7c6
Parent: 4d2c3502e79e34a5cf0fdb65c2a4df23aa1b2ecb
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jan 12 14:36:31 2017 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Feb 13 08:20:10 2017 -0600
fix lvmcmdline warning
declaration of ���usage��� shadows a globa
---
tools/lvmcmdline.c | 40 ++++++++++++++++++++--------------------
1 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index afc941b..ddc87f9 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -1288,7 +1288,7 @@ static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp
#define HELP_LINE_SIZE 1024
-static void _print_usage(const char *usage, int only_required)
+static void _print_usage(const char *usage_str, int only_required)
{
char buf[HELP_LINE_SIZE];
int optional_ui = 0;
@@ -1296,7 +1296,7 @@ static void _print_usage(const char *usage, int only_required)
int ui;
int bi;
- if (!usage || !strlen(usage))
+ if (!usage_str || !strlen(usage_str))
return;
/*
@@ -1313,32 +1313,32 @@ static void _print_usage(const char *usage, int only_required)
memset(buf, 0, sizeof(buf));
bi = 0;
- for (ui = 0; ui < strlen(usage); ui++) {
- if (!bi && ((usage[ui] == ' ') || (usage[ui] == '\n')))
+ for (ui = 0; ui < strlen(usage_str); ui++) {
+ if (!bi && ((usage_str[ui] == ' ') || (usage_str[ui] == '\n')))
continue;
/* The first "[ " indicates the start of the optional opt_args. */
- if ((usage[ui] == '[') && (usage[ui+1] == ' ')) {
+ if ((usage_str[ui] == '[') && (usage_str[ui+1] == ' ')) {
optional_ui = ui;
break;
}
- if (usage[ui] == '\0')
+ if (usage_str[ui] == '\0')
break;
- if (usage[ui] == '(') {
+ if (usage_str[ui] == '(') {
buf[bi++] = '\n';
buf[bi++] = '\t';
}
- buf[bi++] = usage[ui];
+ buf[bi++] = usage_str[ui];
- if (usage[ui] == ')') {
+ if (usage_str[ui] == ')') {
buf[bi++] = '\n';
buf[bi++] = '\t';
}
- if (usage[ui] == ',') {
+ if (usage_str[ui] == ',') {
buf[bi++] = '\n';
buf[bi++] = '\t';
buf[bi++] = ' ';
@@ -1368,25 +1368,25 @@ static void _print_usage(const char *usage, int only_required)
memset(buf, 0, sizeof(buf));
bi = 0;
- for (ui = optional_ui; ui < strlen(usage); ui++) {
+ for (ui = optional_ui; ui < strlen(usage_str); ui++) {
/* The second "[ " indicates the start of the optional pos_args. */
- if ((ui > optional_ui) && (usage[ui] == '[') && (usage[ui+1] == ' ')) {
+ if ((ui > optional_ui) && (usage_str[ui] == '[') && (usage_str[ui+1] == ' ')) {
optional_pos_ui = ui;
break;
}
- if (usage[ui] == '\0')
+ if (usage_str[ui] == '\0')
break;
- if (usage[ui] == '\n')
+ if (usage_str[ui] == '\n')
break;
if (!bi)
buf[bi++] = '\t';
- buf[bi++] = usage[ui];
+ buf[bi++] = usage_str[ui];
- if (usage[ui] == ',') {
+ if (usage_str[ui] == ',') {
buf[bi++] = '\n';
buf[bi++] = '\t';
buf[bi++] = ' ';
@@ -1413,16 +1413,16 @@ static void _print_usage(const char *usage, int only_required)
memset(buf, 0, sizeof(buf));
bi = 0;
- for (ui = optional_pos_ui; ui < strlen(usage); ui++) {
- if (usage[ui] == '\0')
+ for (ui = optional_pos_ui; ui < strlen(usage_str); ui++) {
+ if (usage_str[ui] == '\0')
break;
- if (usage[ui] == '\n')
+ if (usage_str[ui] == '\n')
break;
if (!bi)
buf[bi++] = '\t';
- buf[bi++] = usage[ui];
+ buf[bi++] = usage_str[ui];
if (bi == (HELP_LINE_SIZE - 1))
break;
7 years, 3 months
master - man lvm: remove options
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=4d2c3502e79e34...
Commit: 4d2c3502e79e34a5cf0fdb65c2a4df23aa1b2ecb
Parent: 5c779b323132bfd2ddc5cf639a6fcd3e9b10a309
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jan 12 16:08:53 2017 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Feb 13 08:20:10 2017 -0600
man lvm: remove options
all options are now included in commands
---
man/lvm.8.in | 258 +---------------------------------------------------------
1 files changed, 3 insertions(+), 255 deletions(-)
diff --git a/man/lvm.8.in b/man/lvm.8.in
index cad724b..0a64e4f 100644
--- a/man/lvm.8.in
+++ b/man/lvm.8.in
@@ -45,6 +45,9 @@ A file containing a simple script with one command per line
can also be given on the command line. The script can also be
executed directly if the first line is #! followed by the absolute
path of \fBlvm\fP.
+.P
+Additional hyphens within option names are ignored. For example,
+\fB\-\-readonly\fP and \fB\-\-read\-only\fP are both accepted.
.
.SH BUILT-IN COMMANDS
.
@@ -238,261 +241,6 @@ The following commands are not implemented in LVM2 but might be
in the future:
.BR lvmsadc ", " lvmsar ", " pvdata .
.
-.SH OPTIONS
-.
-The following options are available for many of the commands.
-They are implemented generically and documented here rather
-than repeated on individual manual pages.
-.P
-Additional hyphens within option names are ignored. For example,
-\fB\-\-readonly\fP and \fB\-\-read\-only\fP are both accepted.
-.
-.HP
-.BR \-h | \-? | \-\-help
-.br
-Display the help text.
-.
-.HP
-.BR \-\-version
-.br
-Display version information.
-.
-.HP
-.BR \-v | \-\-verbose
-.br
-Set verbose level. Repeat from 1 to 3 times to increase the detail
-of messages sent to stdout and stderr. Overrides config file setting.
-.
-.HP
-.BR \-d | \-\-debug
-.br
-Set debug level. Repeat from 1 to 6 times to increase the detail of
-messages sent to the log file and/or syslog (if configured).
-Overrides config file setting.
-.
-.HP
-.BR \-q | \-\-quiet
-.br
-Suppress output and log messages.
-Overrides \fB\-d\fP and \fB\-v\fP.
-Repeat once to also suppress any prompts with answer 'no'.
-.
-.HP
-.BR \-\-yes
-.br
-Don't prompt for confirmation interactively but instead always assume the
-answer is 'yes'. Take great care if you use this!
-.
-.HP
-.BR \-t | \-\-test
-.br
-Run in test mode. Commands will not update metadata.
-This is implemented by disabling all metadata writing but nevertheless
-returning success to the calling function. This may lead to unusual
-error messages in multi-stage operations if a tool relies on reading
-back metadata it believes has changed but hasn't.
-.
-.HP
-.BR \-\-driverloaded
-.RB { y | n }
-.br
-Whether or not the device-mapper kernel driver is loaded.
-If you set this to \fBn\fP, no attempt will be made to contact the driver.
-.
-.HP
-.BR \-A | \-\-autobackup
-.RB { y | n }
-.br
-Whether or not to metadata should be backed up automatically after a change.
-You are strongly advised not to disable this!
-See \fBvgcfgbackup\fP(8).
-.
-.HP
-.BR \-P | \-\-partial
-.br
-When set, the tools will do their best to provide access to Volume Groups
-that are only partially available (one or more Physical Volumes belonging
-to the Volume Group are missing from the system). Where part of a logical
-volume is missing, \fI\%/dev/ioerror\fP will be substituted, and you could use
-\fBdmsetup\fP(8) to set this up to return I/O errors when accessed,
-or create it as a large block device of nulls. Metadata may not be
-changed with this option. To insert a replacement Physical Volume
-of the same or large size use \fBpvcreate \-u\fP to set the uuid to
-match the original followed by \fBvgcfgrestore\fP(8).
-.
-.HP
-.BR \-S | \-\-select
-.IR Selection
-.br
-For reporting commands, display only rows that match \fISelection\fP criteria.
-All rows are displayed with the additional "selected" column (\fB-o selected\fP)
-showing 1 if the row matches the \fISelection\fP and 0 otherwise. For non-reporting
-commands which process LVM entities, the selection can be used to match items
-to process. See \fBSelection\fP section in \fBlvmreport\fP(7) man page for more
-information about the way the selection criteria are constructed.
-.
-.HP
-.BR \-M | \-\-metadatatype
-.IR Type
-.br
-Specifies which \fItype\fP of on-disk metadata to use, such as \fBlvm1\fP
-or \fBlvm2\fP, which can be abbreviated to \fB1\fP or \fB2\fP respectively.
-The default (\fBlvm2\fP) can be changed by setting \fBformat\fP
-in the \fBglobal\fP section of the config file \fBlvm.conf\fP(5).
-.
-.HP
-.BR \-\-ignorelockingfailure
-.br
-This lets you proceed with read-only metadata operations such as
-\fBlvchange \-ay\fP and \fBvgchange \-ay\fP even if the locking module fails.
-One use for this is in a system init script if the lock directory
-is mounted read-only when the script runs.
-.
-.HP
-.BR \-\-ignoreskippedcluster
-.br
-Use to avoid exiting with an non-zero status code if the command is run
-without clustered locking and some clustered Volume Groups have to be
-skipped over.
-.
-.HP
-.BR \-\-readonly
-.br
-Run the command in a special read-only mode which will read on-disk
-metadata without needing to take any locks. This can be used to peek
-inside metadata used by a virtual machine image while the virtual
-machine is running.
-It can also be used to peek inside the metadata of clustered Volume
-Groups when clustered locking is not configured or running. No attempt
-will be made to communicate with the device-mapper kernel driver, so
-this option is unable to report whether or not Logical Volumes are
-actually in use.
-.
-.HP
-.BR \-\-foreign
-.br
-Cause the command to access foreign VGs, that would otherwise be skipped.
-It can be used to report or display a VG that is owned by another host.
-This option can cause a command to perform poorly because lvmetad caching
-is not used and metadata is read from disks.
-.
-.HP
-.BR \-\-shared
-.br
-Cause the command to access shared VGs, that would otherwise be skipped
-when lvmlockd is not being used. It can be used to report or display a
-lockd VG without locking. Applicable only if LVM is compiled with lockd
-support.
-.
-.HP
-.BR \-\-addtag
-.IR Tag
-.br
-Add the tag \fITag\fP to a PV, VG or LV.
-Supply this argument multiple times to add more than one tag at once.
-A tag is a word that can be used to group LVM2 objects of the same type
-together.
-Tags can be given on the command line in place of PV, VG or LV
-arguments. Tags should be prefixed with @ to avoid ambiguity.
-Each tag is expanded by replacing it with all objects possessing
-that tag which are of the type expected by its position on the command line.
-PVs can only possess tags while they are part of a Volume Group:
-PV tags are discarded if the PV is removed from the VG.
-As an example, you could tag some LVs as \fBdatabase\fP and others
-as \fBuserdata\fP and then activate the database ones
-with \fBlvchange \-ay @database\fP.
-Objects can possess multiple tags simultaneously.
-Only the new LVM2 metadata format supports tagging: objects using the
-LVM1 metadata format cannot be tagged because the on-disk format does not
-support it.
-Characters allowed in tags are:
-.BR A - Z
-.BR a - z
-.BR 0 - 9
-.BR "_ + . -"
-and as of version 2.02.78 the following characters are also accepted:
-.BR "/ = ! : # &" .
-.
-.HP
-.BR \-\-deltag
-.IR Tag
-.br
-Delete the tag \fITag\fP from a PV, VG or LV, if it's present.
-Supply this argument multiple times to remove more than one tag at once.
-.
-.HP
-.BR \-\-alloc
-.RB { anywhere | contiguous | cling | inherit | normal }
-.br
-Selects the allocation policy when a command needs to allocate
-Physical Extents from the Volume Group.
-Each Volume Group and Logical Volume has an allocation policy defined.
-The default for a Volume Group is \fBnormal\fP which applies
-common-sense rules such as not placing parallel stripes on the same
-Physical Volume. The default for a Logical Volume is \fBinherit\fP
-which applies the same policy as for the Volume Group. These policies can
-be changed using \fBlvchange\fP(8) and \fBvgchange\fP(8) or overridden
-on the command line of any command that performs allocation.
-The \fBcontiguous\fP policy requires that new Physical Extents be placed adjacent
-to existing Physical Extents.
-The \fBcling\fP policy places new Physical Extents on the same Physical
-Volume as existing Physical Extents in the same stripe of the Logical Volume.
-If there are sufficient free Physical Extents to satisfy
-an allocation request but \fBnormal\fP doesn't use them,
-\fBanywhere\fP will - even if that reduces performance by
-placing two stripes on the same Physical Volume.
-.
-.HP
-.BR \-\-commandprofile
-.IR ProfileName
-.br
-Selects the command configuration profile to use when processing an LVM command.
-See also \fBlvm.conf\fP(5) for more information about \fBcommand profile config\fP and
-the way it fits with other LVM configuration methods. Using \fB\-\-commandprofile\fP
-option overrides any command profile specified via \fBLVM_COMMAND_PROFILE\fP
-environment variable.
-.
-.HP
-.BR \-\-metadataprofile
-.IR ProfileName
-.br
-Selects the metadata configuration profile to use when processing an LVM command.
-When using metadata profile during Volume Group or Logical Volume creation,
-the metadata profile name is saved in metadata. When such Volume Group or Logical
-Volume is processed next time, the metadata profile is automatically applied
-and the use of \fB\-\-metadataprofile\fP option is not necessary. See also
-\fBlvm.conf\fP(5) for more information about \fBmetadata profile config\fP and the
-way it fits with other LVM configuration methods.
-.
-.HP
-.BR \-\-profile
-.IR ProfileName
-.br
-A short form of \fB\-\-metadataprofile\fP for \fBvgcreate\fP, \fBlvcreate\fP,
-\fBvgchange\fP and \fBlvchange\fP command and a short form of \fB\-\-commandprofile\fP
-for any other command (with the exception of \fBlvmconfig\fP command where the
-\fB\-\-profile\fP has special meaning, see \fBlvmconfig\fP(8) for more information).
-.
-.HP
-.BR \-\-reportformat
-.IR {basic|json}
-.br
-Overrides current output format for reports which is defined globally by
-\fBreport/output_format\fP configuration setting in \fBlvm.conf\fP(5).
-The \fBbasic\fP format is the original format with columns and rows and
-if there is more than one report per command, each report is prefixed
-with report's name for identification. The \fBjson\fP stands for report
-output in JSON format.
-.HP
-.BR \-\-config
-.IR ConfigurationString
-.br
-Uses the ConfigurationString as direct string representation of the configuration
-to override the existing configuration. The ConfigurationString is of exactly
-the same format as used in any LVM configuration file. See \fBlvm.conf\fP(5)
-for more information about \fBdirect config override on command line\fP and the
-way it fits with other LVM configuration methods.
-.
.SH VALID NAMES
.
The valid characters for VG and LV names are:
7 years, 3 months
master - args: add man page descriptions
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=5c779b323132bf...
Commit: 5c779b323132bfd2ddc5cf639a6fcd3e9b10a309
Parent: db26a82f2f464d0f710229c24d67c83818fd8f3c
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jan 6 16:56:59 2017 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Feb 13 08:20:10 2017 -0600
args: add man page descriptions
---
tools/args.h | 1582 ++++++++++++++++++++++++++++++++++++++++-------
tools/create-commands.c | 292 +++++++--
tools/lvmcmdline.c | 2 +-
tools/tools.h | 3 +-
4 files changed, 1611 insertions(+), 268 deletions(-)
diff --git a/tools/args.h b/tools/args.h
index 690b4ee..8802cd7 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -17,221 +17,1385 @@
* Put all long args that don't have a corresponding short option first.
*/
/* *INDENT-OFF* */
-arg(ARG_UNUSED, '-', "", 0, 0, 0) /* place holder for unused 0 value */
-
-arg(abort_ARG, '\0', "abort", 0, 0, 0)
-arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0)
-arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0)
-arg(aligned_ARG, '\0', "aligned", 0, 0, 0)
-arg(alloc_ARG, '\0', "alloc", alloc_VAL, 0, 0)
-arg(atomic_ARG, '\0', "atomic", 0, 0, 0)
-arg(atversion_ARG, '\0', "atversion", string_VAL, 0, 0)
-arg(binary_ARG, '\0', "binary", 0, 0, 0)
-arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", sizemb_VAL, 0, 0)
-arg(cache_long_ARG, '\0', "cache", 0, 0, 0)
-arg(cachemode_ARG, '\0', "cachemode", cachemode_VAL, 0, 0)
-arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0)
-arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0)
-arg(config_ARG, '\0', "config", string_VAL, 0, 0)
-arg(configreport_ARG, '\0', "configreport", configreport_VAL, ARG_GROUPABLE, 1)
-arg(configtype_ARG, '\0', "typeconfig", configtype_VAL, 0, 0)
-arg(corelog_ARG, '\0', "corelog", 0, 0, 0)
-arg(dataalignment_ARG, '\0', "dataalignment", sizekb_VAL, 0, 0)
-arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", sizekb_VAL, 0, 0)
-arg(deltag_ARG, '\0', "deltag", tag_VAL, ARG_GROUPABLE, 0)
-arg(detachprofile_ARG, '\0', "detachprofile", 0, 0, 0)
-arg(discards_ARG, '\0', "discards", discards_VAL, 0, 0)
-arg(driverloaded_ARG, '\0', "driverloaded", bool_VAL, 0, 0)
-arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0)
-arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0)
-arg(foreign_ARG, '\0', "foreign", 0, 0, 0)
-arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0)
-arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", 0, 0, 0)
-arg(ignorelocal_ARG, '\0', "ignorelocal", 0, 0, 0)
-arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", 0, 0, 0)
-arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", 0, 0, 0)
-arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", 0, 0, 0)
-arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0)
-arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0)
-arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0)
-arg(lockstart_ARG, '\0', "lockstart", 0, 0, 0)
-arg(lockstop_ARG, '\0', "lockstop", 0, 0, 0)
-arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0)
-arg(logonly_ARG, '\0', "logonly", 0, 0, 0)
-arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0)
-arg(merge_ARG, '\0', "merge", 0, 0, 0)
-arg(mergemirrors_ARG, '\0', "mergemirrors", 0, 0, 0)
-arg(mergesnapshot_ARG, '\0', "mergesnapshot", 0, 0, 0)
-arg(mergethin_ARG, '\0', "mergethin", 0, 0, 0)
-arg(mergedconfig_ARG, '\0', "mergedconfig", 0, 0, 0)
-arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0)
-arg(metadataignore_ARG, '\0', "metadataignore", bool_VAL, 0, 0)
-arg(metadataprofile_ARG, '\0', "metadataprofile", string_VAL, 0, 0)
-arg(metadatasize_ARG, '\0', "metadatasize", sizemb_VAL, 0, 0)
-arg(minor_ARG, '\0', "minor", number_VAL, ARG_GROUPABLE, 0)
-arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", sizekb_VAL, 0, 0)
-arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_VAL, 0, 0)
-arg(mirrorsonly_ARG, '\0', "mirrorsonly", 0, 0, 0)
-arg(mknodes_ARG, '\0', "mknodes", 0, 0, 0)
-arg(monitor_ARG, '\0', "monitor", bool_VAL, 0, 0)
-arg(nameprefixes_ARG, '\0', "nameprefixes", 0, 0, 0)
-arg(noheadings_ARG, '\0', "noheadings", 0, 0, 0)
-arg(nohistory_ARG, '\0', "nohistory", 0, 0, 0)
-arg(nolocking_ARG, '\0', "nolocking", 0, 0, 0)
-arg(norestorefile_ARG, '\0', "norestorefile", 0, 0, 0)
-arg(nosuffix_ARG, '\0', "nosuffix", 0, 0, 0)
-arg(nosync_ARG, '\0', "nosync", 0, 0, 0)
-arg(notifydbus_ARG, '\0', "notifydbus", 0, 0, 0)
-arg(noudevsync_ARG, '\0', "noudevsync", 0, 0, 0)
-arg(originname_ARG, '\0', "originname", lv_VAL, 0, 0)
-arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0)
-arg(poll_ARG, '\0', "poll", bool_VAL, 0, 0)
-arg(polloperation_ARG, '\0', "polloperation", polloperation_VAL, 0, 0)
-arg(pooldatasize_ARG, '\0', "pooldatasize", sizemb_VAL, 0, 0)
-arg(poolmetadata_ARG, '\0', "poolmetadata", lv_VAL, 0, 0)
-arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", sizemb_VAL, 0, 0)
-arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", bool_VAL, 0, 0)
-arg(profile_ARG, '\0', "profile", string_VAL, 0, 0)
-arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", pvmetadatacopies_VAL, 0, 0)
-arg(raidrebuild_ARG, '\0', "raidrebuild", pv_VAL, ARG_GROUPABLE, 0)
-arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", sizekb_VAL, 0, 0)
-arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", sizekb_VAL, 0, 0)
-arg(raidsyncaction_ARG, '\0', "raidsyncaction", syncaction_VAL, 0, 0)
-arg(raidwritebehind_ARG, '\0', "raidwritebehind", number_VAL, 0, 0)
-arg(raidwritemostly_ARG, '\0', "raidwritemostly", writemostly_VAL, ARG_GROUPABLE, 0)
-arg(readonly_ARG, '\0', "readonly", 0, 0, 0)
-arg(refresh_ARG, '\0', "refresh", 0, 0, 0)
-arg(removemissing_ARG, '\0', "removemissing", 0, 0, 0)
-arg(rebuild_ARG, '\0', "rebuild", pv_VAL, ARG_GROUPABLE, 0)
-arg(repair_ARG, '\0', "repair", 0, 0, 0)
-arg(replace_ARG, '\0', "replace", pv_VAL, ARG_GROUPABLE, 0)
-arg(reportformat_ARG, '\0', "reportformat", reportformat_VAL, 0, 0)
-arg(restorefile_ARG, '\0', "restorefile", string_VAL, 0, 0)
-arg(restoremissing_ARG, '\0', "restoremissing", 0, 0, 0)
-arg(resync_ARG, '\0', "resync", 0, 0, 0)
-arg(rows_ARG, '\0', "rows", 0, 0, 0)
-arg(segments_ARG, '\0', "segments", 0, 0, 0)
-arg(separator_ARG, '\0', "separator", string_VAL, 0, 0)
-arg(shared_ARG, '\0', "shared", 0, 0, 0)
-arg(sinceversion_ARG, '\0', "sinceversion", string_VAL, 0, 0)
-arg(split_ARG, '\0', "split", 0, 0, 0)
-arg(splitcache_ARG, '\0', "splitcache", 0, 0, 0)
-arg(splitmirrors_ARG, '\0', "splitmirrors", number_VAL, 0, 0)
-arg(splitsnapshot_ARG, '\0', "splitsnapshot", 0, 0, 0)
-arg(showdeprecated_ARG, '\0', "showdeprecated", 0, 0, 0)
-arg(showunsupported_ARG, '\0', "showunsupported", 0, 0, 0)
-arg(startpoll_ARG, '\0', "startpoll", 0, 0, 0)
-arg(stripes_long_ARG, '\0', "stripes", number_VAL, 0, 0)
-arg(swapmetadata_ARG, '\0', "swapmetadata", 0, 0, 0)
-arg(syncaction_ARG, '\0', "syncaction", syncaction_VAL, 0, 0)
-arg(sysinit_ARG, '\0', "sysinit", 0, 0, 0)
-arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0)
-arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0)
-arg(trackchanges_ARG, '\0', "trackchanges", 0, 0, 0)
-arg(trustcache_ARG, '\0', "trustcache", 0, 0, 0)
-arg(type_ARG, '\0', "type", segtype_VAL, 0, 0)
-arg(unbuffered_ARG, '\0', "unbuffered", 0, 0, 0)
-arg(uncache_ARG, '\0', "uncache", 0, 0, 0)
-arg(cachepolicy_ARG, '\0', "cachepolicy", string_VAL, 0, 0)
-arg(cachesettings_ARG, '\0', "cachesettings", string_VAL, ARG_GROUPABLE, 0)
-arg(unconfigured_ARG, '\0', "unconfigured", 0, 0, 0)
-arg(units_ARG, '\0', "units", units_VAL, 0, 0)
-arg(unquoted_ARG, '\0', "unquoted", 0, 0, 0)
-arg(usepolicies_ARG, '\0', "usepolicies", 0, 0, 0)
-arg(validate_ARG, '\0', "validate", 0, 0, 0)
-arg(version_ARG, '\0', "version", 0, 0, 0)
-arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", vgmetadatacopies_VAL, 0, 0)
-arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", sizemb_VAL, 0, 0)
-arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0)
-arg(withcomments_ARG, '\0', "withcomments", 0, 0, 0)
-arg(withspaces_ARG, '\0', "withspaces", 0, 0, 0)
-arg(withversions_ARG, '\0', "withversions", 0, 0, 0)
-arg(writebehind_ARG, '\0', "writebehind", number_VAL, 0, 0)
-arg(writemostly_ARG, '\0', "writemostly", writemostly_VAL, ARG_GROUPABLE, 0)
+arg(ARG_UNUSED, '-', "", 0, 0, 0, NULL) /* place holder for unused 0 value */
+
+arg(abort_ARG, '\0', "abort", 0, 0, 0,
+ "#pvmove\n"
+ "Abort any pvmove operations in progress. If a pvmove was started\n"
+ "with the --atomic option, then all LVs will remain on the source PV.\n"
+ "Otherwise, segments that have been moved will remain on the\n"
+ "destination PV, while unmoved segments will remain on the source PV.\n"
+ "#lvpoll\n"
+ "Stop processing a poll operation in lvmpolld.\n")
+
+arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0,
+ "Determines if LV activation is allowed when PVs are missing,\n"
+ "e.g. because of a device failure.\n"
+ "\\fBcomplete\\fP only allows LVs with no missing PVs to be activated,\n"
+ "and is the most restrictive mode.\n"
+ "\\fBdegraded\\fP allows RAID LVs with missing PVs to be activated.\n"
+ "(This does not include the \"mirror\" type, see \"raid1\" instead.)\n"
+ "\\fBpartial\\fP allows any LV with missing PVs to be activated, and\n"
+ "should only be used for recovery or repair.\n"
+ "For default, see lvm.conf/activation_mode.\n")
+
+arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0,
+ "Adds a tag to a PV, VG or LV. This option can be repeated to add\n"
+ "multiple tags at once. See lvm(8) for information about tags.\n")
+
+arg(aligned_ARG, '\0', "aligned", 0, 0, 0,
+ "Use with --separator to align the output columns\n")
+
+arg(alloc_ARG, '\0', "alloc", alloc_VAL, 0, 0,
+ "Determines the allocation policy when a command needs to allocate\n"
+ "Physical Extents (PEs) from the VG. Each VG and LV has an allocation policy\n"
+ "which can be changed with vgchange/lvchange, or overriden on the\n"
+ "command line.\n"
+ "\\fBnormal\\fP applies common sense rules such as not placing parallel stripes\n"
+ "on the same PV.\n"
+ "\\fBinherit\\fP applies the VG policy to an LV.\n"
+ "\\fBcontiguous\\fP requires new PEs be placed adjacent to existing PEs.\n"
+ "\\fBcling\\fP places new PEs on the same PV as existing PEs in the same\n"
+ "stripe of the LV.\n"
+ "If there are sufficient PEs for an allocation, but normal does not\n"
+ "use them, \\fBanywhere\\fP will use them even if it reduces performance,\n"
+ "e.g. by placing two stripes on the same PV.\n"
+ "Optional positional PV args on the command line can also be used to limit\n"
+ "which PVs the command will use for allocation.\n"
+ "See lvm(8) for more information about allocation.\n")
+
+arg(atomic_ARG, '\0', "atomic", 0, 0, 0,
+ "Makes a pvmove operation atomic, ensuring that all affected LVs are\n"
+ "moved to the destination PV, or none are if the operation is aborted.\n")
+
+arg(atversion_ARG, '\0', "atversion", string_VAL, 0, 0,
+ "Specify an LVM version in x.y.z format where x is the major version,\n"
+ "the y is the minor version and z is the patchlevel (e.g. 2.2.106).\n"
+ "When configuration is displayed, the configuration settings recognized\n"
+ "at this LVM version will be considered only. This can be used\n"
+ "to display a configuration that a certain LVM version understands and\n"
+ "which does not contain any newer settings for which LVM would\n"
+ "issue a warning message when checking the configuration.\n")
+
+arg(binary_ARG, '\0', "binary", 0, 0, 0,
+ "Use binary values \"0\" or \"1\" instead of descriptive literal values\n"
+ "for columns that have exactly two valid values to report (not counting\n"
+ "the \"unknown\" value which denotes that the value could not be determined).\n")
+
+arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", sizemb_VAL, 0, 0,
+ "Create a separate bootloader area of specified size besides PV's data\n"
+ "area. The bootloader area is an area of reserved space on the PV from\n"
+ "which LVM will not allocate any extents and it's kept untouched. This is\n"
+ "primarily aimed for use with bootloaders to embed their own data or metadata.\n"
+ "The start of the bootloader area is always aligned, see also --dataalignment\n"
+ "and --dataalignmentoffset. The bootloader area size may eventually\n"
+ "end up increased due to the alignment, but it's never less than the\n"
+ "size that is requested. To see the bootloader area start and size of\n"
+ "an existing PV use pvs -o +pv_ba_start,pv_ba_size.\n")
+
+arg(cache_long_ARG, '\0', "cache", 0, 0, 0,
+ "#pvscan\n"
+ "Scan one or more devices and send the metadata to lvmetad.\n"
+ "#vgscan\n"
+ "Scan all devices and send the metadata to lvmetad.\n"
+ "#lvscan\n"
+ "Scan the devices used by an LV and send the metadata to lvmetad.\n")
+
+arg(cachemode_ARG, '\0', "cachemode", cachemode_VAL, 0, 0,
+ "Specifies when writes to a cache LV should be considered complete.\n"
+ "\\fBwriteback\\fP considers a write complete as soon as it is\n"
+ "stored in the cache pool.\n"
+ "\\fBwritethough\\fP considers a write complete only when it has\n"
+ "been stored in both the cache pool and on the origin LV.\n"
+ "While writethrough may be slower for writes, it is more\n"
+ "resilient if something should happen to a device associated with the\n"
+ "cache pool LV. With writethrough, all reads are served\n"
+ "from the origin LV (all reads miss the cache) and all writes are\n"
+ "forwarded to the origin LV; additionally, write hits cause cache\n"
+ "block invalidates. See lvmcache(7) for more information.\n")
+
+arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0,
+ "The name of a cache pool LV.\n")
+
+arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0,
+ "The command profile to use for command configuration.\n"
+ "See lvm.conf(5) for more information about profiles.\n")
+
+arg(config_ARG, '\0', "config", string_VAL, 0, 0,
+ "Config settings for the command. These override lvm.conf settings.\n"
+ "The String arg uses the same format as lvm.conf,\n"
+ "or may use section/field syntax.\n"
+ "See lvm.conf(5) for more information about config.\n")
+
+arg(configreport_ARG, '\0', "configreport", configreport_VAL, ARG_GROUPABLE, 1,
+ "See lvmreport(7).\n")
+
+arg(configtype_ARG, '\0', "typeconfig", configtype_VAL, 0, 0,
+ "See lvmreport(7).\n")
+
+arg(corelog_ARG, '\0', "corelog", 0, 0, 0,
+ "An alias for --mirrorlog core.\n")
+
+arg(dataalignment_ARG, '\0', "dataalignment", sizekb_VAL, 0, 0,
+ "Align the start of the data to a multiple of this number.\n"
+ "Also specify an appropriate Physical Extent size when creating a VG.\n"
+ "To see the location of the first Physical Extent of an existing PV,\n"
+ "use pvs -o +pe_start. In addition, it may be shifted by an alignment offset.\n"
+ "See lvm.conf/data_alignment_offset_detection and --dataalignmentoffset.\n")
+
+arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", sizekb_VAL, 0, 0,
+ "Shift the start of the data area by this additional offset.\n")
+
+arg(deltag_ARG, '\0', "deltag", tag_VAL, ARG_GROUPABLE, 0,
+ "Deletes a tag from a PV, VG or LV. This option can be repeated to delete\n"
+ "multiple tags at once. See lvm(8) for information about tags.\n")
+
+arg(detachprofile_ARG, '\0', "detachprofile", 0, 0, 0,
+ "Detaches a metadata profile from a VG or LV.\n"
+ "See lvm.conf(5) for more information about profiles.\n")
+
+arg(discards_ARG, '\0', "discards", discards_VAL, 0, 0,
+ "Specifies how the device-mapper thin pool layer in the kernel should\n"
+ "handle discards.\n"
+ "\\fBignore\\fP causes the thin pool to ignore discards.\n"
+ "\\fBnopassdown\\fP causes the thin pool to process discards itself to\n"
+ "allow reuse of unneeded extents in the thin pool.\n"
+ "\\fBpassdown\\fP causes the thin pool to process discards itself\n"
+ "(like nopassdown) and pass the discards to the underlying device.\n")
+
+arg(driverloaded_ARG, '\0', "driverloaded", bool_VAL, 0, 0,
+ "If set to no, the command will not attempt to use device-mapper.\n"
+ "For testing and debugging.\n")
+
+arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0,
+ "Specifies thin pool behavior when data space is exhausted.\n"
+ "When yes, device-mapper will immediately return an error\n"
+ "when a thin pool is full and an I/O request requires space.\n"
+ "When no, device-mapper will queue these I/O requests for a\n"
+ "period of time to allow the thin pool to be extended.\n"
+ "Errors are returned if no space is available after the timeout.\n"
+ "(Also see dm-thin-pool kernel module option no_space_timeout.)\n")
+
+arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0,
+ "Force metadata restore even with thin pool LVs.\n"
+ "Use with extreme caution. Most changes to thin metadata\n"
+ "cannot be reverted.\n"
+ "You may lose data if you restore metadata that does not match the\n"
+ "thin pool kernel metadata precisely.\n")
+
+arg(foreign_ARG, '\0', "foreign", 0, 0, 0,
+ "Report/display foreign VGs that would otherwise be skipped.\n"
+ "See lvmsystemid(7) for more information about foreign VGs.\n")
+
+arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0,
+ "Allows a polling operation to continue when PVs are missing,\n"
+ "e.g. for repairs due to faulty devices.\n")
+
+arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", 0, 0, 0,
+ "Exclude advanced configuration settings from the output.\n")
+
+arg(ignorelocal_ARG, '\0', "ignorelocal", 0, 0, 0,
+ "Ignore local section.\n")
+
+arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", 0, 0, 0,
+ "Allows a command to continue with read-only metadata\n"
+ "operations after locking failures.\n")
+
+arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", 0, 0, 0,
+ "Do not interact with dmeventd unless --monitor is specified.\n"
+ "Do not use this if dmeventd is already monitoring a device.\n")
+
+arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", 0, 0, 0,
+ "Use to avoid exiting with an non-zero status code if the command is run\n"
+ "without clustered locking and clustered VGs are skipped.\n")
+
+arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0,
+ "Exclude unsupported configuration settings from the output. These settings are\n"
+ "either used for debugging and development purposes only or their support is not\n"
+ "yet complete and they are not meant to be used in production. The \\fBcurrent\\fP\n"
+ "and \\fBdiff\\fP types include unsupported settings in their output by default,\n"
+ "all the other types ignore unsupported settings.\n")
+
+arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0,
+ "By default the PV is labelled with an LVM2 identifier in its second\n"
+ "sector (sector 1). This lets you use a different sector near the\n"
+ "start of the disk (between 0 and 3 inclusive - see LABEL_SCAN_SECTORS\n"
+ "in the source). Use with care.\n")
+
+arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0,
+ "Used to pass options for special cases to lvmlockd.\n"
+ "See lvmlockd(8) for more information.\n")
+
+arg(lockstart_ARG, '\0', "lockstart", 0, 0, 0,
+ "Start the lockspace of a shared VG in lvmlockd.\n"
+ "lvmlockd locks becomes available for the VG, allowing LVM to use the VG.\n"
+ "See lvmlockd(8) for more information.\n")
+
+arg(lockstop_ARG, '\0', "lockstop", 0, 0, 0,
+ "Stop the lockspace of a shared VG in lvmlockd.\n"
+ "lvmlockd locks become unavailable for the VG, preventing LVM from using the VG.\n"
+ "See lvmlockd(8) for more information.\n")
+
+arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0,
+ "#vgchange\n"
+ "Change the VG lock type to or from a shared lock type used with lvmlockd.\n"
+ "See lvmlockd(8) for more information.\n"
+ "#vgcreate\n"
+ "Specify the VG lock type directly in place of using --shared.\n"
+ "See lvmlockd(8) for more information.\n")
+
+arg(logonly_ARG, '\0', "logonly", 0, 0, 0,
+ "Suppress command report and display only log report.\n")
+
+arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0,
+ "Sets the maximum recovery rate for a RAID LV. The rate value\n"
+ "is an amount of data per second for each device in the array.\n"
+ "Setting the rate to 0 means it will be unbounded.\n")
+
+arg(merge_ARG, '\0', "merge", 0, 0, 0,
+ "An alias for --mergethin, --mergemirrors, or --mergesnapshot,\n"
+ "depending on the type of LV.\n")
+
+arg(mergemirrors_ARG, '\0', "mergemirrors", 0, 0, 0,
+ "Merge LV images that were split from a raid1 LV.\n"
+ "See --splitmirrors with --trackchanges.\n")
+
+arg(mergesnapshot_ARG, '\0', "mergesnapshot", 0, 0, 0,
+ "Merge COW snapshot LV into its origin.\n"
+ "When merging a snapshot, if both the origin and snapshot LVs are not open,\n"
+ "the merge will start immediately. Otherwise, the merge will start the\n"
+ "first time either the origin or snapshot LV are activated and both are\n"
+ "closed. Merging a snapshot into an origin that cannot be closed, for\n"
+ "example a root filesystem, is deferred until the next time the origin\n"
+ "volume is activated. When merging starts, the resulting LV will have the\n"
+ "origin's name, minor number and UUID. While the merge is in progress,\n"
+ "reads or writes to the origin appear as being directed to the snapshot\n"
+ "being merged. When the merge finishes, the merged snapshot is removed.\n"
+ "Multiple snapshots may be specified on the command line or a @tag may be\n"
+ "used to specify multiple snapshots be merged to their respective origin.\n")
+
+arg(mergethin_ARG, '\0', "mergethin", 0, 0, 0,
+ "Merge thin LV into its origin LV.\n"
+ "The origin thin LV takes the content of the thin snapshot,\n"
+ "and the thin snapshot LV is removed.\n")
+
+arg(mergedconfig_ARG, '\0', "mergedconfig", 0, 0, 0,
+ "When the command is run with --config\n"
+ "and/or --commandprofile (or using LVM_COMMAND_PROFILE\n"
+ "environment variable), --profile, or --metadataprofile,\n"
+ "merge all the contents of the \"config cascade\" before displaying it.\n"
+ "Without merging, only the configuration at the front of the\n"
+ "cascade is displayed.\n"
+ "See lvm.conf(5) for more information about config.\n")
+
+arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0,
+ "For commands starting with 'pv', this is an alias for --pvmetadatacopies.\n"
+ "For commands starting with 'vg', this is an alias for --vgmetadatacopies.\n")
+
+arg(metadataignore_ARG, '\0', "metadataignore", bool_VAL, 0, 0,
+ "Specifies the metadataignore property of a PV.\n"
+ "If yes, metadata areas on the PV are ignored, and lvm will\n"
+ "not store metadata in the metadata areas of the PV.\n"
+ "If no, lvm will store metadata on the PV.\n")
+
+arg(metadataprofile_ARG, '\0', "metadataprofile", string_VAL, 0, 0,
+ "The metadata profile to use for command configuration.\n"
+ "See lvm.conf(5) for more information about profiles.\n")
+
+arg(metadatasize_ARG, '\0', "metadatasize", sizemb_VAL, 0, 0,
+ "The approximate amount of space used for each VG metadata area.\n"
+ "The size may be rounded.\n")
+
+arg(minor_ARG, '\0', "minor", number_VAL, ARG_GROUPABLE, 0,
+ "#lvcreate\n"
+ "#lvchange\n"
+ "Sets the minor number of an LV block device.\n"
+ "#pvscan\n"
+ "The minor number of a device.\n")
+
+arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", sizekb_VAL, 0, 0,
+ "Sets the minimum recovery rate for a RAID LV. The rate value\n"
+ "is an amount of data per second for each device in the array.\n"
+ "Setting the rate to 0 means it will be unbounded.\n")
+
+arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_VAL, 0, 0,
+ "Specifies the type of mirror log for LVs with the \"mirror\" type\n"
+ "(does not apply to the \"raid1\" type.)\n"
+ "\\fBdisk\\fP is a persistent log and requires a small amount of\n"
+ "storage space, usually on a separate device from the data being mirrored.\n"
+ "\\fBcore\\fP is not persistent; the log is kept only in memory.\n"
+ "In this case, the mirror must be synchronized (by copying LV data from\n"
+ "the first device to others) each time the LV is activated, e.g. after reboot.\n"
+ "\\fBmirrored\\fP is a persistent log that is itself mirrored.\n")
+
+arg(mirrorsonly_ARG, '\0', "mirrorsonly", 0, 0, 0,
+ "Only remove missing PVs from mirror LVs.\n")
+
+arg(mknodes_ARG, '\0', "mknodes", 0, 0, 0,
+ "Also checks the LVM special files in /dev that are needed for active\n"
+ "LVs and creates any missing ones and removes unused ones.\n")
+
+arg(monitor_ARG, '\0', "monitor", bool_VAL, 0, 0,
+ "Start (yes) or stop (no) monitoring an LV with dmeventd.\n"
+ "dmeventd monitors kernel events for an LV, and performs\n"
+ "automated maintenance for the LV in reponse to specific events.\n"
+ "See dmeventd(8) for more information.\n")
+
+arg(nameprefixes_ARG, '\0', "nameprefixes", 0, 0, 0,
+ "Add an \"LVM2_\" prefix plus the field name to the output. Useful\n"
+ "with --noheadings to produce a list of field=value pairs that can\n"
+ "be used to set environment variables (for example, in udev rules).\n")
+
+arg(noheadings_ARG, '\0', "noheadings", 0, 0, 0,
+ "Suppress the headings line that is normally the first line of output.\n"
+ "Useful if grepping the output.\n")
+
+arg(nohistory_ARG, '\0', "nohistory", 0, 0, 0,
+ "Do not record history of LVs being removed.\n"
+ "This has no effect unless the configuration setting\n"
+ "metadata/record_lvs_history is enabled.\n")
+
+arg(nolocking_ARG, '\0', "nolocking", 0, 0, 0,
+ "Disable locking.\n")
+
+arg(norestorefile_ARG, '\0', "norestorefile", 0, 0, 0,
+ "In conjunction with --uuid, this allows a uuid to be specified\n"
+ "without also requiring that a backup of the metadata be provided.\n")
+
+arg(nosuffix_ARG, '\0', "nosuffix", 0, 0, 0,
+ "Suppress the suffix on output sizes. Use with --units\n"
+ "(except h and H) if processing the output.\n")
+
+arg(nosync_ARG, '\0', "nosync", 0, 0, 0,
+ "Causes the creation of mirror, raid1, raid4, raid5 and raid10 to skip the\n"
+ "initial synchronization. In case of mirror, raid1 and raid10, any data\n"
+ "written afterwards will be mirrored, but the original contents will not be\n"
+ "copied. In case of raid4 and raid5, no parity blocks will be written,\n"
+ "though any data written afterwards will cause parity blocks to be stored.\n"
+ "This is useful for skipping a potentially long and resource intensive initial\n"
+ "sync of an empty mirror/raid1/raid4/raid5 and raid10 LV.\n"
+ "This option is not valid for raid6, because raid6 relies on proper parity\n"
+ "(P and Q Syndromes) being created during initial synchronization in order\n"
+ "to reconstruct proper user date in case of device failures.\n"
+ "raid0 and raid0_meta do not provide any data copies or parity support\n"
+ "and thus do not support initial synchronization.\n")
+
+arg(notifydbus_ARG, '\0', "notifydbus", 0, 0, 0,
+ "Send a notification to D-Bus. The command will exit with an error\n"
+ "if LVM is not built with support for D-Bus notification, or if the\n"
+ "notify_dbus config setting is disabled.\n")
+
+arg(noudevsync_ARG, '\0', "noudevsync", 0, 0, 0,
+ "Disables udev synchronisation. The process will not wait for notification\n"
+ "from udev. It will continue irrespective of any possible udev processing\n"
+ "in the background. Only use this if udev is not running or has rules that\n"
+ "ignore the devices LVM creates.\n")
+
+arg(originname_ARG, '\0', "originname", lv_VAL, 0, 0,
+ "Specifies the name to use for the external origin LV when converting an LV\n"
+ "to a thin LV. The LV being converted becomes a read-only external origin\n"
+ "with this name.\n")
+
+arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0,
+ "Overrides the automatically detected size of the PV.\n"
+ "Use with care, or prior to reducing the physical size of the device.\n")
+
+arg(poll_ARG, '\0', "poll", bool_VAL, 0, 0,
+ "When yes, start the background transformation of an LV.\n"
+ "An incomplete transformation, e.g. pvmove or lvconvert interrupted\n"
+ "by reboot or crash, can be restarted from the last checkpoint with --poll y.\n"
+ "When no, background transformation of an LV will not occur, and the\n"
+ "transformation will not complete. It may not be appropriate to immediately\n"
+ "poll an LV after activation, in which case --poll n can be used to defer\n"
+ "polling until a later --poll y command.\n")
+
+arg(polloperation_ARG, '\0', "polloperation", polloperation_VAL, 0, 0,
+ "The command to perform from lvmpolld.\n")
+
+/* Not used. */
+arg(pooldatasize_ARG, '\0', "pooldatasize", sizemb_VAL, 0, 0, NULL)
+
+arg(poolmetadata_ARG, '\0', "poolmetadata", lv_VAL, 0, 0,
+ "The name of a an LV to use for storing pool metadata.\n")
+
+arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", sizemb_VAL, 0, 0,
+ "The size of the pool metadata LV created by the command.\n")
+
+arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", bool_VAL, 0, 0,
+ "Enable or disable the automatic creation and management of a\n"
+ "spare pool metadata LV in the VG. A spare metadata LV is reserved\n"
+ "space that can be used when repairing a pool.\n")
+
+arg(profile_ARG, '\0', "profile", string_VAL, 0, 0,
+ "An alias for --commandprofile or --metadataprofile, depending\n"
+ "on the command.\n")
+
+arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", pvmetadatacopies_VAL, 0, 0,
+ "The number of metadata areas to set aside on a PV for storing VG metadata.\n"
+ "When 2, one copy of the VG metadata is stored at the front of the PV\n"
+ "and a second copy is stored at the end.\n"
+ "When 1, one copy of the VG metadata is stored at the front of the PV\n"
+ "(starting in the 5th sector).\n"
+ "When 0, no copies of the VG metadata are stored on the given PV.\n"
+ "This may be useful in VGs containing many PVs (this places limitations\n"
+ "on the ability to use vgsplit later.)\n")
+
+arg(raidrebuild_ARG, '\0', "raidrebuild", pv_VAL, ARG_GROUPABLE, 0,
+ "An alias for --rebuild.\n")
+
+arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", sizekb_VAL, 0, 0,
+ "An alias for --maxrecoveryrate.\n")
+
+arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", sizekb_VAL, 0, 0,
+ "An alias for --minrecoveryrate.\n")
+
+arg(raidsyncaction_ARG, '\0', "raidsyncaction", syncaction_VAL, 0, 0,
+ "An alias for --syncaction.\n")
+
+arg(raidwritebehind_ARG, '\0', "raidwritebehind", number_VAL, 0, 0,
+ "An alias for --writebehind.\n")
+
+arg(raidwritemostly_ARG, '\0', "raidwritemostly", writemostly_VAL, ARG_GROUPABLE, 0,
+ "An alias for --writemostly.\n")
+
+arg(readonly_ARG, '\0', "readonly", 0, 0, 0,
+ "Run the command in a special read-only mode which will read on-disk\n"
+ "metadata without needing to take any locks. This can be used to peek\n"
+ "inside metadata used by a virtual machine image while the virtual\n"
+ "machine is running.\n"
+ "It can also be used to peek inside the metadata of clustered VGs\n"
+ "when clustered locking is not configured or running. No attempt\n"
+ "will be made to communicate with the device-mapper kernel driver, so\n"
+ "this option is unable to report whether or not LVs are\n"
+ "actually in use.\n")
+
+arg(refresh_ARG, '\0', "refresh", 0, 0, 0,
+ "If the LV is active, reload its metadata.\n"
+ "This is not necessary in normal operation, but may be useful\n"
+ "if something has gone wrong, or if some form of manual LV\n"
+ "sharing is being used.\n")
+
+arg(removemissing_ARG, '\0', "removemissing", 0, 0, 0,
+ "Removes all missing PVs from the VG, if there are no LVs allocated\n"
+ "on them. This resumes normal operation of the VG (new LVs may again\n"
+ "be created, changed and so on).\n"
+ "If this is not possible because LVs are referencing the missing PVs,\n"
+ "this option can be combined with --force to have the command remove\n"
+ "any partial LVs. In this case, any LVs and dependent snapshots that\n"
+ "were partly on the missing disks are removed completely, including\n"
+ "those parts on disks that are still present.\n"
+ "If LVs spanned several disks, including ones that are lost, salvaging\n"
+ "some data first may be possible by activating LVs in partial mode.\n")
+
+arg(rebuild_ARG, '\0', "rebuild", pv_VAL, ARG_GROUPABLE, 0,
+ "Selects a PV to rebuild in a raid LV. Multiple PVs can be rebuilt by\n"
+ "repeating this option.\n"
+ "Use this option in place of --resync or --syncaction repair when the\n"
+ "PVs with corrupted data are known, and their data should be reconstructed\n"
+ "rather than reconstructing default (rotating) data.\n")
+
+arg(repair_ARG, '\0', "repair", 0, 0, 0,
+ "Replace failed PVs in a raid or mirror LV, or run a repair\n"
+ "utility on a thin pool.\n")
+
+arg(replace_ARG, '\0', "replace", pv_VAL, ARG_GROUPABLE, 0,
+ "Replace a specific PV in a raid LV with another PV.\n"
+ "The new PV to use can be optionally specified after the LV.\n"
+ "Multiple PVs can be replaced by repeating this option.\n")
+
+arg(reportformat_ARG, '\0', "reportformat", reportformat_VAL, 0, 0,
+ "Overrides current output format for reports which is defined globally by\n"
+ "the report/output_format setting in lvm.conf.\n"
+ "\\fBbasic\\fP is the original format with columns and rows.\n"
+ "If there is more than one report per command, each report is prefixed\n"
+ "with the report name for identification. \\fBjson\\fP produces report\n"
+ "output in JSON format.\n")
+
+arg(restorefile_ARG, '\0', "restorefile", string_VAL, 0, 0,
+ "In conjunction with --uuid, this reads the file (produced by\n"
+ "vgcfgbackup), extracts the location and size of the data on the PV,\n"
+ "and ensures that the metadata produced by the program is consistent\n"
+ "with the contents of the file, i.e. the physical extents will be in\n"
+ "the same place and not be overwritten by new metadata. This provides\n"
+ "a mechanism to upgrade the metadata format or to add/remove metadata\n"
+ "areas. Use with care.\n")
+
+arg(restoremissing_ARG, '\0', "restoremissing", 0, 0, 0,
+ "Add a PV back into a VG after the PV was missing and then returned,\n"
+ "e.g. due to a transient failure. The PV is not reinitialized.\n")
+
+arg(resync_ARG, '\0', "resync", 0, 0, 0,
+ "Initiates mirror synchronization. Synchronization generally happens\n"
+ "automatically, but this option forces it to run.\n"
+ "Also see --rebuild to synchronize a specific PV.\n"
+ "During synchronization, data is read from the primary mirror device\n"
+ "and copied to the others. This can take considerable time, during\n"
+ "which the LV is without a complete redundant copy of the data.\n")
+
+arg(rows_ARG, '\0', "rows", 0, 0, 0,
+ "Output columns as rows.\n")
+
+arg(segments_ARG, '\0', "segments", 0, 0, 0,
+ "#pvs\n"
+ "Produces one line of output for each contiguous allocation of space on each\n"
+ "PV, showing the start (pvseg_start) and length (pvseg_size) in units of\n"
+ "physical extents.\n"
+ "#lvs\n"
+ "Use default columns that emphasize segment information.\n")
+
+arg(separator_ARG, '\0', "separator", string_VAL, 0, 0,
+ "String to use to separate each column. Useful if grepping the output.\n")
+
+arg(shared_ARG, '\0', "shared", 0, 0, 0,
+ "#vgcreate\n"
+ "Create a shared VG using lvmlockd if LVM is compiled with lockd support.\n"
+ "lvmlockd will select lock type sanlock or dlm depending on which lock\n"
+ "manager is running. This allows multiple hosts to share a VG on shared\n"
+ "devices. lvmlockd and a lock manager must be configured and running.\n"
+ "(A shared VG using lvmlockd is different from a clustered VG using clvmd.)\n"
+ "See lvmlockd(8) for more information about shared VGs.\n"
+ "#vgs\n"
+ "#lvs\n"
+ "#pvs\n"
+ "#fullreport\n"
+ "#vgdisplay\n"
+ "#lvdisplay\n"
+ "#pvdisplay\n"
+ "Report/display shared VGs that would otherwise be skipped when\n"
+ "lvmlockd is not being used on the host.\n"
+ "See lvmlockd(8) for more information about shared VGs.\n")
+
+arg(sinceversion_ARG, '\0', "sinceversion", string_VAL, 0, 0,
+ "Specify an LVM version in x.y.z format where x is the major version,\n"
+ "the y is the minor version and z is the patchlevel (e.g. 2.2.106).\n"
+ "This option is currently applicable only with --type new\n"
+ "to display all configuration settings introduced since given version.\n")
+
+/* Not used */
+arg(split_ARG, '\0', "split", 0, 0, 0, NULL)
+
+arg(splitcache_ARG, '\0', "splitcache", 0, 0, 0,
+ "Separates a cache pool from a cache LV, and keeps the unused cache pool LV.\n"
+ "Before the separation, the cache is flushed. Also see --uncache.\n")
+
+arg(splitmirrors_ARG, '\0', "splitmirrors", number_VAL, 0, 0,
+ "Splits the specified number of images from a raid1 or mirror LV\n"
+ "and uses them to create a new LV. If --trackchanges is also specified,\n"
+ "changes to the raid1 LV are tracked while the split LV remains detached.\n")
+
+arg(splitsnapshot_ARG, '\0', "splitsnapshot", 0, 0, 0,
+ "Separates a COW snapshot from its origin LV. The LV that is split off\n"
+ "contains the chunks that differ from the origin LV along with metadata\n"
+ "describing them. This LV can be wiped and then destroyed with lvremove.\n")
+
+arg(showdeprecated_ARG, '\0', "showdeprecated", 0, 0, 0,
+ "Include deprecated configuration settings in the output. These settings\n"
+ "are deprecated after a certain version. If a concrete version is specified\n"
+ "with --atversion, deprecated settings are automatically included\n"
+ "if the specified version is lower than the version in which the settings were\n"
+ "deprecated. The current and diff types include deprecated settings\n"
+ "in their output by default, all the other types ignore deprecated settings.\n")
+
+arg(showunsupported_ARG, '\0', "showunsupported", 0, 0, 0,
+ "Include unsupported configuration settings in the output. These settings\n"
+ "are either used for debugging or development purposes only, or their support\n"
+ "is not yet complete and they are not meant to be used in production. The\n"
+ "current and diff types include unsupported settings in their\n"
+ "output by default, all the other types ignore unsupported settings.\n")
+
+arg(startpoll_ARG, '\0', "startpoll", 0, 0, 0,
+ "Start polling an LV to continue processing a conversion.\n")
+
+arg(stripes_long_ARG, '\0', "stripes", number_VAL, 0, 0,
+ "Specifies the number of stripes in a striped LV. This is the number of\n"
+ "PVs (devices) that a striped LV is spread across. Data that\n"
+ "appears sequential in the LV is spread across multiple devices in units of\n"
+ "the stripe size (see --stripesize). This does not apply to\n"
+ "existing allocated space, only newly allocated space can be striped.\n")
+
+arg(swapmetadata_ARG, '\0', "swapmetadata", 0, 0, 0,
+ "Remove the metadata LV in a pool and replace it with another specified LV.\n"
+ "The removed LV is preserved and given the name of the LV that replaced it.\n"
+ "Used for repair only.\n")
+
+arg(syncaction_ARG, '\0', "syncaction", syncaction_VAL, 0, 0,
+ "Initiate different types of RAID synchronization.\n"
+ "This causes the RAID LV to read all data and parity\n"
+ "blocks in the array and check for discrepancies\n"
+ "(mismatches between mirrors or incorrect parity values).\n"
+ "\\fBcheck\\fP will count but not correct discrepancies.\n"
+ "\\fBrepair\\fP will correct discrepancies.\n"
+ "See lvs for reporting discrepancies found or repaired.\n")
+
+arg(sysinit_ARG, '\0', "sysinit", 0, 0, 0,
+ "Indicates that vgchange/lvchange is being invoked from early system initialisation\n"
+ "scripts (e.g. rc.sysinit or an initrd), before writable filesystems are\n"
+ "available. As such, some functionality needs to be disabled and this option\n"
+ "acts as a shortcut which selects an appropriate set of options. Currently,\n"
+ "this is equivalent to using --ignorelockingfailure, --ignoremonitoring,\n"
+ "--poll n, and setting env var LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES.\n"
+ "When used in conjunction with lvmetad enabled and running,\n"
+ "vgchange/lvchange skip autoactivation, and defer to pvscan autoactivation.\n")
+
+arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0,
+ "#vgcreate\n"
+ "Specifies the system ID that will be given to the new VG, overriding the\n"
+ "system ID of the host running the command. A VG is normally created\n"
+ "without this option, in which case the new VG is given the system ID of\n"
+ "the host creating it. Using this option requires caution because the\n"
+ "system ID of the new VG may not match the system ID of the host running\n"
+ "the command, leaving the VG inaccessible to the host.\n"
+ "See lvmsystemid(7) for more information.\n"
+ "#vgchange\n"
+ "Changes the system ID of the VG. Using this option requires caution\n"
+ "because the VG may become foreign to the host running the command,\n"
+ "leaving the host unable to access it.\n"
+ "See lvmsystemid(7) for more information.\n")
+
+arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0,
+ "The name of a thin pool LV.\n")
+
+arg(trackchanges_ARG, '\0', "trackchanges", 0, 0, 0,
+ "Can be used with --splitmirrors on a raid1 LV. This causes\n"
+ "changes to the original raid1 LV to be tracked while the split images\n"
+ "remain detached. This allows the read-only detached image(s) to be\n"
+ "merged efficiently back into the raid1 LV later. Only the regions with\n"
+ "changed data are resynchronized during merge. (This option only applies\n"
+ "when using the raid1 LV type.)\n")
+
+/* TODO: hide this? */
+arg(trustcache_ARG, '\0', "trustcache", 0, 0, 0,
+ "Avoids certain device scanning during command processing. Do not use.\n")
+
+arg(type_ARG, '\0', "type", segtype_VAL, 0, 0,
+ "Specifies an LV type, or \"segment type\".\n")
+
+arg(unbuffered_ARG, '\0', "unbuffered", 0, 0, 0,
+ "Produce output immediately without sorting or aligning the columns properly.\n")
+
+arg(uncache_ARG, '\0', "uncache", 0, 0, 0,
+ "Separates a cache pool from a cache LV, and deletes the unused cache pool LV.\n"
+ "Before the separation, the cache is flushed. Also see --splitcache.\n")
+
+arg(cachepolicy_ARG, '\0', "cachepolicy", string_VAL, 0, 0,
+ "Specifies the cache policy for a cache LV.\n"
+ "See lvmcache(7) for more information.\n")
+
+arg(cachesettings_ARG, '\0', "cachesettings", string_VAL, ARG_GROUPABLE, 0,
+ "Specifies tunable values for a cache LV in \"Key = Value\" form.\n"
+ "Repeat this option to specify multiple values.\n"
+ "(The default values should usually be adequate.)\n"
+ "The special string value \\fBdefault\\fP switches\n"
+ "settings back to their default kernel values and removes\n"
+ "them from the list of settings stored in LVM metadata.\n"
+ "See lvmcache(7) for more information.\n")
+
+arg(unconfigured_ARG, '\0', "unconfigured", 0, 0, 0,
+ "Internal option used for generating config file during build.\n")
+
+arg(units_ARG, '\0', "units", units_VAL, 0, 0,
+ "All sizes are output in these units: (h)uman-readable, (b)ytes, (s)ectors,\n"
+ "(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes.\n"
+ "Capitalise to use multiples of 1000 (S.I.) instead of 1024. Can also specify\n"
+ "custom units e.g. --units 3M.\n")
+
+arg(unquoted_ARG, '\0', "unquoted", 0, 0, 0,
+ "When used with --nameprefixes, output values in the field=value\n"
+ "pairs are not quoted.\n")
+
+arg(usepolicies_ARG, '\0', "usepolicies", 0, 0, 0,
+ "Perform an operation according to the policy configured in lvm.conf.\n"
+ "or a profile.\n")
+
+arg(validate_ARG, '\0', "validate", 0, 0, 0,
+ "Validate current configuration used and exit with appropriate\n"
+ "return code. The validation is done only for the configuration\n"
+ "at the front of the \"config cascade\". To validate the whole\n"
+ "merged configuration tree, also use --mergedconfig.\n"
+ "The validation is done even if lvm.conf config/checks is disabled.\n")
+
+arg(version_ARG, '\0', "version", 0, 0, 0,
+ "Display version information.\n")
+
+arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", vgmetadatacopies_VAL, 0, 0,
+ "Number of copies of the VG metadata that are kept.\n"
+ "VG metadata is kept in VG metadata areas on PVs in the VG,\n"
+ "i.e. reserved space at the start and/or end of the PVs.\n"
+ "Keeping a copy of the VG metadata on every PV can reduce performance\n"
+ "in VGs containing a large number of PVs.\n"
+ "When this number is set to a non-zero value, LVM will automatically\n"
+ "choose PVs on which to store metadata, using the metadataignore flags\n"
+ "on PVs to achieve the specified number.\n"
+ "The number can also be replaced with special string values:\n"
+ "\\fBunmanaged\\fP causes LVM to not automatically manage the PV\n"
+ "metadataignore flags.\n"
+ "\\fBall\\fP causes LVM to first clear the metadataignore flags on\n"
+ "all PVs, and then to become unmanaged.\n")
+
+arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", sizemb_VAL, 0, 0,
+ "An alias for --virtualsize.\n")
+
+arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0,
+ "Display a one line comment for each configuration node.\n")
+
+arg(withcomments_ARG, '\0', "withcomments", 0, 0, 0,
+ "Display a full comment for each configuration node. For deprecated\n"
+ "settings, also display comments about deprecation.\n")
+
+arg(withspaces_ARG, '\0', "withspaces", 0, 0, 0,
+ "Where appropriate, add more spaces in output for better readability.\n")
+
+arg(withversions_ARG, '\0', "withversions", 0, 0, 0,
+ "Also display a comment containing the version of introduction for\n"
+ "each configuration node. If the setting is deprecated, also display\n"
+ "the version since which it is deprecated.\n")
+
+arg(writebehind_ARG, '\0', "writebehind", number_VAL, 0, 0,
+ "The maximum number of outstanding writes that are allowed to\n"
+ "devices in a RAID1 LV that is marked write-mostly.\n"
+ "Once this value is exceeded, writes become synchronous (i.e. all writes\n"
+ "to the constituent devices must complete before the array signals the\n"
+ "write has completed). Setting the value to zero clears the preference\n"
+ "and allows the system to choose the value arbitrarily.\n")
+
+arg(writemostly_ARG, '\0', "writemostly", writemostly_VAL, ARG_GROUPABLE, 0,
+ "Mark a device in a RAID1 LV as write-mostly. All reads\n"
+ "to these drives will be avoided unless absolutely necessary. This keeps\n"
+ "the number of I/Os to the drive to a minimum. The default behavior is to\n"
+ "set the write-mostly attribute for the specified PV.\n"
+ "It is also possible to remove the write-mostly flag by adding the\n"
+ "suffix \\fB:n\\fP at the end of the PV name, or to toggle the value with\n"
+ "the suffix \\fB:t\\fP. Repeat this option to change the attribute on\n"
+ "multiple PVs.\n")
/* Allow some variations */
-arg(allocation_ARG, '\0', "allocation", bool_VAL, 0, 0)
-arg(available_ARG, '\0', "available", activation_VAL, 0, 0)
-arg(resizable_ARG, '\0', "resizable", bool_VAL, 0, 0)
+arg(allocation_ARG, '\0', "allocation", bool_VAL, 0, 0, NULL)
+arg(available_ARG, '\0', "available", activation_VAL, 0, 0, NULL)
+arg(resizable_ARG, '\0', "resizable", bool_VAL, 0, 0, NULL)
/*
* ... and now the short args.
*/
-arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0)
-arg(all_ARG, 'a', "all", 0, 0, 0)
-arg(autobackup_ARG, 'A', "autobackup", bool_VAL, 0, 0)
-arg(activevolumegroups_ARG, 'A', "activevolumegroups", 0, 0, 0)
-arg(background_ARG, 'b', "background", 0, 0, 0)
-arg(backgroundfork_ARG, 'b', "background", 0, 0, 0)
-arg(basevgname_ARG, 'n', "basevgname", string_VAL, 0, 0)
-arg(blockdevice_ARG, 'b', "blockdevice", 0, 0, 0)
-arg(chunksize_ARG, 'c', "chunksize", sizekb_VAL, 0, 0)
-arg(clustered_ARG, 'c', "clustered", bool_VAL, 0, 0)
-arg(colon_ARG, 'c', "colon", 0, 0, 0)
-arg(columns_ARG, 'C', "columns", 0, 0, 0)
-arg(contiguous_ARG, 'C', "contiguous", bool_VAL, 0, 0)
-arg(debug_ARG, 'd', "debug", 0, ARG_COUNTABLE, 0)
-arg(exported_ARG, 'e', "exported", 0, 0, 0)
-arg(physicalextent_ARG, 'E', "physicalextent", 0, 0, 0)
-arg(file_ARG, 'f', "file", string_VAL, 0, 0)
-arg(force_ARG, 'f', "force", 0, ARG_COUNTABLE, 0)
-arg(full_ARG, 'f', "full", 0, 0, 0)
-arg(help_ARG, 'h', "help", 0, ARG_COUNTABLE, 0)
-arg(cache_ARG, 'H', "cache", 0, 0, 0)
-arg(history_ARG, 'H', "history", 0, 0, 0)
-arg(help2_ARG, '?', "", 0, 0, 0)
-arg(import_ARG, 'i', "import", 0, 0, 0)
-arg(interval_ARG, 'i', "interval", number_VAL, 0, 0)
-arg(iop_version_ARG, 'i', "iop_version", 0, 0, 0)
-arg(stripes_ARG, 'i', "stripes", number_VAL, 0, 0)
-arg(stripesize_ARG, 'I', "stripesize", sizekb_VAL, 0, 0)
-arg(logicalvolume_ARG, 'l', "logicalvolume", number_VAL, 0, 0)
-arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", number_VAL, 0, 0)
-arg(extents_ARG, 'l', "extents", numsignedper_VAL, 0, 0)
-arg(list_ARG, 'l', "list", 0, 0, 0)
-arg(lvmpartition_ARG, 'l', "lvmpartition", 0, 0, 0)
-arg(size_ARG, 'L', "size", sizemb_VAL, 0, 0)
-arg(persistent_ARG, 'M', "persistent", bool_VAL, 0, 0)
-arg(major_ARG, 'j', "major", number_VAL, ARG_GROUPABLE, 0)
-arg(setactivationskip_ARG, 'k', "setactivationskip", bool_VAL, 0, 0)
-arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", 0, 0, 0)
-arg(maps_ARG, 'm', "maps", 0, 0, 0)
-arg(mirrors_ARG, 'm', "mirrors", numsigned_VAL, 0, 0)
-arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_VAL, 0, 0)
-arg(name_ARG, 'n', "name", string_VAL, 0, 0)
-arg(nofsck_ARG, 'n', "nofsck", 0, 0, 0)
-arg(novolumegroup_ARG, 'n', "novolumegroup", 0, 0, 0)
-arg(oldpath_ARG, 'n', "oldpath", 0, 0, 0)
-arg(options_ARG, 'o', "options", string_VAL, ARG_GROUPABLE, 0)
-arg(sort_ARG, 'O', "sort", string_VAL, ARG_GROUPABLE, 0)
-arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", uint32_VAL, 0, 0)
-arg(permission_ARG, 'p', "permission", permission_VAL, 0, 0)
-arg(partial_ARG, 'P', "partial", 0, 0, 0)
-arg(physicalvolume_ARG, 'P', "physicalvolume", 0, 0, 0)
-arg(quiet_ARG, 'q', "quiet", 0, ARG_COUNTABLE, 0)
-arg(readahead_ARG, 'r', "readahead", readahead_VAL, 0, 0)
-arg(resizefs_ARG, 'r', "resizefs", 0, 0, 0)
-arg(reset_ARG, 'R', "reset", 0, 0, 0)
-arg(regionsize_ARG, 'R', "regionsize", sizemb_VAL, 0, 0)
-arg(physicalextentsize_ARG, 's', "physicalextentsize", sizemb_VAL, 0, 0)
-arg(snapshot_ARG, 's', "snapshot", 0, 0, 0)
-arg(short_ARG, 's', "short", 0, 0, 0)
-arg(stdin_ARG, 's', "stdin", 0, 0, 0)
-arg(select_ARG, 'S', "select", string_VAL, ARG_GROUPABLE, 0)
-arg(test_ARG, 't', "test", 0, 0, 0)
-arg(thin_ARG, 'T', "thin", 0, 0, 0)
-arg(uuid_ARG, 'u', "uuid", 0, 0, 0)
-arg(uuidstr_ARG, 'u', "uuid", string_VAL, 0, 0)
-arg(uuidlist_ARG, 'U', "uuidlist", 0, 0, 0)
-arg(verbose_ARG, 'v', "verbose", 0, ARG_COUNTABLE, 0)
-arg(volumegroup_ARG, 'V', "volumegroup", 0, 0, 0)
-arg(virtualsize_ARG, 'V', "virtualsize", sizemb_VAL, 0, 0)
-arg(wipesignatures_ARG, 'W', "wipesignatures", bool_VAL, 0, 0)
-arg(allocatable_ARG, 'x', "allocatable", bool_VAL, 0, 0)
-arg(resizeable_ARG, 'x', "resizeable", bool_VAL, 0, 0)
-arg(yes_ARG, 'y', "yes", 0, 0, 0)
-arg(zero_ARG, 'Z', "zero", bool_VAL, 0, 0)
+arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0,
+ "#lvchange\n"
+ "#vgchange\n"
+ "Change the active state of LVs.\n"
+ "An active LV can be used through a block device,\n"
+ "allowing data on the LV to be accessed.\n"
+ "\\fBy\\fP makes LVs active, or available.\n"
+ "\\fBn\\fP makes LVs inactive, or unavailable.\n"
+ "The block device for the LV is added or removed from the system\n"
+ "using device-mapper in the kernel.\n"
+ "A symbolic link /dev/VGName/LVName pointing to the device node is also added/removed.\n"
+ "All software and scripts should access the device through the symbolic\n"
+ "link and present this as the name of the device.\n"
+ "The location and name of the underlying device node may depend on\n"
+ "the distribution, configuration (e.g. udev), or release version.\n"
+ "\\fBay\\fP specifies autoactivation, in which case an LV is activated\n"
+ "only if it matches an item in lvm.conf activation/auto_activation_volume_list.\n"
+ "If the list is not set, all LVs are considered to match, and if\n"
+ "if the list is set but empty, no LVs match.\n"
+ "Autoactivation should be used during system boot to make it possible\n"
+ "to select which LVs should be automatically activated by the system.\n"
+ "See lvmlockd(8) for more information about activation options for shared VGs.\n"
+ "See clvmd(8) for more information about activation options for clustered VGs.\n"
+ "#lvcreate\n"
+ "Controls the active state of the new LV.\n"
+ "\\fBy\\fP makes the LV active, or available.\n"
+ "New LVs are made active by default.\n"
+ "\\fBn\\fP makes the LV inactive, or unavailable, only when possible.\n"
+ "In some cases, creating an LV requires it to be active.\n"
+ "For example, COW snapshots of an active origin LV can only\n"
+ "be created in the active state (this does not apply to thin snapshots.)\n"
+ "The --zero option normally requires the LV to be active.\n"
+ "If autoactivation \\fBay\\fP is used, the LV is only activated\n"
+ "if it matches an item in lvm.conf activation/auto_activation_volume_list.\n"
+ "\\fBay\\fP implies --zero n and --wipesignatures n.\n"
+ "See lvmlockd(8) for more information about activation options for shared VGs.\n"
+ "See clvmd(8) for more information about activation options for clustered VGs.\n")
+
+arg(all_ARG, 'a', "all", 0, 0, 0,
+ "#vgreduce\n"
+ "Removes all empty PVs if none are named on the command line.\n"
+ "#lvscan\n"
+ "#lvdisplay\n"
+ "#lvs\n"
+ "Show information about internal LVs.\n"
+ "These are components of normal LVs, such as mirrors,\n"
+ "which are not independently accessible, e.g. not mountable.\n"
+ "#vgs\n"
+ "List all VGs. Equivalent to not specifying any VGs.\n"
+ "#pvs\n"
+ "#pvdisplay\n"
+ "Show information about devices that have not been initialized\n"
+ "by LVM, i.e. they are not PVs.\n")
+
+arg(autobackup_ARG, 'A', "autobackup", bool_VAL, 0, 0,
+ "Specifies if metadata should be backed up automatically after a change.\n"
+ "Enabling this is strongly advised! See vgcfgbackup(8) for more information.\n")
+
+arg(activevolumegroups_ARG, 'A', "activevolumegroups", 0, 0, 0,
+ "Only select active VGs. The VG is considered active\n"
+ "if at least one of its LVs is active.\n")
+
+/* FIXME: remove background option from pvscan, it's not used */
+
+arg(background_ARG, 'b', "background", 0, 0, 0,
+ "If the operation requires polling, this option causes the command to\n"
+ "return before the operation is complete, and polling is done in the\n"
+ "background.\n")
+
+/* Not used */
+arg(backgroundfork_ARG, 'b', "background", 0, 0, 0, NULL)
+
+arg(basevgname_ARG, 'n', "basevgname", string_VAL, 0, 0,
+ "By default the snapshot VG will be renamed to the original name plus a\n"
+ "numeric suffix to avoid duplicate naming (e.g. 'test_vg' would be renamed\n"
+ "to 'test_vg1'). This option will override the base VG name that is\n"
+ "used for all VG renames. If a VG already exists with the specified name\n"
+ "a numeric suffix will be added (like the previous example) to make it unique.\n")
+
+arg(blockdevice_ARG, 'b', "blockdevice", 0, 0, 0,
+ "No longer used.\n")
+
+arg(chunksize_ARG, 'c', "chunksize", sizekb_VAL, 0, 0,
+ "The size of chunks in a snapshot, cache pool or thin pool.\n"
+ "For snapshots, the value must be a power of 2 between 4KiB and 512KiB\n"
+ "and the default value is 4.\n"
+ "For a cache pool the value must be between 32KiB and 1GiB\n"
+ "and the default value is 64.\n"
+ "For a thin pool the value must be between 64KiB and 1GiB\n"
+ "and the default value starts with 64 and scales up to fit the\n"
+ "pool metadata size within 128MiB, if the pool metadata size is not specified.\n"
+ "The value must be a multiple of 64KiB.\n")
+
+arg(clustered_ARG, 'c', "clustered", bool_VAL, 0, 0,
+ "#vgcreate\n"
+ "Create a clustered VG using clvmd if LVM is compiled with cluster support.\n"
+ "This allows multiple hosts to share a VG on shared devices.\n"
+ "clvmd and a lock manager must be configured and running.\n"
+ "(A clustered VG using clvmd is different from a shared VG using lvmlockd.)\n"
+ "See clvmd(8) for more information about clustered VGs.\n"
+ "#vgchange\n"
+ "Change the clustered property of a VG using clvmd.\n"
+ "See clvmd(8) for more information about clustered VGs.\n"
+ "#vgsplit\n"
+ "Specifies the clustered property of the new VG.\n")
+
+arg(colon_ARG, 'c', "colon", 0, 0, 0,
+ "Generate colon separated output for easier parsing in scripts or programs.\n"
+ "Also see vgs(8) which provides considerably more control over the output.\n")
+
+arg(columns_ARG, 'C', "columns", 0, 0, 0,
+ "Display output in columns, the equivalent of vgs(8).\n"
+ "Options listed are the same as options given in vgs(8).\n")
+
+arg(contiguous_ARG, 'C', "contiguous", bool_VAL, 0, 0,
+ "Sets or resets the contiguous allocation policy for LVs.\n"
+ "Default is no contiguous allocation based on a next free principle.\n"
+ "It is only possible to change a non-contiguous allocation policy\n"
+ "to contiguous if all of the allocated physical extents in the LV\n"
+ "are already contiguous.\n")
+
+arg(debug_ARG, 'd', "debug", 0, ARG_COUNTABLE, 0,
+ "Set debug level. Repeat from 1 to 6 times to increase the detail of\n"
+ "messages sent to the log file and/or syslog (if configured).\n")
+
+arg(exported_ARG, 'e', "exported", 0, 0, 0,
+ "Only show PVs belonging to exported VGs.\n")
+
+/* Not used. */
+arg(physicalextent_ARG, 'E', "physicalextent", 0, 0, 0, NULL)
+
+arg(file_ARG, 'f', "file", string_VAL, 0, 0,
+ "#lvmconfig\n"
+ "#dumpconfig\n"
+ "#config\n"
+ "Write output to the named file.\n"
+ "#vgcfgbackup\n"
+ "Write the backup to the named file.\n"
+ "When backing up more than one VG, the file name is\n"
+ "treated as a template, and %s is replaced by the VG name.\n"
+ "#vgcfgrestore\n"
+ "Read metadata backup from the named file.\n"
+ "Usually this file was created by vgcfgbackup.\n")
+
+arg(force_ARG, 'f', "force", 0, ARG_COUNTABLE, 0,
+ "Override various checks, confirmations and protections.\n"
+ "Use with extreme caution.\n")
+
+/* Not used. */
+arg(full_ARG, 'f', "full", 0, 0, 0, NULL)
+
+arg(help_ARG, 'h', "help", 0, ARG_COUNTABLE, 0,
+ "Display help text. Repeat this option for more information.\n")
+
+arg(cache_ARG, 'H', "cache", 0, 0, 0,
+ "Specifies the command is handling a cache LV or cache pool.\n"
+ "See --type cache and --type cache-pool.\n"
+ "See lvmcache(7) for more information about LVM caching.\n")
+
+arg(history_ARG, 'H', "history", 0, 0, 0,
+ "Include historical LVs in the output.\n"
+ "(This has no effect unless LVs were removed while\n"
+ "lvm.conf metadata/record_lvs_history was enabled.\n")
+
+/* Not used */
+arg(help2_ARG, '?', "", 0, 0, 0, NULL)
+
+arg(import_ARG, 'i', "import", 0, 0, 0,
+ "Import exported VGs. Otherwise VGs that have been exported\n"
+ "will not be changed (nor will their associated PVs).\n")
+
+arg(interval_ARG, 'i', "interval", number_VAL, 0, 0,
+ "Report progress at regular intervals.\n")
+
+/* Not used */
+arg(iop_version_ARG, 'i', "iop_version", 0, 0, 0, NULL)
+
+arg(stripes_ARG, 'i', "stripes", number_VAL, 0, 0,
+ "Specifies the number of stripes in a striped LV. This is the number of\n"
+ "PVs (devices) that a striped LV is spread across. Data that\n"
+ "appears sequential in the LV is spread across multiple devices in units of\n"
+ "the stripe size (see --stripesize). This does not apply to\n"
+ "existing allocated space, only newly allocated space can be striped.\n"
+ "When creating a RAID 4/5/6 LV, this number does not include the extra\n"
+ "devices that are required for parity. The largest number depends on\n"
+ "the RAID type (raid0: 64, raid10: 32, raid4/5: 63, raid6: 62.)\n"
+ "When unspecified, the default depends on the RAID type\n"
+ "(raid0: 2, raid10: 4, raid4/5: 3, raid6: 5.)\n"
+ "When unspecified, to stripe across all PVs of the VG,\n"
+ "set lvm.conf allocation/raid_stripe_all_devices=1.\n")
+
+arg(stripesize_ARG, 'I', "stripesize", sizekb_VAL, 0, 0,
+ "The amount of data that is written to one device before\n"
+ "moving to the next in a striped LV.\n")
+
+arg(logicalvolume_ARG, 'l', "logicalvolume", number_VAL, 0, 0,
+ "Sets the maximum number of LVs allowed in a VG.\n")
+
+arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", number_VAL, 0, 0,
+ "Sets the maximum number of LVs allowed in a VG.\n")
+
+arg(extents_ARG, 'l', "extents", numsignedper_VAL, 0, 0,
+ "#lvcreate\n"
+ "Specifies the size of the new LV in logical extents.\n"
+ "The --size and --extents options are alternate methods of specifying size.\n"
+ "The total number of physical extents used will be\n"
+ "greater when redundant data is needed for RAID levels.\n"
+ "An alternate syntax allows the size to be determined indirectly\n"
+ "as a percentage of the size of a related VG, LV, or set of PVs. The\n"
+ "suffix \\fB%VG\\fP denotes the total size of the VG, the suffix \\fB%FREE\\fP\n"
+ "the remaining free space in the VG, and the suffix \\fB%PVS\\fP the free\n"
+ "space in the specified PVs. For a snapshot, the size\n"
+ "can be expressed as a percentage of the total size of the origin LV\n"
+ "with the suffix \\fB%ORIGIN\\fP (\\fB100%ORIGIN\\fP provides space for\n"
+ "the whole origin).\n"
+ "When expressed as a percentage, the size defines an upper limit for the\n"
+ "number of logical extents in the new LV. The precise number of logical\n"
+ "extents in the new LV is not determined until the command has completed.\n"
+ "#lvreduce\n"
+ "#lvextend\n"
+ "#lvresize\n"
+ "Specifies the new size of the LV in logical extents.\n"
+ "The --size and --extents options are alternate methods of specifying size.\n"
+ "The total number of physical extents used will be\n"
+ "greater when redundant data is needed for RAID levels.\n"
+ "An alternate syntax allows the size to be determined indirectly\n"
+ "as a percentage of the size of a related VG, LV, or set of PVs. The\n"
+ "suffix \\fB%VG\\fP denotes the total size of the VG, the suffix \\fB%FREE\\fP\n"
+ "the remaining free space in the VG, and the suffix \\fB%PVS\\fP the free\n"
+ "space in the specified PVs. For a snapshot, the size\n"
+ "can be expressed as a percentage of the total size of the origin LV\n"
+ "with the suffix \\fB%ORIGIN\\fP (\\fB100%ORIGIN\\fP provides space for\n"
+ "the whole origin).\n"
+ "When expressed as a percentage, the size defines an upper limit for the\n"
+ "number of logical extents in the new LV. The precise number of logical\n"
+ "extents in the new LV is not determined until the command has completed.\n"
+ "The plus prefix \\fB+\\fP can be used, in which case\n"
+ "the value is added to the current size,\n"
+ "or the minus prefix \\fB-\\fP can be used, in which case\n"
+ "the value is subtracted from the current size.\n")
+
+arg(list_ARG, 'l', "list", 0, 0, 0,
+ "#lvmconfig\n"
+ "#dumpconfig\n"
+ "#config\n"
+ "List config settings with summarizing comment. This is the same as using\n"
+ "options --type list --withsummary.\n"
+ "#vgcfgrestore\n"
+ "List metadata backup and archive files pertaining to the VG.\n"
+ "May be used with --file. Does not restore the VG.\n"
+ "#vgmerge\n"
+ "Display merged destination VG like vgdisplay -v.\n")
+
+arg(lvmpartition_ARG, 'l', "lvmpartition", 0, 0, 0,
+ "Only report PVs.\n")
+
+arg(size_ARG, 'L', "size", sizemb_VAL, 0, 0,
+ "#lvcreate\n"
+ "Specifies the size of the new LV.\n"
+ "The --size and --extents options are alternate methods of specifying size.\n"
+ "The total number of physical extents used will be\n"
+ "greater when redundant data is needed for RAID levels.\n"
+ "A suffix can be chosen from: \\fBbBsSkKmMgGtTpPeE\\fP.\n"
+ "All units are base two values, regardless of letter capitalization:\n"
+ "b|B is bytes, s|S is sectors of 512 bytes,\n"
+ "k|K is kilobytes, m|M is megabytes,\n"
+ "g|G is gigabytes, t|T is terabytes,\n"
+ "p|P is petabytes, e|E is exabytes.\n"
+ "#lvreduce\n"
+ "#lvextend\n"
+ "#lvresize\n"
+ "Specifies the new size of the LV.\n"
+ "The --size and --extents options are alternate methods of specifying size.\n"
+ "The total number of physical extents used will be\n"
+ "greater when redundant data is needed for RAID levels.\n"
+ "A suffix can be chosen from: \\fBbBsSkKmMgGtTpPeE\\fP.\n"
+ "All units are base two values, regardless of letter capitalization:\n"
+ "b|B is bytes, s|S is sectors of 512 bytes,\n"
+ "k|K is kilobytes, m|M is megabytes,\n"
+ "g|G is gigabytes, t|T is terabytes,\n"
+ "p|P is petabytes, e|E is exabytes.\n"
+ "The plus prefix \\fB+\\fP can be used, in which case\n"
+ "the value is added to the current size,\n"
+ "or the minus prefix \\fB-\\fP can be used, in which case\n"
+ "the value is subtracted from the current size.\n")
+
+arg(persistent_ARG, 'M', "persistent", bool_VAL, 0, 0,
+ "When yes, makes the specified minor number persistent.\n")
+
+arg(major_ARG, 'j', "major", number_VAL, ARG_GROUPABLE, 0,
+ "#lvcreate\n"
+ "#lvchange\n"
+ "Sets the major number of an LV block device.\n"
+ "#pvscan\n"
+ "The major number of a device.\n")
+
+arg(setactivationskip_ARG, 'k', "setactivationskip", bool_VAL, 0, 0,
+ "Persistently sets (yes) or clears (no) the \"activation skip\" flag on an LV.\n"
+ "An LV with this flag set is not activated unless the\n"
+ "--ignoreactivationskip option is used by the activation command.\n"
+ "This flag is set by default on new thin snapshot LVs.\n"
+ "The flag is not applied to deactivation.\n"
+ "The current value of the flag is indicated in the lvs lv_attr bits.\n")
+
+arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", 0, 0, 0,
+ "Ignore the \"activation skip\" LV flag during activation\n"
+ "to allow LVs with the flag set to be activated.\n")
+
+arg(maps_ARG, 'm', "maps", 0, 0, 0,
+ "#lvdisplay\n"
+ "Display the mapping of logical extents to PVs and physical extents.\n"
+ "To map physical extents to logical extents use:\n"
+ "pvs --segments -o+lv_name,seg_start_pe,segtype\n"
+ "#pvdisplay\n"
+ "Display the mapping of physical extents to LVs and logical extents.\n")
+
+/* FIXME: should the unused mirrors option be removed from lvextend? */
+
+arg(mirrors_ARG, 'm', "mirrors", numsigned_VAL, 0, 0,
+ "#lvcreate\n"
+ "Specifies the number of mirror images in addition to the original LV\n"
+ "image, e.g. --mirrors 1 means there are two images of the data, the\n"
+ "original and one mirror image.\n"
+ "Optional positional PV args on the command line can specify the devices\n"
+ "the images should be placed on.\n"
+ "There are two mirroring implementations: \"raid1\" and \"mirror\".\n"
+ "These are the names of the corresponding LV types, or \"segment types\".\n"
+ "Use the --type option to specify which to use (raid1 is default,\n"
+ "and mirror is legacy)\n"
+ "Use lvm.conf global/mirror_segtype_default and\n"
+ "global/raid10_segtype_default to configure the default types.\n"
+ "See the --nosync option for avoiding initial image synchronization.\n"
+ "#lvconvert\n"
+ "Specifies the number of mirror images in addition to the original LV\n"
+ "image, e.g. --mirrors 1 means there are two images of the data, the\n"
+ "original and one mirror image.\n"
+ "Optional positional PV args on the command line can specify the devices\n"
+ "the images should be placed on.\n"
+ "There are two mirroring implementations: \"raid1\" and \"mirror\".\n"
+ "These are the names of the corresponding LV types, or \"segment types\".\n"
+ "Use the --type option to specify which to use (raid1 is default,\n"
+ "and mirror is legacy)\n"
+ "Use lvm.conf global/mirror_segtype_default and\n"
+ "global/raid10_segtype_default to configure the default types.\n"
+ "The plus prefix \\fB+\\fP can be used, in which case\n"
+ "the number is added to the current number of images,\n"
+ "or the minus prefix \\fB-\\fP can be used, in which case\n"
+ "the number is subtracted from the current number of images.\n"
+ "#lvextend\n"
+ "Not used.\n")
+
+arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_VAL, 0, 0,
+ "Specifies the type of on-disk metadata to use.\n"
+ "\\fBlvm2\\fP (or just \\fB2\\fP) is the current, standard format.\n"
+ "\\fBlvm1\\fP (or just \\fB1\\fP) is a historical format that\n"
+ "can be used for accessing old data.\n")
+
+arg(name_ARG, 'n', "name", string_VAL, 0, 0,
+ "#lvcreate\n"
+ "#lvconvert\n"
+ "Specifies the name of a new LV.\n"
+ "When unspecified, a default name of \"lvol#\" is\n"
+ "generated, where # is a number generated by LVM.\n"
+ "#pvmove\n"
+ "Move only the extents belonging to the named LV.\n"
+ "#vgsplit\n"
+ "Move only PVs used by the named LV.\n")
+
+arg(nofsck_ARG, 'n', "nofsck", 0, 0, 0,
+ "Do not perform fsck before resizing filesystem when filesystem\n"
+ "requires it. You may need to use --force to proceed with\n"
+ "this option.\n")
+
+arg(novolumegroup_ARG, 'n', "novolumegroup", 0, 0, 0,
+ "Only show PVs not belonging to any VG.\n")
+
+/* Not used */
+arg(oldpath_ARG, 'n', "oldpath", 0, 0, 0, NULL)
+
+/*
+ * FIXME: a free-form discussion section and document the
+ * VG/LV/PV attr bits which were previously listed
+ * in the description for -o.
+ */
+
+arg(options_ARG, 'o', "options", string_VAL, ARG_GROUPABLE, 0,
+ "Comma-separated, ordered list of fields to display in columns.\n"
+ "String arg syntax is: [+|-|#]Field1[,Field2 ...]\n"
+ "The prefix \\fB+\\fP will append the specified fields to the default fields,\n"
+ "\\fB-\\fP will remove the specified fields from the default fields, and\n"
+ "\\fB#\\fP will compact specified fields (removing them when empty for all rows.)\n"
+ "Use \\fB-o help\\fP to view the list of all available fields.\n"
+ "The -o option can be repeated, providing several lists.\n"
+ "These lists are evaluated from left to right.\n"
+ "Use field name \\fBlv_all\\fP to view all LV fields,\n"
+ "\\fBvg_all\\fP all VG fields,\n"
+ "\\fBpv_all\\fP all PV fields,\n"
+ "\\fBpvseg_all\\fP all PV segment fields,\n"
+ "\\fBseg_all\\fP all LV segment fields, and\n"
+ "\\fBpvseg_all\\fP all PV segment columns.\n"
+ "See the lvm.conf report section for more config options.\n"
+ "See lvmreport(7) for more information about reporting.\n")
+
+arg(sort_ARG, 'O', "sort", string_VAL, ARG_GROUPABLE, 0,
+ "Comma-separated ordered list of columns to sort by. Replaces the default\n"
+ "selection. Precede any column with \\fB-\\fP for a reverse sort on that column.\n")
+
+arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", uint32_VAL, 0, 0,
+ "Sets the maximum number of PVs that can belong to the VG.\n"
+ "The value 0 removes any limitation.\n"
+ "For large numbers of PVs, also see options --pvmetadatacopies,\n"
+ "and --vgmetadatacopies for improving performance.\n")
+
+arg(permission_ARG, 'p', "permission", permission_VAL, 0, 0,
+ "Set access permission to read only \\fBr\\fP or read and write \\fBrw\\fP.\n")
+
+/* FIXME: I left out some of the previous description that didn't sound correct. */
+
+arg(partial_ARG, 'P', "partial", 0, 0, 0,
+ "When set, the tools will do their best to provide access to VGs\n"
+ "that are only partially available (one or more PVs belonging\n"
+ "to the VG are missing from the system). Metadata may not be\n"
+ "changed with this option.\n")
+
+/* Not used */
+arg(physicalvolume_ARG, 'P', "physicalvolume", 0, 0, 0, NULL)
+
+arg(quiet_ARG, 'q', "quiet", 0, ARG_COUNTABLE, 0,
+ "Suppress output and log messages. Overrides --debug and --verbose.\n"
+ "Repeat once to also suppress any prompts with answer no.\n")
+
+arg(readahead_ARG, 'r', "readahead", readahead_VAL, 0, 0,
+ "Sets read ahead sector count of an LV.\n"
+ "\\fBauto\\fP is the default which allows the kernel to choose\n"
+ "a suitable value automatically.\n"
+ "\\fBnone\\fP is equivalent to zero.\n")
+
+arg(resizefs_ARG, 'r', "resizefs", 0, 0, 0,
+ "Resize underlying filesystem together with the LV using fsadm(8).\n")
+
+/* Not used */
+arg(reset_ARG, 'R', "reset", 0, 0, 0, NULL)
+
+arg(regionsize_ARG, 'R', "regionsize", sizemb_VAL, 0, 0,
+ "A mirror is divided into regions of this size, and the mirror log\n"
+ "uses this granularity to track which regions are in sync.\n"
+ "(This can be used with the \"mirror\" type, not the \"raid1\" type.)\n")
+
+arg(physicalextentsize_ARG, 's', "physicalextentsize", sizemb_VAL, 0, 0,
+ "#vgcreate\n"
+ "Sets the physical extent size of PVs in the VG.\n"
+ "The value must be either a power of 2 of at least 1 sector\n"
+ "(where the sector size is the largest sector size of the PVs\n"
+ "currently used in the VG), or at least 128KiB.\n"
+ "Once this value has been set, it is difficult to change\n"
+ "without recreating the VG, unless no extents need moving.\n"
+ "#vgchange\n"
+ "Sets the physical extent size of PVs in the VG.\n"
+ "The value must be either a power of 2 of at least 1 sector\n"
+ "(where the sector size is the largest sector size of the PVs\n"
+ "currently used in the VG), or at least 128KiB.\n"
+ "Once this value has been set, it is difficult to change\n"
+ "without recreating the VG, unless no extents need moving.\n"
+ "Before increasing the physical extent size, you might need to use lvresize,\n"
+ "pvresize and/or pvmove so that everything fits. For example, every\n"
+ "contiguous range of extents used in a LV must start and end on an extent boundary.\n")
+
+arg(snapshot_ARG, 's', "snapshot", 0, 0, 0,
+ "#lvcreate\n"
+ "Create a snapshot. Snapshots provide a \"frozen image\" of an origin LV.\n"
+ "The snapshot LV can be used, e.g. for backups, while the origin LV\n"
+ "continues to be used.\n"
+ "This option can create a COW (copy on write) snapshot,\n"
+ "or a thin snapshot (in a thin pool.)\n"
+ "Thin snapshots are created when the origin is a thin LV and\n"
+ "the size option is NOT specified. Thin snapshots share the same blocks\n"
+ "in the thin pool, and do not allocate new space from the VG.\n"
+ "Thin snapshots are created with the \"activation skip\" flag,\n"
+ "see --setactivationskip.\n"
+ "A thin snapshot of a non-thin \"external origin\" LV is created\n"
+ "when a thin pool is specified. Unprovisioned blocks in the thin snapshot\n"
+ "LV are read from the external origin LV. The external origin LV must\n"
+ "be read-only.\n"
+ "See lvmthin(7) for more information about LVM thin provisioning.\n"
+ "COW snapshots are created when a size is specified. The size is allocated\n"
+ "from space in the VG, and is the amount of space that can be used\n"
+ "for saving COW blocks as writes occur to the origin or snapshot.\n"
+ "The size chosen should depend upon the amount of writes that are expected;\n"
+ "often 20% of the origin LV is enough. If COW space runs low, it can\n"
+ "be extended with lvextend (shrinking is also allowed with lvreduce.)\n"
+ "A small amount of the COW snapshot LV size is used to track COW block\n"
+ "locations, so the full size is not available for COW data blocks.\n"
+ "Use lvs to check how much space is used, and see --monitor to\n"
+ "to automatically extend the size to avoid running out of space.\n"
+ "#lvconvert\n"
+ "Combine a former COW snapshot LV with a former origin LV to reverse\n"
+ "a previous --splitsnapshot command.\n")
+
+arg(short_ARG, 's', "short", 0, 0, 0,
+ "#pvdisplay\n"
+ "Only display the size of the given PVs.\n"
+ "#vgdisplay\n"
+ "Give a short listing showing the existence of VGs.\n"
+ "#pvscan\n"
+ "Short listing format.\n")
+
+/* Not used */
+arg(stdin_ARG, 's', "stdin", 0, 0, 0, NULL)
+
+arg(select_ARG, 'S', "select", string_VAL, ARG_GROUPABLE, 0,
+ "Select objects for processing and reporting based on specified criteria.\n"
+ "The criteria syntax is described in lvmreport(7) under Selection.\n"
+ "For reporting commands, display rows that match the criteria.\n"
+ "All rows can be displayed with an additional \"selected\" field (-o selected)\n"
+ "showing 1 if the row matches the selection and 0 otherwise.\n"
+ "For non-reporting commands which process LVM entities, the selection is\n"
+ "used to choose items to process.\n")
+
+arg(test_ARG, 't', "test", 0, 0, 0,
+ "Run in test mode. Commands will not update metadata.\n"
+ "This is implemented by disabling all metadata writing but nevertheless\n"
+ "returning success to the calling function. This may lead to unusual\n"
+ "error messages in multi-stage operations if a tool relies on reading\n"
+ "back metadata it believes has changed but hasn't.\n")
+
+arg(thin_ARG, 'T', "thin", 0, 0, 0,
+ "Specifies the command is handling a thin LV or thin pool.\n"
+ "See --type thin, --type thin-pool, and --virtualsize.\n"
+ "See lvmthin(7) for more information about LVM thin provisioning.\n")
+
+arg(uuid_ARG, 'u', "uuid", 0, 0, 0,
+ "#pvchange\n"
+ "Generate new random UUID for specified PVs.\n"
+ "#pvscan\n"
+ "Show UUIDs in addition to device names.\n"
+ "#vgchange\n"
+ "Generate new random UUID for specified VGs.\n")
+
+arg(uuidstr_ARG, 'u', "uuid", string_VAL, 0, 0,
+ "Specify a UUID for the device.\n"
+ "Without this option, a random UUID is generated.\n"
+ "This option is needed before restoring a backup of LVM metadata\n"
+ "onto a replacement device; see vgcfgrestore(8). As such, use of\n"
+ "--restorefile is compulsory unless the --norestorefile is used.\n"
+ "All PVs must have unique UUIDs, and LVM will prevent certain operations\n"
+ "if multiple devices are seen with the same UUID.\n"
+ "See vgimportclone(8) for more information.\n")
+
+/* Not used */
+arg(uuidlist_ARG, 'U', "uuidlist", 0, 0, 0, NULL)
+
+arg(verbose_ARG, 'v', "verbose", 0, ARG_COUNTABLE, 0,
+ "Set verbose level. Repeat from 1 to 4 times to increase the detail\n"
+ "of messages sent to stdout and stderr.\n")
+
+/* Not used */
+arg(volumegroup_ARG, 'V', "volumegroup", 0, 0, 0, NULL)
+
+arg(virtualsize_ARG, 'V', "virtualsize", sizemb_VAL, 0, 0,
+ "The virtual size of a new thin LV.\n"
+ "See lvmthin(7) for more information about LVM thin provisioning.\n"
+ "Using virtual size (-V) and actual size (-L) together creates\n"
+ "a sparse LV.\n"
+ "lvm.conf global/sparse_segtype_default determines the\n"
+ "default segment type used to create a sparse LV.\n"
+ "Anything written to a sparse LV will be returned when reading from it.\n"
+ "Reading from other areas of the LV will return blocks of zeros.\n"
+ "When using a snapshot to create a sparse LV, a hidden virtual device\n"
+ "is created using the zero target, and the LV has the suffix _vorigin.\n"
+ "Snapshots are less efficient than thin provisioning when creating\n"
+ "large sparse LVs (GiB).\n")
+
+arg(wipesignatures_ARG, 'W', "wipesignatures", bool_VAL, 0, 0,
+ "Controls detection and subsequent wiping of signatures on new LVs.\n"
+ "There is a prompt for each signature detected to confirm its wiping\n"
+ "(unless --yes is used to override confirmations.)\n"
+ "When not specified, signatures are wiped whenever zeroing is done\n"
+ "(see --zero). This behaviour can be configured with\n"
+ "lvm.conf allocation/wipe_signatures_when_zeroing_new_lvs.\n"
+ "If blkid wiping is used (lvm.conf allocation/use_blkid_wiping)\n"
+ "and LVM is compiled with blkid wiping support, then the blkid(8)\n"
+ "library is used to detect the signatures (use blkid -k to list the\n"
+ "signatures that are recognized).\n"
+ "Otherwise, native LVM code is used to detect signatures\n"
+ "(only MD RAID, swap and LUKS signatures are detected in this case.)\n"
+ "The LV is not wiped if the read only flag is set.\n")
+
+arg(allocatable_ARG, 'x', "allocatable", bool_VAL, 0, 0,
+ "Enable or disable allocation of physical extents on this PV.\n")
+
+arg(resizeable_ARG, 'x', "resizeable", bool_VAL, 0, 0,
+ "Enables or disables the addition or removal of PVs to/from a VG\n"
+ "(by vgextend/vgreduce).\n")
+
+arg(yes_ARG, 'y', "yes", 0, 0, 0,
+ "Do not prompt for confirmation interactively but always assume the\n"
+ "answer yes. Use with extreme caution.\n")
+
+arg(zero_ARG, 'Z', "zero", bool_VAL, 0, 0,
+ "#lvchange\n"
+ "Set zeroing mode for thin pool. Note: already provisioned blocks from pool\n"
+ "in non-zero mode are not cleared in unwritten parts when setting --zero y.\n"
+ "#lvconvert\n"
+ "For snapshots, this controls zeroing of the first 4KiB of data in the\n"
+ "snapshot. If the LV is read-only, the snapshot will not be zeroed.\n"
+ "For thin pools, this controls zeroing of provisioned blocks.\n"
+ "Provisioning of large zeroed chunks negatively impacts performance.\n"
+ "#lvcreate\n"
+ "Controls zeroing of the first 4KiB of data in the new LV.\n"
+ "Default is \\fBy\\fP.\n"
+ "Snapshot COW volumes are always zeroed.\n"
+ "LV is not zeroed if the read only flag is set.\n"
+ "Warning: trying to mount an unzeroed LV can cause the system to hang.\n"
+ "#pvcreate\n"
+ "#vgcreate\n"
+ "#vgextend\n"
+ "Controls if the first 4 sectors (2048 bytes) of the device are wiped.\n"
+ "The default is to wipe these sectors unless either or both of\n"
+ "--restorefile or --uuid are specified.\n")
/* this should always be last */
-arg(ARG_COUNT, '-', "", 0, 0, 0)
+arg(ARG_COUNT, '-', "", 0, 0, 0, NULL)
/* *INDENT-ON* */
diff --git a/tools/create-commands.c b/tools/create-commands.c
index d9f8218..f9ff800 100644
--- a/tools/create-commands.c
+++ b/tools/create-commands.c
@@ -68,6 +68,7 @@ struct opt_name {
int val_enum; /* xyz_VAL when --foo takes a val like "--foo xyz" */
uint32_t unused1;
uint32_t unused2;
+ const char *desc;
};
/* also see val_props in tools.h and vals.h */
@@ -104,7 +105,7 @@ enum {
/* create foo_ARG enums for --option's */
enum {
-#define arg(a, b, c, d, e, f) a ,
+#define arg(a, b, c, d, e, f, g) a ,
#include "args.h"
#undef arg
};
@@ -136,7 +137,7 @@ static struct val_name val_names[VAL_COUNT + 1] = {
/* create table of option names, e.g. --foo, and corresponding enum from args.h */
static struct opt_name opt_names[ARG_COUNT + 1] = {
-#define arg(a, b, c, d, e, f) { # a, a, b, "", "--" c, d, e, f },
+#define arg(a, b, c, d, e, f, g) { # a, a, b, "", "--" c, d, e, f, g },
#include "args.h"
#undef arg
};
@@ -180,9 +181,15 @@ static struct cmd_name cmd_names[MAX_CMD_NAMES] = {
#undef xx
};
+/* array of pointers into opt_names[] that is sorted alphabetically (by long opt name) */
+
+static struct opt_name *opt_names_alpha[ARG_COUNT + 1];
+
#define MAX_LINE 1024
#define MAX_LINE_ARGC 256
+#define DESC_LINE 256
+
#define REQUIRED 1 /* required option */
#define OPTIONAL 0 /* optional option */
#define IGNORE -1 /* ignore option */
@@ -2050,6 +2057,23 @@ void print_man_usage(struct command *cmd)
printf("\n");
}
+/*
+ * common options listed in the usage section.
+ *
+ * For commands with only one variant, this is only
+ * the options which are common to all lvm commands
+ * (in lvm_all, see is_lvm_all_opt).
+ *
+ * For commands with more than one variant, this
+ * is the set of options common to all variants
+ * (in cname->common_options), (which obviously
+ * includes the options common to all lvm commands.)
+ *
+ * List ordering:
+ * options with short+long names, alphabetically,
+ * then options with only long names, alphabetically
+ */
+
void print_man_usage_common(struct command *cmd)
{
struct cmd_name *cname;
@@ -2063,23 +2087,17 @@ void print_man_usage_common(struct command *cmd)
printf(".RS 4\n");
printf("[");
- /*
- * when there's more than one variant, options that
- * are common to all commands with a common name.
- */
-
- if (cname->variants < 2)
- goto all;
-
/* print those with short opts */
- for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
+ for (i = 0; i < ARG_COUNT; i++) {
+ opt_enum = opt_names_alpha[i]->opt_enum;
+
if (!cname->common_options[opt_enum])
continue;
if (!opt_names[opt_enum].short_opt)
continue;
- if (is_lvm_all_opt(opt_enum))
+ if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
continue;
if (sep) {
@@ -2107,14 +2125,16 @@ void print_man_usage_common(struct command *cmd)
}
/* print those without short opts */
- for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
+ for (i = 0; i < ARG_COUNT; i++) {
+ opt_enum = opt_names_alpha[i]->opt_enum;
+
if (!cname->common_options[opt_enum])
continue;
if (opt_names[opt_enum].short_opt)
continue;
- if (is_lvm_all_opt(opt_enum))
+ if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
continue;
if (sep) {
@@ -2140,67 +2160,108 @@ void print_man_usage_common(struct command *cmd)
break;
}
}
- all:
- /* options that are common to all lvm commands */
-
- /* those with short opts */
- for (oo = 0; oo < lvm_all.oo_count; oo++) {
- opt_enum = lvm_all.optional_opt_args[oo].opt;
- if (!opt_names[opt_enum].short_opt)
- continue;
+ printf(" ]\n");
+ return;
+}
- if (sep) {
- printf(",");
- printf("\n.br\n");
- printf(" ");
- }
+/*
+ * Format of description, when different command names have
+ * different descriptions:
+ *
+ * "#cmdname1"
+ * "text foo goes here"
+ * "a second line of text."
+ * "#cmdname2"
+ * "text bar goes here"
+ * "another line of text."
+ *
+ * When called for cmdname2, this function should just print:
+ *
+ * "text bar goes here"
+ * "another line of text."
+ */
- printf(" \\fB-%c\\fP|\\fB%s\\fP",
- opt_names[opt_enum].short_opt,
- man_long_opt_name(cmd->name, opt_enum));
+static void print_man_option_desc(struct cmd_name *cname, int opt_enum)
+{
+ const char *desc = opt_names[opt_enum].desc;
+ char buf[DESC_LINE];
+ int started_cname = 0;
+ int line_count = 0;
+ int di, bi;
- if (lvm_all.optional_opt_args[oo].def.val_bits) {
- printf(" ");
- print_def(&lvm_all.optional_opt_args[oo].def, 1);
- }
- sep = 1;
+ if (desc[0] != '#') {
+ printf("%s", desc);
+ return;
}
- /* those without short opts */
- for (oo = 0; oo < lvm_all.oo_count; oo++) {
- opt_enum = lvm_all.optional_opt_args[oo].opt;
+ for (di = 0; di < strlen(desc); di++) {
+ buf[bi++] = desc[di];
- if (opt_names[opt_enum].short_opt)
+ if (bi == DESC_LINE) {
+ printf("print_man_option_desc line too long\n");
+ return;
+ }
+
+ if (buf[bi-1] != '\n')
continue;
- if (sep) {
- printf(",");
- printf("\n.br\n");
- printf(" ");
+ if (buf[0] != '#') {
+ if (started_cname) {
+ printf("%s", buf);
+ line_count++;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ bi = 0;
+ continue;
}
- /* space alignment without short opt */
- printf(" ");
+ /* Line starting with #cmdname */
- printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
+ /*
+ * Must be starting a new command name.
+ * If no lines have been printed, multiple command names
+ * are using the same text. If lines have been printed,
+ * then the start of a new command name means the end
+ * of text for the current command name.
+ */
+ if (line_count && started_cname)
+ return;
- if (lvm_all.optional_opt_args[oo].def.val_bits) {
- printf(" ");
- print_def(&lvm_all.optional_opt_args[oo].def, 1);
+ if (!strncmp(buf + 1, cname->name, strlen(cname->name))) {
+ /* The start of our command name. */
+ started_cname = 1;
+ memset(buf, 0, sizeof(buf));
+ bi = 0;
+ } else {
+ /* The start of another command name. */
+ memset(buf, 0, sizeof(buf));
+ bi = 0;
}
- sep = 1;
}
- printf(" ]\n");
+
+ if (bi && started_cname)
+ printf("%s", buf);
}
-void print_man_all_options(struct cmd_name *cname)
+/*
+ * Print a list of all options names for a given
+ * command name, listed by:
+ * options with short+long names, alphabetically,
+ * then options with only long names, alphabetically
+ */
+
+void print_man_all_options_list(struct cmd_name *cname)
{
int opt_enum, val_enum;
int sep = 0;
+ int i;
+
+ /* print those with both short and long opts */
+ for (i = 0; i < ARG_COUNT; i++) {
+ opt_enum = opt_names_alpha[i]->opt_enum;
- /* print those with short opts */
- for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
if (!cname->all_options[opt_enum])
continue;
@@ -2232,7 +2293,9 @@ void print_man_all_options(struct cmd_name *cname)
}
/* print those without short opts */
- for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
+ for (i = 0; i < ARG_COUNT; i++) {
+ opt_enum = opt_names_alpha[i]->opt_enum;
+
if (!cname->all_options[opt_enum])
continue;
@@ -2265,7 +2328,79 @@ void print_man_all_options(struct cmd_name *cname)
}
}
-#define DESC_LINE 256
+/*
+ * All options used for a given command name, along with descriptions.
+ * listed in order of:
+ * 1. options that are not common to all lvm commands, alphabetically
+ * 2. options common to all lvm commands, alphabetically
+ */
+
+void print_man_all_options_desc(struct cmd_name *cname)
+{
+ int opt_enum, val_enum;
+ int print_common = 0;
+ int sep = 0;
+ int i;
+
+ again:
+ /*
+ * Loop 1: print options that are not common to all lvm commands.
+ * Loop 2: print options common to all lvm commands (lvm_all)
+ */
+
+ for (i = 0; i < ARG_COUNT; i++) {
+ opt_enum = opt_names_alpha[i]->opt_enum;
+
+ if (!cname->all_options[opt_enum])
+ continue;
+
+ if (!print_common && is_lvm_all_opt(opt_enum))
+ continue;
+
+ if (print_common && !is_lvm_all_opt(opt_enum))
+ continue;
+
+ if (sep)
+ printf("\n.br\n");
+
+ printf("\n.TP\n");
+
+ if (opt_names[opt_enum].short_opt) {
+ printf("\\fB-%c\\fP|\\fB%s\\fP",
+ opt_names[opt_enum].short_opt,
+ man_long_opt_name(cname->name, opt_enum));
+ } else {
+ printf("\\fB%s\\fP", man_long_opt_name(cname->name, opt_enum));
+ }
+
+ val_enum = opt_names[opt_enum].val_enum;
+
+ if (!val_names[val_enum].fn) {
+ /* takes no arg */
+ } else if (!val_names[val_enum].usage) {
+ printf(" ");
+ printf("\\fI");
+ printf("%s", val_names[val_enum].name);
+ printf("\\fP");
+ } else {
+ printf(" ");
+ print_val_man(val_names[val_enum].usage);
+ }
+
+ if (opt_names[opt_enum].desc) {
+ printf("\n");
+ printf(".br\n");
+ print_man_option_desc(cname, opt_enum);
+ }
+
+ sep = 1;
+ }
+
+ if (!print_common) {
+ print_common = 1;
+ goto again;
+ }
+}
void print_desc_man(const char *desc)
{
@@ -2338,6 +2473,12 @@ void print_man_command(void)
printf("Common options:\n");
printf(".\n");
print_man_usage_common(prev_cmd);
+
+ printf("\n");
+ printf(".SH OPTIONS\n");
+ printf(".br\n");
+ print_man_all_options_desc(cname);
+
prev_cmd = NULL;
}
@@ -2396,7 +2537,7 @@ void print_man_command(void)
/* listing them all when there's only 1 or 2 is just repetative */
if (cname->variants > 2) {
printf(".P\n");
- print_man_all_options(cname);
+ print_man_all_options_list(cname);
printf("\n");
printf(".P\n");
printf("\n");
@@ -2419,6 +2560,12 @@ void print_man_command(void)
printf("Common options:\n");
printf(".\n");
print_man_usage_common(cmd);
+
+ printf("\n");
+ printf(".SH OPTIONS\n");
+ printf(".br\n");
+ print_man_all_options_desc(cname);
+
}
printf("\n");
@@ -2730,6 +2877,23 @@ next:
}
}
+static int long_name_compare(const void *on1, const void *on2)
+{
+ struct opt_name **optname1 = (void *)on1;
+ struct opt_name **optname2 = (void *)on2;
+ return strcmp((*optname1)->long_opt + 2, (*optname2)->long_opt + 2);
+}
+
+static void create_opt_names_alpha(void)
+{
+ int i;
+
+ for (i = 0; i < ARG_COUNT; i++)
+ opt_names_alpha[i] = &opt_names[i];
+
+ qsort(opt_names_alpha, ARG_COUNT, sizeof(long), long_name_compare);
+}
+
void print_command_list(void)
{
int i;
@@ -2754,6 +2918,17 @@ void print_option_list(void)
opt_names[i].short_opt ? opt_names[i].short_opt : 0);
}
+void print_option_alpha_list(void)
+{
+ int i;
+
+ for (i = 0; i < ARG_COUNT; i++)
+ printf("%d %s %s %c (%d)\n",
+ opt_names_alpha[i]->opt_enum, opt_names_alpha[i]->name,
+ opt_names_alpha[i]->long_opt, opt_names_alpha[i]->short_opt ?: ' ',
+ opt_names_alpha[i]->short_opt ? opt_names_alpha[i]->short_opt : 0);
+}
+
static void print_help(int argc, char *argv[])
{
printf("%s [options] --output <format> <filename>\n", argv[0]);
@@ -2791,9 +2966,12 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
+ create_opt_names_alpha();
+
if (!strcmp(argv[1], "debug")) {
print_command_list();
print_option_list();
+ print_option_alpha_list();
return 0;
}
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 4f1718b..afc941b 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -64,7 +64,7 @@ static struct val_props _val_props[VAL_COUNT + 1] = {
* Table of valid --option's
*/
static struct arg_props _arg_props[ARG_COUNT + 1] = {
-#define arg(a, b, c, d, e, f) {a, b, "", "--" c, d, e, f},
+#define arg(a, b, c, d, e, f, g) {a, b, "", "--" c, d, e, f, g},
#include "args.h"
#undef arg
};
diff --git a/tools/tools.h b/tools/tools.h
index 89ee8ad..392490f 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -59,7 +59,7 @@ enum {
/* define the enums for the command line --options, foo_ARG */
enum {
-#define arg(a, b, c, d, e, f) a ,
+#define arg(a, b, c, d, e, f, g) a ,
#include "args.h"
#undef arg
};
@@ -109,6 +109,7 @@ struct arg_props {
int val_enum; /* foo_VAL from vals.h */
uint32_t flags;
uint32_t prio;
+ const char *desc;
};
struct arg_value_group_list {
7 years, 3 months
master - args: use uint32 arg for maxphysicalvolumes
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=db26a82f2f464d...
Commit: db26a82f2f464d0f710229c24d67c83818fd8f3c
Parent: 041c2fef88ab2e546555625039a17ccbb7b1c9c5
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jan 3 15:52:27 2017 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Feb 13 08:20:10 2017 -0600
args: use uint32 arg for maxphysicalvolumes
---
tools/args.h | 2 +-
tools/command-lines.in | 6 +++---
tools/create-commands.c | 1 +
tools/vals.h | 1 +
4 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/tools/args.h b/tools/args.h
index 559bf16..690b4ee 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -204,7 +204,7 @@ arg(novolumegroup_ARG, 'n', "novolumegroup", 0, 0, 0)
arg(oldpath_ARG, 'n', "oldpath", 0, 0, 0)
arg(options_ARG, 'o', "options", string_VAL, ARG_GROUPABLE, 0)
arg(sort_ARG, 'O', "sort", string_VAL, ARG_GROUPABLE, 0)
-arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", number_VAL, 0, 0)
+arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", uint32_VAL, 0, 0)
arg(permission_ARG, 'p', "permission", permission_VAL, 0, 0)
arg(partial_ARG, 'P', "partial", 0, 0, 0)
arg(physicalvolume_ARG, 'P', "physicalvolume", 0, 0, 0)
diff --git a/tools/command-lines.in b/tools/command-lines.in
index ebe7006..f99cb8c 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1335,7 +1335,7 @@ OO_VGCHANGE: --autobackup Bool, --ignoremonitoring, --ignoreskippedcluster,
# because it can function as a required opt.
OO_VGCHANGE_META: --addtag Tag, --deltag Tag,
---logicalvolume Number, --maxphysicalvolumes Number, --alloc Alloc, --uuid,
+--logicalvolume Number, --maxphysicalvolumes Uint32, --alloc Alloc, --uuid,
--clustered Bool, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
--physicalextentsize SizeMB, --resizeable Bool, --systemid String, --locktype LockType,
--profile String, --detachprofile, --metadataprofile String
@@ -1402,7 +1402,7 @@ ID: vgconvert_general
vgcreate VG_new PV ...
OO: --addtag Tag, --alloc Alloc, --autobackup Bool, --clustered Bool, --maxlogicalvolumes Number,
---maxphysicalvolumes Number, --metadataprofile String, --metadatatype MetadataType,
+--maxphysicalvolumes Uint32, --metadataprofile String, --metadatatype MetadataType,
--physicalextentsize SizeMB, --force, --zero Bool, --labelsector Number,
--metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
--reportformat ReportFmt, --dataalignment SizeKB, --dataalignmentoffset SizeKB,
@@ -1535,7 +1535,7 @@ OO_VGSPLIT: --autobackup Bool
# used only when the destination VG is new
OO_VGSPLIT_NEW: --alloc Alloc, --clustered Bool,
---maxlogicalvolumes Number, --maxphysicalvolumes Number,
+--maxlogicalvolumes Number, --maxphysicalvolumes Uint32,
--metadatatype MetadataType, --vgmetadatacopies MetadataCopiesVG
vgsplit VG VG PV ...
diff --git a/tools/create-commands.c b/tools/create-commands.c
index 704ec47..d9f8218 100644
--- a/tools/create-commands.c
+++ b/tools/create-commands.c
@@ -34,6 +34,7 @@ int size_kb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int size_mb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int int_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
+int uint32_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int major_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
diff --git a/tools/vals.h b/tools/vals.h
index c8c998f..12d315f 100644
--- a/tools/vals.h
+++ b/tools/vals.h
@@ -99,6 +99,7 @@ val(conststr_VAL, NULL, "ConstString", "ERR") /* used only for command defs */
val(constnum_VAL, NULL, "ConstNumber", "ERR") /* used only for command defs */
val(bool_VAL, yes_no_arg, "Bool", "y|n")
val(number_VAL, int_arg, "Number", NULL)
+val(uint32_VAL, uint32_arg, "Uint32", "Number")
val(string_VAL, string_arg, "String", NULL)
val(vg_VAL, string_arg, "VG", NULL)
val(lv_VAL, string_arg, "LV", NULL)
7 years, 3 months
master - lvconvert: remove unused code
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=041c2fef88ab2e...
Commit: 041c2fef88ab2e546555625039a17ccbb7b1c9c5
Parent: 46b2599d5c4e01eee66be7c45aa6cf36d7cbc50f
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Dec 20 15:17:48 2016 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Feb 13 08:20:10 2017 -0600
lvconvert: remove unused code
---
tools/lvconvert.c | 3170 +++++++++++++++--------------------------------------
1 files changed, 882 insertions(+), 2288 deletions(-)
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 642d6b7..757e8b4 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -19,25 +19,6 @@
#include "lvconvert_poll.h"
#include "command-lines-count.h"
-/*
- * Guidelines for mapping options to operations.
- *
- * There should be a clear and unique correspondence between an option
- * name and the operation to be performed.
- *
- * An option with a given name should always perform the same operation.
- * If the same operation applies to two types of LV, then the same option
- * name can be used with both LV types. But, a given option name should
- * not be used to perform different operations depending on the LV type it
- * is used with.
- *
- * --merge and --split are examples where a single option name has been
- * overloaded with different operations. The case of --split has been
- * corrected with the clear and unique variations --splitcache,
- * --splitsnapshot, --splitmirror, which should allow --split to be
- * deprecated. (The same is still needed for --merge.)
- */
-
typedef enum {
/* Split:
* For a mirrored or raid LV, split mirror into two mirrors, optionally tracking
@@ -52,23 +33,13 @@ typedef enum {
struct lvconvert_params {
/* Exactly one of these 12 command categories is determined */
- int merge; /* 1 */
- int split; /* 2 */
- int splitsnapshot; /* 3 */
- int splitcache; /* 4 */
- int keep_mimages; /* 5 */ /* --splitmirrors */
- int cache; /* 6 */
- int uncache; /* 7 */
- int snapshot; /* 8 */
- int thin; /* 11 */
- /* other */ /* 12 */
+ int split; /* 1 */
+ int keep_mimages; /* 2 */ /* --splitmirrors */
+ /* other */ /* 3 */
/* FIXME Eliminate all cases where more than one of the above are set then use conv_type instead */
conversion_type_t conv_type;
- int merge_snapshot; /* CONV_MERGE is set */
- int merge_mirror; /* CONV_MERGE is set */
-
int track_changes; /* CONV_SPLIT_MIRRORS is set */
int corelog; /* Equivalent to --mirrorlog core */
@@ -80,7 +51,6 @@ struct lvconvert_params {
const struct segment_type *segtype; /* Holds what segment type you will get */
- int poolmetadataspare;
int force;
int yes;
int zero;
@@ -92,8 +62,6 @@ struct lvconvert_params {
int wait_completion;
int need_polling;
- int thin_chunk_size_calc_policy;
- uint32_t chunk_size;
uint32_t region_size;
uint32_t mirrors;
@@ -103,9 +71,6 @@ struct lvconvert_params {
unsigned stripes_supplied;
unsigned stripe_size_supplied;
uint32_t read_ahead;
- cache_mode_t cache_mode; /* cache */
- const char *policy_name; /* cache */
- struct dm_config_tree *policy_settings; /* cache */
unsigned target_attr;
@@ -118,15 +83,7 @@ struct lvconvert_params {
struct logical_volume *lv_to_poll;
struct dm_list idls;
- uint32_t pool_metadata_extents;
- int passed_args;
- uint64_t pool_metadata_size;
const char *origin_name;
- const char *pool_data_name;
- struct logical_volume *pool_data_lv;
- const char *pool_metadata_name;
- struct logical_volume *pool_metadata_lv;
- thin_discards_t discards;
};
struct convert_poll_id_list {
@@ -145,12 +102,6 @@ static void _set_conv_type(struct lvconvert_params *lp, int conv_type)
lp->conv_type = conv_type;
}
-/* -s/--snapshot and --type snapshot are synonyms */
-static int _snapshot_type_requested(struct cmd_context *cmd, const char *type_str)
-{
- return (arg_is_set(cmd, snapshot_ARG) || !strcmp(type_str, SEG_TYPE_NAME_SNAPSHOT));
-}
-
static int _raid0_type_requested(const char *type_str)
{
return (!strcmp(type_str, SEG_TYPE_NAME_RAID0) || !strcmp(type_str, SEG_TYPE_NAME_RAID0_META));
@@ -1282,11 +1233,6 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
return 0;
}
- if (lp->merge_mirror) {
- log_error("Unable to merge mirror images of segment type 'mirror'.");
- return 0;
- }
-
if (!_lvconvert_validate_thin(lv, lp))
return_0;
@@ -1424,7 +1370,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
if (!_is_valid_raid_conversion(seg->segtype, lp->segtype))
goto try_new_takeover_or_reshape;
- if (seg_is_linear(seg) && !lp->merge_mirror && !lp->mirrors_supplied) {
+ if (seg_is_linear(seg) && !lp->mirrors_supplied) {
if (_raid0_type_requested(lp->type_str)) {
log_error("Linear LV %s cannot be converted to %s.",
display_lvname(lv), lp->type_str);
@@ -1466,9 +1412,6 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
return 0;
}
- if (lp->merge_mirror)
- return lv_raid_merge(lv);
-
if (lp->track_changes)
return lv_raid_split_and_track(lv, lp->pvh);
@@ -1563,97 +1506,413 @@ try_new_takeover_or_reshape:
return 0;
}
-static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volume *cow)
+/*
+ * Functions called to perform a specific operation on a specific LV type.
+ *
+ * _convert_<lvtype>_<operation>
+ *
+ * For cases where an operation does not apply to the LV itself, but
+ * is implicitly redirected to a sub-LV, these functions locate the
+ * correct sub-LV and call the operation on that sub-LV. If a sub-LV
+ * of the proper type is not found, these functions report the error.
+ *
+ * FIXME: the _lvconvert_foo() functions can be cleaned up since they
+ * are now only called for valid combinations of LV type and operation.
+ * After that happens, the code remaining in those functions can be
+ * moved into the _convert_lvtype_operation() functions below.
+ */
+
+/*
+ * Change the number of images in a mirror LV.
+ * lvconvert --mirrors Number LV
+ */
+static int _convert_mirror_number(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
{
- struct volume_group *vg = cow->vg;
- const char *cow_name = display_lvname(cow);
+ return _lvconvert_mirrors(cmd, lv, lp);
+}
- if (lv_is_virtual_origin(origin_from_cow(cow))) {
- log_error("Unable to split off snapshot %s with virtual origin.", cow_name);
- return 0;
- }
+/*
+ * Split images from a mirror LV and use them to create a new LV.
+ * lvconvert --splitmirrors Number LV
+ *
+ * Required options:
+ * --name Name
+ */
- if (!(vg->fid->fmt->features & FMT_MDAS)) {
- log_error("Unable to split off snapshot %s using old LVM1-style metadata.", cow_name);
- return 0;
- }
+static int _convert_mirror_splitmirrors(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ return _lvconvert_mirrors(cmd, lv, lp);
+}
- if (is_lockd_type(vg->lock_type)) {
- /* FIXME: we need to create a lock for the new LV. */
- log_error("Unable to split snapshots in VG with lock_type %s.", vg->lock_type);
- return 0;
- }
+/*
+ * Change the type of log used by a mirror LV.
+ * lvconvert --mirrorlog Type LV
+ */
+static int _convert_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ return _lvconvert_mirrors(cmd, lv, lp);
+}
- if (lv_is_active_locally(cow)) {
- if (!lv_check_not_in_use(cow, 1))
- return_0;
+/*
+ * Convert mirror LV to linear LV.
+ * lvconvert --type linear LV
+ *
+ * Alternate syntax:
+ * lvconvert --mirrors 0 LV
+ */
+static int _convert_mirror_linear(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ return _lvconvert_mirrors(cmd, lv, lp);
+}
- if ((arg_count(cmd, force_ARG) == PROMPT) &&
- !arg_count(cmd, yes_ARG) &&
- lv_is_visible(cow) &&
- lv_is_active(cow)) {
- if (yes_no_prompt("Do you really want to split off active "
- "logical volume %s? [y/n]: ", display_lvname(cow)) == 'n') {
- log_error("Logical volume %s not split.", display_lvname(cow));
- return 0;
- }
- }
- }
+/*
+ * Convert mirror LV to raid1 LV.
+ * lvconvert --type raid1 LV
+ */
+static int _convert_mirror_raid(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ return _lvconvert_raid(lv, lp);
+}
- if (!archive(vg))
- return_0;
+/*
+ * Change the number of images in a raid1 LV.
+ * lvconvert --mirrors Number LV
+ */
+static int _convert_raid_number(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ return _lvconvert_raid(lv, lp);
+}
- log_verbose("Splitting snapshot %s from its origin.", display_lvname(cow));
+/*
+ * Split images from a raid1 LV and use them to create a new LV.
+ * lvconvert --splitmirrors Number LV
+ *
+ * Required options:
+ * --trackchanges | --name Name
+ */
+static int _convert_raid_splitmirrors(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ /* FIXME: split the splitmirrors section out of _lvconvert_raid and call it here. */
+ return _lvconvert_raid(lv, lp);
+}
- if (!vg_remove_snapshot(cow))
- return_0;
+/*
+ * Convert a raid* LV to use a different raid level.
+ * lvconvert --type raid* LV
+ */
+static int _convert_raid_raid(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ return _lvconvert_raid(lv, lp);
+}
- backup(vg);
+/*
+ * Convert a raid* LV to a mirror LV.
+ * lvconvert --type mirror LV
+ */
+static int _convert_raid_mirror(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ return _lvconvert_raid(lv, lp);
+}
- log_print_unless_silent("Logical Volume %s split from its origin.", display_lvname(cow));
+/*
+ * Convert a raid* LV to a striped LV.
+ * lvconvert --type striped LV
+ */
+static int _convert_raid_striped(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ return _lvconvert_raid(lv, lp);
+}
- return 1;
+/*
+ * Convert a raid* LV to a linear LV.
+ * lvconvert --type linear LV
+ */
+static int _convert_raid_linear(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ return _lvconvert_raid(lv, lp);
}
-static int _lvconvert_split_and_keep_cachepool(struct cmd_context *cmd,
- struct logical_volume *lv,
- struct logical_volume *cachepool_lv)
+/*
+ * Convert a striped/linear LV to a mirror LV.
+ * lvconvert --type mirror LV
+ *
+ * Required options:
+ * --mirrors Number
+ *
+ * Alternate syntax:
+ * This is equivalent to above when global/mirror_segtype_default="mirror".
+ * lvconvert --mirrors Number LV
+ */
+static int _convert_striped_mirror(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
{
- log_debug("Detaching cache pool %s from cache LV %s.",
- display_lvname(cachepool_lv), display_lvname(lv));
+ return _lvconvert_mirrors(cmd, lv, lp);
+}
- if (!archive(lv->vg))
- return_0;
+/*
+ * Convert a striped/linear LV to a raid* LV.
+ * lvconvert --type raid* LV
+ *
+ * Required options:
+ * --mirrors Number
+ *
+ * Alternate syntax:
+ * This is equivalent to above when global/mirror_segtype_default="raid1".
+ * lvconvert --mirrors Number LV
+ */
+static int _convert_striped_raid(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ return _lvconvert_raid(lv, lp);
+}
- if (!lv_cache_remove(lv))
- return_0;
+static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ if (arg_is_set(cmd, mirrors_ARG))
+ return _convert_mirror_number(cmd, lv, lp);
- if (!vg_write(lv->vg) || !vg_commit(lv->vg))
- return_0;
+ if (arg_is_set(cmd, splitmirrors_ARG))
+ return _convert_mirror_splitmirrors(cmd, lv, lp);
- backup(lv->vg);
+ if (arg_is_set(cmd, mirrorlog_ARG) || arg_is_set(cmd, corelog_ARG))
+ return _convert_mirror_log(cmd, lv, lp);
- log_print_unless_silent("Logical volume %s is not cached and cache pool %s is unused.",
- display_lvname(lv), display_lvname(cachepool_lv));
+ if (_linear_type_requested(lp->type_str))
+ return _convert_mirror_linear(cmd, lv, lp);
- return 1;
+ if (segtype_is_raid(lp->segtype))
+ return _convert_mirror_raid(cmd, lv, lp);
+
+ log_error("Unknown operation on mirror LV %s.", display_lvname(lv));
+ return 0;
}
-static int _lvconvert_split_and_remove_cachepool(struct cmd_context *cmd,
- struct logical_volume *lv,
- struct logical_volume *cachepool_lv)
+static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
{
- struct lv_segment *seg;
- struct logical_volume *remove_lv;
+ if (arg_is_set(cmd, mirrors_ARG))
+ return _convert_raid_number(cmd, lv, lp);
- seg = first_seg(lv);
+ if (arg_is_set(cmd, splitmirrors_ARG))
+ return _convert_raid_splitmirrors(cmd, lv, lp);
- if (lv_is_partial(seg_lv(seg, 0))) {
- log_warn("WARNING: Cache origin logical volume %s is missing.",
- display_lvname(seg_lv(seg, 0)));
- remove_lv = lv; /* When origin is missing, drop everything */
- } else
- remove_lv = seg->pool_lv;
+ if (segtype_is_raid(lp->segtype))
+ return _convert_raid_raid(cmd, lv, lp);
+
+ if (segtype_is_mirror(lp->segtype))
+ return _convert_raid_mirror(cmd, lv, lp);
+
+ if (!strcmp(lp->type_str, SEG_TYPE_NAME_STRIPED))
+ return _convert_raid_striped(cmd, lv, lp);
+
+ if (_linear_type_requested(lp->type_str))
+ return _convert_raid_linear(cmd, lv, lp);
+
+ log_error("Unknown operation on raid LV %s.", display_lvname(lv));
+ return 0;
+}
+
+static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ const char *mirrors_type = find_config_tree_str(cmd, global_mirror_segtype_default_CFG, NULL);
+
+ if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR))
+ return _convert_striped_mirror(cmd, lv, lp);
+
+ if (segtype_is_raid(lp->segtype))
+ return _convert_striped_raid(cmd, lv, lp);
+
+ /* --mirrors can mean --type mirror or --type raid1 depending on config setting. */
+
+ if (arg_is_set(cmd, mirrors_ARG) && mirrors_type && !strcmp(mirrors_type, SEG_TYPE_NAME_MIRROR))
+ return _convert_striped_mirror(cmd, lv, lp);
+
+ if (arg_is_set(cmd, mirrors_ARG) && mirrors_type && !strcmp(mirrors_type, SEG_TYPE_NAME_RAID1))
+ return _convert_striped_raid(cmd, lv, lp);
+
+ log_error("Unknown operation on striped or linear LV %s.", display_lvname(lv));
+ return 0;
+}
+
+static int _lvconvert_raid_types(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvconvert_params *lp)
+{
+ struct lv_segment *seg = first_seg(lv);
+ int ret = 0;
+
+ /* Set up segtype either from type_str or else to match the existing one. */
+ if (!*lp->type_str)
+ lp->segtype = seg->segtype;
+ else if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str)))
+ goto_out;
+
+ if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) {
+ if (!lp->mirrors_supplied && !seg_is_raid1(seg)) {
+ log_error("Conversions to --type mirror require -m/--mirrors");
+ goto out;
+ }
+ }
+
+ /* lv->segtype can't be NULL */
+ if (activation() && lp->segtype->ops->target_present &&
+ !lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) {
+ log_error("%s: Required device-mapper target(s) not "
+ "detected in your kernel.", lp->segtype->name);
+ goto out;
+ }
+
+ /* Process striping parameters */
+ /* FIXME This is incomplete */
+ if (_mirror_or_raid_type_requested(cmd, lp->type_str) || _raid0_type_requested(lp->type_str) ||
+ _striped_type_requested(lp->type_str) || lp->mirrorlog || lp->corelog) {
+ /* FIXME Handle +/- adjustments too? */
+ if (!get_stripe_params(cmd, lp->segtype, &lp->stripes, &lp->stripe_size, &lp->stripes_supplied, &lp->stripe_size_supplied))
+ goto_out;
+
+ if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str))
+ /* FIXME Shouldn't need to override get_stripe_params which defaults to 1 stripe (i.e. linear)! */
+ /* The default keeps existing number of stripes, handled inside the library code */
+ if (!arg_is_set(cmd, stripes_long_ARG))
+ lp->stripes = 0;
+ }
+
+ if (lv_is_cache(lv))
+ lv = seg_lv(first_seg(lv), 0);
+
+ if (lv_is_mirror(lv)) {
+ ret = _convert_mirror(cmd, lv, lp);
+ goto out;
+ }
+
+ if (lv_is_raid(lv)) {
+ ret = _convert_raid(cmd, lv, lp);
+ goto out;
+ }
+
+ /*
+ * FIXME: add lv_is_striped() and lv_is_linear()?
+ * This does not include raid0 which is caught by the test above.
+ * If operations differ between striped and linear, split this case.
+ */
+ if (segtype_is_striped(seg->segtype) || segtype_is_linear(seg->segtype)) {
+ ret = _convert_striped(cmd, lv, lp);
+ goto out;
+ }
+
+ /*
+ * The intention is to explicitly check all cases above and never
+ * reach here, but this covers anything that was missed.
+ */
+ log_error("Cannot convert LV %s.", display_lvname(lv));
+
+out:
+ return ret ? ECMD_PROCESSED : ECMD_FAILED;
+}
+
+static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volume *cow)
+{
+ struct volume_group *vg = cow->vg;
+ const char *cow_name = display_lvname(cow);
+
+ if (lv_is_virtual_origin(origin_from_cow(cow))) {
+ log_error("Unable to split off snapshot %s with virtual origin.", cow_name);
+ return 0;
+ }
+
+ if (!(vg->fid->fmt->features & FMT_MDAS)) {
+ log_error("Unable to split off snapshot %s using old LVM1-style metadata.", cow_name);
+ return 0;
+ }
+
+ if (is_lockd_type(vg->lock_type)) {
+ /* FIXME: we need to create a lock for the new LV. */
+ log_error("Unable to split snapshots in VG with lock_type %s.", vg->lock_type);
+ return 0;
+ }
+
+ if (lv_is_active_locally(cow)) {
+ if (!lv_check_not_in_use(cow, 1))
+ return_0;
+
+ if ((arg_count(cmd, force_ARG) == PROMPT) &&
+ !arg_count(cmd, yes_ARG) &&
+ lv_is_visible(cow) &&
+ lv_is_active(cow)) {
+ if (yes_no_prompt("Do you really want to split off active "
+ "logical volume %s? [y/n]: ", display_lvname(cow)) == 'n') {
+ log_error("Logical volume %s not split.", display_lvname(cow));
+ return 0;
+ }
+ }
+ }
+
+ if (!archive(vg))
+ return_0;
+
+ log_verbose("Splitting snapshot %s from its origin.", display_lvname(cow));
+
+ if (!vg_remove_snapshot(cow))
+ return_0;
+
+ backup(vg);
+
+ log_print_unless_silent("Logical Volume %s split from its origin.", display_lvname(cow));
+
+ return 1;
+}
+
+static int _lvconvert_split_and_keep_cachepool(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct logical_volume *cachepool_lv)
+{
+ log_debug("Detaching cache pool %s from cache LV %s.",
+ display_lvname(cachepool_lv), display_lvname(lv));
+
+ if (!archive(lv->vg))
+ return_0;
+
+ if (!lv_cache_remove(lv))
+ return_0;
+
+ if (!vg_write(lv->vg) || !vg_commit(lv->vg))
+ return_0;
+
+ backup(lv->vg);
+
+ log_print_unless_silent("Logical volume %s is not cached and cache pool %s is unused.",
+ display_lvname(lv), display_lvname(cachepool_lv));
+
+ return 1;
+}
+
+static int _lvconvert_split_and_remove_cachepool(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct logical_volume *cachepool_lv)
+{
+ struct lv_segment *seg;
+ struct logical_volume *remove_lv;
+
+ seg = first_seg(lv);
+
+ if (lv_is_partial(seg_lv(seg, 0))) {
+ log_warn("WARNING: Cache origin logical volume %s is missing.",
+ display_lvname(seg_lv(seg, 0)));
+ remove_lv = lv; /* When origin is missing, drop everything */
+ } else
+ remove_lv = seg->pool_lv;
if (lv_is_partial(seg_lv(first_seg(seg->pool_lv), 0)))
log_warn("WARNING: Cache pool data logical volume %s is missing.",
@@ -2179,49 +2438,45 @@ deactivate_pmslv:
return 1;
}
-/* Currently converts only to thin volume with external origin */
-static int _lvconvert_thin(struct cmd_context *cmd,
+static int _lvconvert_to_thin_with_external(struct cmd_context *cmd,
struct logical_volume *lv,
- struct lvconvert_params *lp)
+ struct logical_volume *thinpool_lv)
{
- struct logical_volume *torigin_lv, *pool_lv = lp->pool_data_lv;
struct volume_group *vg = lv->vg;
+ struct logical_volume *thin_lv;
+ const char *origin_name;
+
struct lvcreate_params lvc = {
.activate = CHANGE_AEY,
.alloc = ALLOC_INHERIT,
- .lv_name = lp->origin_name,
.major = -1,
.minor = -1,
.suppress_zero_warn = 1, /* Suppress warning for this thin */
.permission = LVM_READ,
- .pool_name = pool_lv->name,
+ .pool_name = thinpool_lv->name,
.pvh = &vg->pvs,
.read_ahead = DM_READ_AHEAD_AUTO,
.stripes = 1,
.virtual_extents = lv->le_count,
};
- if (lv == pool_lv) {
+ if (lv == thinpool_lv) {
log_error("Can't use same LV %s for thin pool and thin volume.",
- display_lvname(pool_lv));
+ display_lvname(thinpool_lv));
return 0;
}
- if (lv_is_locked(lv) ||
- !lv_is_visible(lv) ||
- lv_is_cow(lv) ||
- lv_is_pool(lv) ||
- lv_is_pool_data(lv) ||
- lv_is_pool_metadata(lv)) {
- log_error("Can't use%s%s %s %s as external origin.",
- lv_is_locked(lv) ? " locked" : "",
- lv_is_visible(lv) ? "" : " hidden",
- lvseg_name(first_seg(lv)),
- display_lvname(lv));
- return 0;
- }
+ if ((origin_name = arg_str_value(cmd, originname_ARG, NULL)))
+ if (!validate_restricted_lvname_param(cmd, &vg->name, &origin_name))
+ return_0;
+
+ /*
+ * If NULL, an auto-generated 'lvol' name is used.
+ * If set, the lv create code checks the name isn't used.
+ */
+ lvc.lv_name = origin_name;
- if (is_lockd_type(lv->vg->lock_type)) {
+ if (is_lockd_type(vg->lock_type)) {
/*
* FIXME: external origins don't work in lockd VGs.
* Prior to the lvconvert, there's a lock associated with
@@ -2233,13 +2488,13 @@ static int _lvconvert_thin(struct cmd_context *cmd,
* lock for the new LV uuid used by the external LV.
*/
log_error("Can't use lock_type %s LV as external origin.",
- lv->vg->lock_type);
+ vg->lock_type);
return 0;
}
dm_list_init(&lvc.tags);
- if (!pool_supports_external_origin(first_seg(pool_lv), lv))
+ if (!pool_supports_external_origin(first_seg(thinpool_lv), lv))
return_0;
if (!(lvc.segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_THIN)))
@@ -2248,14 +2503,22 @@ static int _lvconvert_thin(struct cmd_context *cmd,
if (!archive(vg))
return_0;
- /* New thin LV needs to be created (all messages sent to pool)
- * In this case thin volume is created READ-ONLY and
- * also warn about not zeroing is suppressed. */
- if (!(torigin_lv = lv_create_single(vg, &lvc)))
+ /*
+ * New thin LV needs to be created (all messages sent to pool) In this
+ * case thin volume is created READ-ONLY and also warn about not
+ * zeroing is suppressed.
+ *
+ * The new thin LV is created with the origin_name, or an autogenerated
+ * 'lvol' name. Then the names and ids are swapped between the thin LV
+ * and the original/external LV. So, the thin LV gets the name and id
+ * of the original LV arg, and the original LV arg gets the origin_name
+ * or the autogenerated name.
+ */
+
+ if (!(thin_lv = lv_create_single(vg, &lvc)))
return_0;
- /* Deactivate prepared Thin LV */
- if (!deactivate_lv(cmd, torigin_lv)) {
+ if (!deactivate_lv(cmd, thin_lv)) {
log_error("Aborting. Unable to deactivate new LV. "
"Manual intervention required.");
return 0;
@@ -2266,47 +2529,45 @@ static int _lvconvert_thin(struct cmd_context *cmd,
* which could be easily removed by the user after i.e. power-off
*/
- if (!swap_lv_identifiers(cmd, torigin_lv, lv)) {
+ if (!swap_lv_identifiers(cmd, thin_lv, lv)) {
stack;
goto revert_new_lv;
}
/* Preserve read-write status of original LV here */
- torigin_lv->status |= (lv->status & LVM_WRITE);
+ thin_lv->status |= (lv->status & LVM_WRITE);
- if (!attach_thin_external_origin(first_seg(torigin_lv), lv)) {
+ if (!attach_thin_external_origin(first_seg(thin_lv), lv)) {
stack;
goto revert_new_lv;
}
- if (!lv_update_and_reload(torigin_lv)) {
+ if (!lv_update_and_reload(thin_lv)) {
stack;
goto deactivate_and_revert_new_lv;
}
- log_print_unless_silent("Converted %s to thin volume with "
- "external origin %s.",
- display_lvname(torigin_lv),
- display_lvname(lv));
+ log_print_unless_silent("Converted %s to thin volume with external origin %s.",
+ display_lvname(thin_lv), display_lvname(lv));
return 1;
deactivate_and_revert_new_lv:
- if (!swap_lv_identifiers(cmd, torigin_lv, lv))
+ if (!swap_lv_identifiers(cmd, thin_lv, lv))
stack;
- if (!deactivate_lv(cmd, torigin_lv)) {
+ if (!deactivate_lv(cmd, thin_lv)) {
log_error("Unable to deactivate failed new LV. "
"Manual intervention required.");
return 0;
}
- if (!detach_thin_external_origin(first_seg(torigin_lv)))
+ if (!detach_thin_external_origin(first_seg(thin_lv)))
return_0;
revert_new_lv:
/* FIXME Better to revert to backup of metadata? */
- if (!lv_remove(torigin_lv) || !vg_write(vg) || !vg_commit(vg))
+ if (!lv_remove(thin_lv) || !vg_write(vg) || !vg_commit(vg))
log_error("Manual intervention may be required to remove "
"abandoned LV(s) before retrying.");
else
@@ -2315,269 +2576,225 @@ revert_new_lv:
return 0;
}
-static int _lvconvert_to_thin_with_external(struct cmd_context *cmd,
- struct logical_volume *lv,
- struct logical_volume *thinpool_lv)
+static int _lvconvert_swap_pool_metadata(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct logical_volume *metadata_lv)
{
struct volume_group *vg = lv->vg;
- struct logical_volume *thin_lv;
- const char *origin_name;
+ struct logical_volume *prev_metadata_lv;
+ struct lv_segment *seg;
+ struct lv_types *lvtype;
+ char meta_name[NAME_LEN];
+ const char *swap_name;
+ uint32_t chunk_size;
+ int is_thinpool;
+ int is_cachepool;
+ int lvt_enum;
- struct lvcreate_params lvc = {
- .activate = CHANGE_AEY,
- .alloc = ALLOC_INHERIT,
- .major = -1,
- .minor = -1,
- .suppress_zero_warn = 1, /* Suppress warning for this thin */
- .permission = LVM_READ,
- .pool_name = thinpool_lv->name,
- .pvh = &vg->pvs,
- .read_ahead = DM_READ_AHEAD_AUTO,
- .stripes = 1,
- .virtual_extents = lv->le_count,
- };
+ is_thinpool = lv_is_thin_pool(lv);
+ is_cachepool = lv_is_cache_pool(lv);
+ lvt_enum = get_lvt_enum(metadata_lv);
+ lvtype = get_lv_type(lvt_enum);
- if (lv == thinpool_lv) {
- log_error("Can't use same LV %s for thin pool and thin volume.",
- display_lvname(thinpool_lv));
+ if (lvt_enum != striped_LVT && lvt_enum != linear_LVT && lvt_enum != raid_LVT) {
+ log_error("LV %s with type %s cannot be used as a metadata LV.",
+ display_lvname(metadata_lv), lvtype ? lvtype->name : "unknown");
return 0;
}
- if ((origin_name = arg_str_value(cmd, originname_ARG, NULL)))
- if (!validate_restricted_lvname_param(cmd, &vg->name, &origin_name))
- return_0;
+ if (!lv_is_visible(metadata_lv)) {
+ log_error("Can't convert internal LV %s.",
+ display_lvname(metadata_lv));
+ return 0;
+ }
- /*
- * If NULL, an auto-generated 'lvol' name is used.
- * If set, the lv create code checks the name isn't used.
- */
- lvc.lv_name = origin_name;
+ if (lv_is_locked(metadata_lv)) {
+ log_error("Can't convert locked LV %s.",
+ display_lvname(metadata_lv));
+ return 0;
+ }
- if (is_lockd_type(vg->lock_type)) {
- /*
- * FIXME: external origins don't work in lockd VGs.
- * Prior to the lvconvert, there's a lock associated with
- * the uuid of the external origin LV. After the convert,
- * that uuid belongs to the new thin LV, and a new LV with
- * a new uuid exists as the non-thin, readonly external LV.
- * We'd need to remove the lock for the previous uuid
- * (the new thin LV will have no lock), and create a new
- * lock for the new LV uuid used by the external LV.
- */
- log_error("Can't use lock_type %s LV as external origin.",
- vg->lock_type);
+ if (lv_is_origin(metadata_lv) ||
+ lv_is_merging_origin(metadata_lv) ||
+ lv_is_external_origin(metadata_lv) ||
+ lv_is_virtual(metadata_lv)) {
+ log_error("Pool metadata LV %s is of an unsupported type.",
+ display_lvname(metadata_lv));
return 0;
}
- dm_list_init(&lvc.tags);
+ /* FIXME cache pool */
+ if (is_thinpool && pool_is_active(lv)) {
+ /* If any volume referencing pool active - abort here */
+ log_error("Cannot convert pool %s with active volumes.",
+ display_lvname(lv));
+ return 0;
+ }
- if (!pool_supports_external_origin(first_seg(thinpool_lv), lv))
- return_0;
+ if ((dm_snprintf(meta_name, sizeof(meta_name), "%s%s", lv->name, is_cachepool ? "_cmeta" : "_tmeta") < 0)) {
+ log_error("Failed to create internal lv names, pool name is too long.");
+ return 0;
+ }
- if (!(lvc.segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_THIN)))
- return_0;
+ seg = first_seg(lv);
- if (!archive(vg))
- return_0;
+ /* Normally do NOT change chunk size when swapping */
- /*
- * New thin LV needs to be created (all messages sent to pool) In this
- * case thin volume is created READ-ONLY and also warn about not
- * zeroing is suppressed.
- *
- * The new thin LV is created with the origin_name, or an autogenerated
- * 'lvol' name. Then the names and ids are swapped between the thin LV
- * and the original/external LV. So, the thin LV gets the name and id
- * of the original LV arg, and the original LV arg gets the origin_name
- * or the autogenerated name.
- */
+ if (arg_is_set(cmd, chunksize_ARG)) {
+ chunk_size = arg_uint_value(cmd, chunksize_ARG, 0);
- if (!(thin_lv = lv_create_single(vg, &lvc)))
- return_0;
+ if ((chunk_size != seg->chunk_size) && !dm_list_empty(&lv->segs_using_this_lv)) {
+ if (arg_count(cmd, force_ARG) == PROMPT) {
+ log_error("Chunk size can be only changed with --force. Conversion aborted.");
+ return 0;
+ }
- if (!deactivate_lv(cmd, thin_lv)) {
- log_error("Aborting. Unable to deactivate new LV. "
- "Manual intervention required.");
- return 0;
- }
+ if (!validate_pool_chunk_size(cmd, seg->segtype, chunk_size))
+ return_0;
- /*
- * Crashing till this point will leave plain thin volume
- * which could be easily removed by the user after i.e. power-off
- */
+ log_warn("WARNING: Changing chunk size %s to %s for %s pool volume.",
+ display_size(cmd, seg->chunk_size),
+ display_size(cmd, chunk_size),
+ display_lvname(lv));
- if (!swap_lv_identifiers(cmd, thin_lv, lv)) {
- stack;
- goto revert_new_lv;
- }
+ /* Ok, user has likely some serious reason for this */
+ if (!arg_count(cmd, yes_ARG) &&
+ yes_no_prompt("Do you really want to change chunk size for %s pool volume? [y/n]: ",
+ display_lvname(lv)) == 'n') {
+ log_error("Conversion aborted.");
+ return 0;
+ }
+ }
- /* Preserve read-write status of original LV here */
- thin_lv->status |= (lv->status & LVM_WRITE);
+ seg->chunk_size = chunk_size;
+ }
- if (!attach_thin_external_origin(first_seg(thin_lv), lv)) {
- stack;
- goto revert_new_lv;
+ if (!arg_count(cmd, yes_ARG) &&
+ yes_no_prompt("Do you want to swap metadata of %s pool with metadata volume %s? [y/n]: ",
+ display_lvname(lv),
+ display_lvname(metadata_lv)) == 'n') {
+ log_error("Conversion aborted.");
+ return 0;
}
- if (!lv_update_and_reload(thin_lv)) {
- stack;
- goto deactivate_and_revert_new_lv;
+ if (!deactivate_lv(cmd, metadata_lv)) {
+ log_error("Aborting. Failed to deactivate %s.",
+ display_lvname(metadata_lv));
+ return 0;
}
- log_print_unless_silent("Converted %s to thin volume with external origin %s.",
- display_lvname(thin_lv), display_lvname(lv));
+ if (!archive(vg))
+ return_0;
- return 1;
+ /* Swap names between old and new metadata LV */
-deactivate_and_revert_new_lv:
- if (!swap_lv_identifiers(cmd, thin_lv, lv))
- stack;
+ if (!detach_pool_metadata_lv(seg, &prev_metadata_lv))
+ return_0;
- if (!deactivate_lv(cmd, thin_lv)) {
- log_error("Unable to deactivate failed new LV. "
- "Manual intervention required.");
- return 0;
- }
+ swap_name = metadata_lv->name;
- if (!detach_thin_external_origin(first_seg(thin_lv)))
+ if (!lv_rename_update(cmd, metadata_lv, "pvmove_tmeta", 0))
return_0;
-revert_new_lv:
- /* FIXME Better to revert to backup of metadata? */
- if (!lv_remove(thin_lv) || !vg_write(vg) || !vg_commit(vg))
- log_error("Manual intervention may be required to remove "
- "abandoned LV(s) before retrying.");
- else
- backup(vg);
+ /* Give the previous metadata LV the name of the LV replacing it. */
- return 0;
-}
+ if (!lv_rename_update(cmd, prev_metadata_lv, swap_name, 0))
+ return_0;
-static int _lvconvert_update_pool_params(struct logical_volume *pool_lv,
- struct lvconvert_params *lp)
-{
- if (lp->pool_metadata_size &&
- !(lp->pool_metadata_extents =
- extents_from_size(pool_lv->vg->cmd, lp->pool_metadata_size, pool_lv->vg->extent_size)))
+ /* Rename deactivated metadata LV to have _tmeta suffix */
+
+ if (!lv_rename_update(cmd, metadata_lv, meta_name, 0))
+ return_0;
+
+ if (!attach_pool_metadata_lv(seg, metadata_lv))
+ return_0;
+
+ if (!vg_write(vg) || !vg_commit(vg))
return_0;
- return update_pool_params(lp->segtype,
- pool_lv->vg,
- lp->target_attr,
- lp->passed_args,
- pool_lv->le_count,
- &lp->pool_metadata_extents,
- &lp->thin_chunk_size_calc_policy,
- &lp->chunk_size,
- &lp->discards,
- &lp->zero);
+ backup(vg);
+ return 1;
}
/*
- * Converts a data lv and a metadata lv into a thin or cache pool lv.
- *
- * Thin lvconvert version which
- * rename metadata
- * convert/layers thinpool over data
- * attach metadata
- *
- * pool_lv might or might not already be a pool.
+ * Create a new pool LV, using the lv arg as the data sub LV.
+ * The metadata sub LV is either a new LV created here, or an
+ * existing LV specified by --poolmetadata.
*/
-static int _lvconvert_pool(struct cmd_context *cmd,
- struct logical_volume *pool_lv,
- struct lvconvert_params *lp)
+
+static int _lvconvert_to_pool(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ int to_thinpool,
+ int to_cachepool,
+ struct dm_list *use_pvh)
{
- int r = 0;
- const char *old_name;
+ struct volume_group *vg = lv->vg;
+ struct logical_volume *metadata_lv = NULL; /* existing or created */
+ struct logical_volume *data_lv; /* lv arg renamed */
+ struct logical_volume *pool_lv; /* new lv created here */
+ const char *pool_metadata_name; /* user-specified lv name */
+ const char *pool_name; /* name of original lv arg */
+ char meta_name[NAME_LEN]; /* generated sub lv name */
+ char data_name[NAME_LEN]; /* generated sub lv name */
+ struct segment_type *pool_segtype; /* thinpool or cachepool */
struct lv_segment *seg;
- struct volume_group *vg = pool_lv->vg;
- struct logical_volume *data_lv;
- struct logical_volume *metadata_lv = NULL;
- struct logical_volume *pool_metadata_lv;
+ unsigned int target_attr = ~0;
+ unsigned int passed_args = 0;
+ unsigned int activate_pool;
+ unsigned int zero_metadata;
+ uint64_t meta_size;
+ uint32_t meta_extents;
+ uint32_t chunk_size;
+ int chunk_calc;
+ int r = 0;
+
+ /* for handling lvmlockd cases */
char *lockd_data_args = NULL;
char *lockd_meta_args = NULL;
char *lockd_data_name = NULL;
char *lockd_meta_name = NULL;
struct id lockd_data_id;
struct id lockd_meta_id;
- char metadata_name[NAME_LEN], data_name[NAME_LEN];
- int zero_metadata = 1;
- int activate_pool;
-
- if (lp->pool_data_name) {
- if ((lp->thin || lp->cache) &&
- !strcmp(lp->pool_data_name, pool_lv->name)) {
- log_error("Converted volume %s and pool volume must differ.",
- display_lvname(pool_lv));
- return 0;
- }
- if (!(pool_lv = find_lv(vg, lp->pool_data_name))) {
- log_error("Unknown pool data LV %s.", lp->pool_data_name);
- return 0;
- }
- }
-
- /* An existing LV needs to have its lock freed once it becomes a data LV. */
- if (is_lockd_type(vg->lock_type) && !lv_is_pool(pool_lv) && pool_lv->lock_args) {
- lockd_data_args = dm_pool_strdup(cmd->mem, pool_lv->lock_args);
- lockd_data_name = dm_pool_strdup(cmd->mem, pool_lv->name);
- memcpy(&lockd_data_id, &pool_lv->lvid.id[1], sizeof(struct id));
- }
- if (!lv_is_visible(pool_lv)) {
- log_error("Can't convert internal LV %s.", display_lvname(pool_lv));
- return 0;
- }
- if (lv_is_locked(pool_lv)) {
- log_error("Can't convert locked LV %s.", display_lvname(pool_lv));
+ if (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) {
+ log_error(INTERNAL_ERROR "LV %s is already a pool.", display_lvname(lv));
return 0;
}
- if (lv_is_thin_pool(pool_lv) && (segtype_is_cache_pool(lp->segtype) || lp->cache)) {
- log_error("Can't convert thin pool LV %s.", display_lvname(pool_lv));
- return 0;
- }
+ pool_segtype = to_cachepool ? get_segtype_from_string(cmd, SEG_TYPE_NAME_CACHE_POOL) :
+ get_segtype_from_string(cmd, SEG_TYPE_NAME_THIN_POOL);
- if (lv_is_cache(pool_lv) && !segtype_is_thin_pool(lp->segtype)) {
- log_error("Cached LV %s could be only converted into a thin pool volume.",
- display_lvname(pool_lv));
+ if (!pool_segtype->ops->target_present(cmd, NULL, &target_attr)) {
+ log_error("%s: Required device-mapper target(s) not detected in your kernel.", pool_segtype->name);
return 0;
}
- if (lv_is_cache_pool(pool_lv) && (segtype_is_thin_pool(lp->segtype) || lp->thin)) {
- log_error("Cannot convert cache pool %s as pool data volume.",
- display_lvname(pool_lv));
- return 0;
- }
+ /* Allow to have only thinpool active and restore it's active state. */
+ activate_pool = to_thinpool && lv_is_active(lv);
- if (lv_is_mirror(pool_lv)) {
- log_error("Mirror logical volumes cannot be used as pools.");
- log_print_unless_silent("Try \"%s\" segment type instead.", SEG_TYPE_NAME_RAID1);
- return 0;
+ /* Wipe metadata_lv by default, but allow skipping this for cache pools. */
+ zero_metadata = to_cachepool ? arg_int_value(cmd, zero_ARG, 1) : 1;
+
+ /* An existing LV needs to have its lock freed once it becomes a data LV. */
+ if (is_lockd_type(vg->lock_type) && lv->lock_args) {
+ lockd_data_args = dm_pool_strdup(cmd->mem, lv->lock_args);
+ lockd_data_name = dm_pool_strdup(cmd->mem, lv->name);
+ memcpy(&lockd_data_id, &lv->lvid.id[1], sizeof(struct id));
}
/*
- * Only linear, striped and raid supported.
- * FIXME Tidy up all these type restrictions.
+ * If an existing LV is to be used as the metadata LV,
+ * verify that it's in a usable state. These checks are
+ * not done by command def rules because this LV is not
+ * processed by process_each_lv.
*/
- if (!lv_is_pool(pool_lv) &&
- (lv_is_thin_type(pool_lv) ||
- lv_is_cow(pool_lv) || lv_is_merging_cow(pool_lv) ||
- lv_is_origin(pool_lv) ||lv_is_merging_origin(pool_lv) ||
- lv_is_external_origin(pool_lv) ||
- lv_is_virtual(pool_lv))) {
- log_error("Pool data LV %s is of an unsupported type.", display_lvname(pool_lv));
- return 0;
- }
- if (lp->pool_metadata_name) {
- if (!(lp->pool_metadata_lv = find_lv(vg, lp->pool_metadata_name))) {
- log_error("Unknown pool metadata LV %s.", lp->pool_metadata_name);
+ if ((pool_metadata_name = arg_str_value(cmd, poolmetadata_ARG, NULL))) {
+ if (!(metadata_lv = find_lv(vg, pool_metadata_name))) {
+ log_error("Unknown pool metadata LV %s.", pool_metadata_name);
return 0;
}
- lp->pool_metadata_extents = lp->pool_metadata_lv->le_count;
- metadata_lv = lp->pool_metadata_lv;
/* An existing LV needs to have its lock freed once it becomes a meta LV. */
if (is_lockd_type(vg->lock_type) && metadata_lv->lock_args) {
@@ -2586,7 +2803,7 @@ static int _lvconvert_pool(struct cmd_context *cmd,
memcpy(&lockd_meta_id, &metadata_lv->lvid.id[1], sizeof(struct id));
}
- if (metadata_lv == pool_lv) {
+ if (metadata_lv == lv) {
log_error("Can't use same LV for pool data and metadata LV %s.",
display_lvname(metadata_lv));
return 0;
@@ -2621,199 +2838,152 @@ static int _lvconvert_pool(struct cmd_context *cmd,
display_lvname(metadata_lv));
return 0;
}
-
- if (!lv_is_pool(pool_lv)) {
- if (!_lvconvert_update_pool_params(pool_lv, lp))
- return_0;
-
- if (lp->pool_metadata_extents > metadata_lv->le_count) {
- log_error("Logical volume %s is too small for metadata.",
- display_lvname(metadata_lv));
- return 0;
- }
- }
}
- if (lv_is_pool(pool_lv)) {
- lp->pool_data_lv = pool_lv;
+ /*
+ * Determine the size of the metadata LV and the chunk size. When an
+ * existing LV is to be used for metadata, this introduces some
+ * constraints/defaults. When chunk_size=0 and/or meta_extents=0 are
+ * passed to the "update params" function, defaults are calculated and
+ * returned.
+ */
- if (!metadata_lv) {
- if (arg_from_list_is_set(cmd, "is invalid with existing pool",
- discards_ARG,
- poolmetadatasize_ARG, -1))
- return_0;
+ if (arg_is_set(cmd, chunksize_ARG)) {
+ passed_args |= PASS_ARG_CHUNK_SIZE;
+ chunk_size = arg_uint_value(cmd, chunksize_ARG, 0);
+ if (!validate_pool_chunk_size(cmd, pool_segtype, chunk_size))
+ return_0;
+ } else {
+ /* A default will be chosen by the "update" function. */
+ chunk_size = 0;
+ }
- if (lp->thin &&
- arg_from_list_is_set(cmd, "is invalid with existing thin pool",
- chunksize_ARG, zero_ARG, -1))
- return_0;
+ if (arg_is_set(cmd, poolmetadatasize_ARG)) {
+ meta_size = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0));
+ meta_extents = extents_from_size(cmd, meta_size, vg->extent_size);
+ passed_args |= PASS_ARG_POOL_METADATA_SIZE;
+ } else if (metadata_lv) {
+ meta_extents = metadata_lv->le_count;
+ passed_args |= PASS_ARG_POOL_METADATA_SIZE;
+ } else {
+ /* A default will be chosen by the "update" function. */
+ meta_extents = 0;
+ }
- if (lp->cache) {
- if (!lp->chunk_size)
- lp->chunk_size = first_seg(pool_lv)->chunk_size;
-
- if (!validate_lv_cache_chunk_size(pool_lv, lp->chunk_size))
- return_0;
-
- /* Check is user requested zeroing logic via [-Z y|n] */
- if (!arg_is_set(cmd, zero_ARG)) {
- /* Note: requires rather deep know-how to skip zeroing */
- if (!lp->yes &&
- yes_no_prompt("Do you want wipe existing metadata of "
- "cache pool volume %s? [y/n]: ",
- display_lvname(pool_lv)) == 'n') {
- log_error("Conversion aborted.");
- log_error("To preserve cache metadata add option \"--zero n\".");
- log_warn("WARNING: Reusing mismatched cache pool metadata "
- "MAY DESTROY YOUR DATA!");
- return 0;
- }
- /* Wiping confirmed, go ahead */
- if (!wipe_cache_pool(pool_lv))
- return_0;
- } else if (arg_int_value(cmd, zero_ARG, 0)) {
- if (!wipe_cache_pool(pool_lv)) /* Wipe according to -Z y|n */
- return_0;
- } else
- log_warn("WARNING: Reusing cache pool metadata %s "
- "for volume caching.", display_lvname(pool_lv));
- }
+ /* Tell the "update" function to ignore these, they are handled below. */
+ passed_args |= PASS_ARG_DISCARDS | PASS_ARG_ZERO;
- if (lp->thin || lp->cache)
- /* already pool, can continue converting volume */
- return 1;
+ /*
+ * Validate and/or choose defaults for meta_extents and chunk_size,
+ * this involves some complicated calculations.
+ */
- log_error("LV %s is already pool.", display_lvname(pool_lv));
- return 0;
- }
+ if (to_cachepool) {
+ if (!update_cache_pool_params(pool_segtype, vg, target_attr,
+ passed_args, lv->le_count,
+ &meta_extents,
+ &chunk_calc,
+ &chunk_size))
+ return_0;
+ } else {
+ if (!update_thin_pool_params(pool_segtype, vg, target_attr,
+ passed_args, lv->le_count,
+ &meta_extents,
+ &chunk_calc,
+ &chunk_size,
+ NULL, NULL))
+ return_0;
+ }
- if (lp->thin || lp->cache) {
- log_error("--%s and pool metadata swap is not supported.",
- lp->thin ? "thin" : "cache");
- return 0;
- }
+ if ((uint64_t)chunk_size > ((uint64_t)lv->le_count * vg->extent_size)) {
+ log_error("Pool data LV %s is too small (%s) for specified chunk size (%s).",
+ display_lvname(lv),
+ display_size(cmd, (uint64_t)lv->le_count * vg->extent_size),
+ display_size(cmd, chunk_size));
+ return 0;
+ }
- /* FIXME cache pool */
- if (lv_is_thin_pool(pool_lv) && pool_is_active(pool_lv)) {
- /* If any volume referencing pool active - abort here */
- log_error("Cannot convert pool %s with active volumes.",
- display_lvname(pool_lv));
- return 0;
- }
+ if (metadata_lv && (meta_extents > metadata_lv->le_count)) {
+ log_error("Pool metadata LV %s is too small (%u extents) for required metadata (%u extents).",
+ display_lvname(metadata_lv), metadata_lv->le_count, meta_extents);
+ return 0;
+ }
- lp->passed_args |= PASS_ARG_CHUNK_SIZE | PASS_ARG_DISCARDS | PASS_ARG_ZERO;
- seg = first_seg(pool_lv);
+ log_verbose("Pool metadata extents %u chunk_size %u", meta_extents, chunk_size);
- /* Normally do NOT change chunk size when swapping */
- if (arg_is_set(cmd, chunksize_ARG) &&
- (lp->chunk_size != seg->chunk_size) &&
- !dm_list_empty(&pool_lv->segs_using_this_lv)) {
- if (lp->force == PROMPT) {
- log_error("Chunk size can be only changed with --force. Conversion aborted.");
- return 0;
- }
- log_warn("WARNING: Changing chunk size %s to "
- "%s for %s pool volume.",
- display_size(cmd, seg->chunk_size),
- display_size(cmd, lp->chunk_size),
- display_lvname(pool_lv));
- /* Ok, user has likely some serious reason for this */
- if (!lp->yes &&
- yes_no_prompt("Do you really want to change chunk size "
- "for %s pool volume? [y/n]: ",
- display_lvname(pool_lv)) == 'n') {
- log_error("Conversion aborted.");
- return 0;
- }
- } else
- lp->chunk_size = seg->chunk_size;
- if (!_lvconvert_update_pool_params(pool_lv, lp))
- return_0;
+ /*
+ * Verify that user wants to use these LVs.
+ */
- if (metadata_lv->le_count < lp->pool_metadata_extents)
- log_print_unless_silent("Continuing with swap...");
+ log_warn("WARNING: Converting logical volume %s%s%s to %s pool's data%s %s metadata wiping.",
+ display_lvname(lv),
+ metadata_lv ? " and " : "",
+ metadata_lv ? display_lvname(metadata_lv) : "",
+ to_cachepool ? "cache" : "thin",
+ metadata_lv ? " and metadata volumes" : " volume",
+ zero_metadata ? "with" : "WITHOUT");
- if (!arg_is_set(cmd, discards_ARG))
- lp->discards = seg->discards;
- if (!arg_is_set(cmd, zero_ARG))
- lp->zero = seg->zero_new_blocks;
+ if (zero_metadata)
+ log_warn("THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)");
+ else if (to_cachepool)
+ log_warn("WARNING: Using mismatched cache pool metadata MAY DESTROY YOUR DATA!");
- if (!lp->yes &&
- yes_no_prompt("Do you want to swap metadata of %s "
- "pool with metadata volume %s? [y/n]: ",
- display_lvname(pool_lv),
- display_lvname(metadata_lv)) == 'n') {
- log_error("Conversion aborted.");
- return 0;
- }
- } else {
- /* Only cache pool conversion may suppress metadata zeroing
- * TODO: Maybe similar support could be useful for thin-pool, but --zero
- * is already overloade and we would also need to possibly match transaction Id. */
- if (segtype_is_cache_pool(lp->segtype) && metadata_lv)
- /* Check is user requested zeroing logic via [-Z y|n] (default is yes) */
- zero_metadata = arg_int_value(cmd, zero_ARG, 1);
-
- log_warn("WARNING: Converting logical volume %s%s%s to %s pool's data%s %s metadata wiping.",
- display_lvname(pool_lv),
- metadata_lv ? " and " : "",
- metadata_lv ? display_lvname(metadata_lv) : "",
- segtype_is_cache_pool(lp->segtype) ? "cache" : "thin",
- metadata_lv ? " and metadata volumes" : " volume",
- zero_metadata ? "with" : "WITHOUT");
-
- if (zero_metadata)
- log_warn("THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)");
- else /* ATM supported only for cache pools */
- log_warn("WARNING: Using mismatched cache pool metadata "
- "MAY DESTROY YOUR DATA!");
-
- if (!lp->yes &&
- yes_no_prompt("Do you really want to convert %s%s%s? [y/n]: ",
- display_lvname(pool_lv),
- metadata_lv ? " and " : "",
- metadata_lv ? display_lvname(metadata_lv) : "") == 'n') {
- log_error("Conversion aborted.");
- return 0;
- }
+ if (!arg_count(cmd, yes_ARG) &&
+ yes_no_prompt("Do you really want to convert %s%s%s? [y/n]: ",
+ display_lvname(lv),
+ metadata_lv ? " and " : "",
+ metadata_lv ? display_lvname(metadata_lv) : "") == 'n') {
+ log_error("Conversion aborted.");
+ return 0;
}
- if (segtype_is_cache_pool(lp->segtype))
- activate_pool = 0; /* Cannot activate cache pool */
- else
- /* Allow to have only thinpool active and restore it's active state */
- activate_pool = lv_is_active(pool_lv);
-
- if ((dm_snprintf(metadata_name, sizeof(metadata_name), "%s%s",
- pool_lv->name,
- (segtype_is_cache_pool(lp->segtype)) ?
- "_cmeta" : "_tmeta") < 0) ||
- (dm_snprintf(data_name, sizeof(data_name), "%s%s",
- pool_lv->name,
- (segtype_is_cache_pool(lp->segtype)) ?
- "_cdata" : "_tdata") < 0)) {
- log_error("Failed to create internal lv names, "
- "pool name is too long.");
+ /*
+ * The internal LV names for pool data/meta LVs.
+ */
+
+ if ((dm_snprintf(meta_name, sizeof(meta_name), "%s%s", lv->name, to_cachepool ? "_cmeta" : "_tmeta") < 0) ||
+ (dm_snprintf(data_name, sizeof(data_name), "%s%s", lv->name, to_cachepool ? "_cdata" : "_tdata") < 0)) {
+ log_error("Failed to create internal lv names, pool name is too long.");
return 0;
}
+ /*
+ * If a new metadata LV needs to be created, collect the settings for
+ * the new LV and create it.
+ *
+ * If an existing LV is used for metadata, deactivate/activate/wipe it.
+ */
+
if (!metadata_lv) {
- if (!_lvconvert_update_pool_params(pool_lv, lp))
- return_0;
+ uint32_t meta_stripes;
+ uint32_t meta_stripe_size;
+ uint32_t meta_readahead;
+ alloc_policy_t meta_alloc;
+ unsigned meta_stripes_supplied;
+ unsigned meta_stripe_size_supplied;
if (!get_stripe_params(cmd, get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED),
- &lp->stripes, &lp->stripe_size, &lp->stripes_supplied, &lp->stripe_size_supplied))
+ &meta_stripes,
+ &meta_stripe_size,
+ &meta_stripes_supplied,
+ &meta_stripe_size_supplied))
return_0;
+ meta_readahead = arg_uint_value(cmd, readahead_ARG, cmd->default_settings.read_ahead);
+ meta_alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
+
if (!archive(vg))
return_0;
- if (!(metadata_lv = alloc_pool_metadata(pool_lv, metadata_name,
- lp->read_ahead, lp->stripes,
- lp->stripe_size,
- lp->pool_metadata_extents,
- lp->alloc, lp->pvh)))
+ if (!(metadata_lv = alloc_pool_metadata(lv,
+ meta_name,
+ meta_readahead,
+ meta_stripes,
+ meta_stripe_size,
+ meta_extents,
+ meta_alloc,
+ use_pvh)))
return_0;
} else {
if (!deactivate_lv(cmd, metadata_lv)) {
@@ -2825,21 +2995,6 @@ static int _lvconvert_pool(struct cmd_context *cmd,
if (!archive(vg))
return_0;
- /* Swap normal LV with pool's metadata LV ? */
- if (lv_is_pool(pool_lv)) {
- /* Swap names between old and new metadata LV */
- seg = first_seg(pool_lv);
- if (!detach_pool_metadata_lv(seg, &pool_metadata_lv))
- return_0;
- old_name = metadata_lv->name;
- if (!lv_rename_update(cmd, metadata_lv, "pvmove_tmeta", 0))
- return_0;
- if (!lv_rename_update(cmd, pool_metadata_lv, old_name, 0))
- return_0;
-
- goto mda_write;
- }
-
if (zero_metadata) {
metadata_lv->status |= LV_TEMPORARY;
if (!activate_lv_local(cmd, metadata_lv)) {
@@ -2854,41 +3009,66 @@ static int _lvconvert_pool(struct cmd_context *cmd,
}
}
- /* We are changing target type, so deactivate first */
+ /*
+ * Deactivate the data LV and metadata LV.
+ * We are changing target type, so deactivate first.
+ */
+
if (!deactivate_lv(cmd, metadata_lv)) {
log_error("Aborting. Failed to deactivate metadata lv. "
"Manual intervention required.");
return 0;
}
- if (!deactivate_lv(cmd, pool_lv)) {
+ if (!deactivate_lv(cmd, lv)) {
log_error("Aborting. Failed to deactivate logical volume %s.",
- display_lvname(pool_lv));
+ display_lvname(lv));
return 0;
}
- data_lv = pool_lv;
- old_name = data_lv->name; /* Use for pool name */
/*
+ * When the LV referenced by the original function arg "lv"
+ * is renamed, it is then referenced as "data_lv".
+ *
+ * pool_name pool name taken from lv arg
+ * data_name sub lv name, generated
+ * meta_name sub lv name, generated
+ *
+ * pool_lv new lv for pool object, created here
+ * data_lv sub lv, was lv arg, now renamed
+ * metadata_lv sub lv, existing or created here
+ */
+
+ data_lv = lv;
+ pool_name = lv->name; /* Use original LV name for pool name */
+
+ /*
+ * Rename the original LV arg to the internal data LV naming scheme.
+ *
* Since we wish to have underlaying devs to match _[ct]data
* rename data LV to match pool LV subtree first,
* also checks for visible LV.
+ *
+ * FIXME: any more types prohibited here?
*/
- /* FIXME: any more types prohibited here? */
+
if (!lv_rename_update(cmd, data_lv, data_name, 0))
return_0;
- if (!(pool_lv = lv_create_empty(old_name, NULL,
- ((segtype_is_cache_pool(lp->segtype)) ?
- CACHE_POOL : THIN_POOL) |
- VISIBLE_LV | LVM_READ | LVM_WRITE,
+ /*
+ * Create LV structures for the new pool LV object,
+ * and connect it to the data/meta LVs.
+ */
+
+ if (!(pool_lv = lv_create_empty(pool_name, NULL,
+ (to_cachepool ? CACHE_POOL : THIN_POOL) | VISIBLE_LV | LVM_READ | LVM_WRITE,
ALLOC_INHERIT, vg))) {
log_error("Creation of pool LV failed.");
return 0;
}
/* Allocate a new pool segment */
- if (!(seg = alloc_lv_segment(lp->segtype, pool_lv, 0, data_lv->le_count,
+ if (!(seg = alloc_lv_segment(pool_segtype, pool_lv, 0, data_lv->le_count,
pool_lv->status, 0, NULL, 1,
data_lv->le_count, 0, 0, 0, NULL)))
return_0;
@@ -2907,7 +3087,7 @@ static int _lvconvert_pool(struct cmd_context *cmd,
* data and meta LVs (they are unlocked and deleted below.)
*/
if (is_lockd_type(vg->lock_type)) {
- if (segtype_is_cache_pool(lp->segtype)) {
+ if (to_cachepool) {
data_lv->lock_args = NULL;
metadata_lv->lock_args = NULL;
} else {
@@ -2919,1763 +3099,182 @@ static int _lvconvert_pool(struct cmd_context *cmd,
else if (!strcmp(vg->lock_type, "dlm"))
pool_lv->lock_args = "dlm";
/* The lock_args will be set in vg_write(). */
- }
- }
-
- /* FIXME: revert renamed LVs in fail path? */
- /* FIXME: any common code with metadata/thin_manip.c extend_pool() ? */
-
- seg->transaction_id = 0;
-
-mda_write:
- seg->chunk_size = lp->chunk_size;
- seg->discards = lp->discards;
- seg->zero_new_blocks = lp->zero ? 1 : 0;
-
- if (lp->cache_mode &&
- !cache_set_cache_mode(seg, lp->cache_mode))
- return_0;
-
- if ((lp->policy_name || lp->policy_settings) &&
- !cache_set_policy(seg, lp->policy_name, lp->policy_settings))
- return_0;
-
- /* Rename deactivated metadata LV to have _tmeta suffix */
- /* Implicit checks if metadata_lv is visible */
- if (lp->pool_metadata_name &&
- !lv_rename_update(cmd, metadata_lv, metadata_name, 0))
- return_0;
-
- if (!attach_pool_metadata_lv(seg, metadata_lv))
- return_0;
-
- if (!handle_pool_metadata_spare(vg, metadata_lv->le_count,
- lp->pvh, lp->poolmetadataspare))
- return_0;
-
- if (!vg_write(vg) || !vg_commit(vg))
- return_0;
-
- if (seg->zero_new_blocks &&
- seg->chunk_size >= DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE * 2)
- log_warn("WARNING: Pool zeroing and large %s chunk size slows down "
- "provisioning.", display_size(cmd, seg->chunk_size));
-
- if (activate_pool && !lockd_lv(cmd, pool_lv, "ex", LDLV_PERSISTENT)) {
- log_error("Failed to lock pool LV %s.", display_lvname(pool_lv));
- goto out;
- }
-
- if (activate_pool &&
- !activate_lv_excl(cmd, pool_lv)) {
- log_error("Failed to activate pool logical volume %s.",
- display_lvname(pool_lv));
- /* Deactivate subvolumes */
- if (!deactivate_lv(cmd, seg_lv(seg, 0)))
- log_error("Failed to deactivate pool data logical volume %s.",
- display_lvname(seg_lv(seg, 0)));
- if (!deactivate_lv(cmd, seg->metadata_lv))
- log_error("Failed to deactivate pool metadata logical volume %s.",
- display_lvname(seg->metadata_lv));
- goto out;
- }
-
- r = 1;
- lp->pool_data_lv = pool_lv;
-
-out:
- backup(vg);
-
- if (r)
- log_print_unless_silent("Converted %s to %s pool.",
- display_lvname(pool_lv),
- (segtype_is_cache_pool(lp->segtype)) ?
- "cache" : "thin");
-
- /*
- * Unlock and free the locks from existing LVs that became pool data
- * and meta LVs.
- */
- if (lockd_data_name) {
- if (!lockd_lv_name(cmd, vg, lockd_data_name, &lockd_data_id, lockd_data_args, "un", LDLV_PERSISTENT))
- log_error("Failed to unlock pool data LV %s/%s", vg->name, lockd_data_name);
- lockd_free_lv(cmd, vg, lockd_data_name, &lockd_data_id, lockd_data_args);
- }
-
- if (lockd_meta_name) {
- if (!lockd_lv_name(cmd, vg, lockd_meta_name, &lockd_meta_id, lockd_meta_args, "un", LDLV_PERSISTENT))
- log_error("Failed to unlock pool metadata LV %s/%s", vg->name, lockd_meta_name);
- lockd_free_lv(cmd, vg, lockd_meta_name, &lockd_meta_id, lockd_meta_args);
- }
-
- return r;
-#if 0
-revert_new_lv:
- /* TBD */
- if (!lp->pool_metadata_lv_name) {
- if (!deactivate_lv(cmd, metadata_lv)) {
- log_error("Failed to deactivate metadata lv.");
- return 0;
- }
- if (!lv_remove(metadata_lv) || !vg_write(vg) || !vg_commit(vg))
- log_error("Manual intervention may be required to remove "
- "abandoned LV(s) before retrying.");
- else
- backup(vg);
- }
-
- return 0;
-#endif
-}
-
-static int _lvconvert_swap_pool_metadata(struct cmd_context *cmd,
- struct logical_volume *lv,
- struct logical_volume *metadata_lv)
-{
- struct volume_group *vg = lv->vg;
- struct logical_volume *prev_metadata_lv;
- struct lv_segment *seg;
- struct lv_types *lvtype;
- char meta_name[NAME_LEN];
- const char *swap_name;
- uint32_t chunk_size;
- int is_thinpool;
- int is_cachepool;
- int lvt_enum;
-
- is_thinpool = lv_is_thin_pool(lv);
- is_cachepool = lv_is_cache_pool(lv);
- lvt_enum = get_lvt_enum(metadata_lv);
- lvtype = get_lv_type(lvt_enum);
-
- if (lvt_enum != striped_LVT && lvt_enum != linear_LVT && lvt_enum != raid_LVT) {
- log_error("LV %s with type %s cannot be used as a metadata LV.",
- display_lvname(metadata_lv), lvtype ? lvtype->name : "unknown");
- return 0;
- }
-
- if (!lv_is_visible(metadata_lv)) {
- log_error("Can't convert internal LV %s.",
- display_lvname(metadata_lv));
- return 0;
- }
-
- if (lv_is_locked(metadata_lv)) {
- log_error("Can't convert locked LV %s.",
- display_lvname(metadata_lv));
- return 0;
- }
-
- if (lv_is_origin(metadata_lv) ||
- lv_is_merging_origin(metadata_lv) ||
- lv_is_external_origin(metadata_lv) ||
- lv_is_virtual(metadata_lv)) {
- log_error("Pool metadata LV %s is of an unsupported type.",
- display_lvname(metadata_lv));
- return 0;
- }
-
- /* FIXME cache pool */
- if (is_thinpool && pool_is_active(lv)) {
- /* If any volume referencing pool active - abort here */
- log_error("Cannot convert pool %s with active volumes.",
- display_lvname(lv));
- return 0;
- }
-
- if ((dm_snprintf(meta_name, sizeof(meta_name), "%s%s", lv->name, is_cachepool ? "_cmeta" : "_tmeta") < 0)) {
- log_error("Failed to create internal lv names, pool name is too long.");
- return 0;
- }
-
- seg = first_seg(lv);
-
- /* Normally do NOT change chunk size when swapping */
-
- if (arg_is_set(cmd, chunksize_ARG)) {
- chunk_size = arg_uint_value(cmd, chunksize_ARG, 0);
-
- if ((chunk_size != seg->chunk_size) && !dm_list_empty(&lv->segs_using_this_lv)) {
- if (arg_count(cmd, force_ARG) == PROMPT) {
- log_error("Chunk size can be only changed with --force. Conversion aborted.");
- return 0;
- }
-
- if (!validate_pool_chunk_size(cmd, seg->segtype, chunk_size))
- return_0;
-
- log_warn("WARNING: Changing chunk size %s to %s for %s pool volume.",
- display_size(cmd, seg->chunk_size),
- display_size(cmd, chunk_size),
- display_lvname(lv));
-
- /* Ok, user has likely some serious reason for this */
- if (!arg_count(cmd, yes_ARG) &&
- yes_no_prompt("Do you really want to change chunk size for %s pool volume? [y/n]: ",
- display_lvname(lv)) == 'n') {
- log_error("Conversion aborted.");
- return 0;
- }
- }
-
- seg->chunk_size = chunk_size;
- }
-
- if (!arg_count(cmd, yes_ARG) &&
- yes_no_prompt("Do you want to swap metadata of %s pool with metadata volume %s? [y/n]: ",
- display_lvname(lv),
- display_lvname(metadata_lv)) == 'n') {
- log_error("Conversion aborted.");
- return 0;
- }
-
- if (!deactivate_lv(cmd, metadata_lv)) {
- log_error("Aborting. Failed to deactivate %s.",
- display_lvname(metadata_lv));
- return 0;
- }
-
- if (!archive(vg))
- return_0;
-
- /* Swap names between old and new metadata LV */
-
- if (!detach_pool_metadata_lv(seg, &prev_metadata_lv))
- return_0;
-
- swap_name = metadata_lv->name;
-
- if (!lv_rename_update(cmd, metadata_lv, "pvmove_tmeta", 0))
- return_0;
-
- /* Give the previous metadata LV the name of the LV replacing it. */
-
- if (!lv_rename_update(cmd, prev_metadata_lv, swap_name, 0))
- return_0;
-
- /* Rename deactivated metadata LV to have _tmeta suffix */
-
- if (!lv_rename_update(cmd, metadata_lv, meta_name, 0))
- return_0;
-
- if (!attach_pool_metadata_lv(seg, metadata_lv))
- return_0;
-
- if (!vg_write(vg) || !vg_commit(vg))
- return_0;
-
- backup(vg);
- return 1;
-}
-
-/*
- * Create a new pool LV, using the lv arg as the data sub LV.
- * The metadata sub LV is either a new LV created here, or an
- * existing LV specified by --poolmetadata.
- */
-
-static int _lvconvert_to_pool(struct cmd_context *cmd,
- struct logical_volume *lv,
- int to_thinpool,
- int to_cachepool,
- struct dm_list *use_pvh)
-{
- struct volume_group *vg = lv->vg;
- struct logical_volume *metadata_lv = NULL; /* existing or created */
- struct logical_volume *data_lv; /* lv arg renamed */
- struct logical_volume *pool_lv; /* new lv created here */
- const char *pool_metadata_name; /* user-specified lv name */
- const char *pool_name; /* name of original lv arg */
- char meta_name[NAME_LEN]; /* generated sub lv name */
- char data_name[NAME_LEN]; /* generated sub lv name */
- struct segment_type *pool_segtype; /* thinpool or cachepool */
- struct lv_segment *seg;
- unsigned int target_attr = ~0;
- unsigned int passed_args = 0;
- unsigned int activate_pool;
- unsigned int zero_metadata;
- uint64_t meta_size;
- uint32_t meta_extents;
- uint32_t chunk_size;
- int chunk_calc;
- int r = 0;
-
- /* for handling lvmlockd cases */
- char *lockd_data_args = NULL;
- char *lockd_meta_args = NULL;
- char *lockd_data_name = NULL;
- char *lockd_meta_name = NULL;
- struct id lockd_data_id;
- struct id lockd_meta_id;
-
-
- if (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) {
- log_error(INTERNAL_ERROR "LV %s is already a pool.", display_lvname(lv));
- return 0;
- }
-
- pool_segtype = to_cachepool ? get_segtype_from_string(cmd, SEG_TYPE_NAME_CACHE_POOL) :
- get_segtype_from_string(cmd, SEG_TYPE_NAME_THIN_POOL);
-
- if (!pool_segtype->ops->target_present(cmd, NULL, &target_attr)) {
- log_error("%s: Required device-mapper target(s) not detected in your kernel.", pool_segtype->name);
- return 0;
- }
-
- /* Allow to have only thinpool active and restore it's active state. */
- activate_pool = to_thinpool && lv_is_active(lv);
-
- /* Wipe metadata_lv by default, but allow skipping this for cache pools. */
- zero_metadata = to_cachepool ? arg_int_value(cmd, zero_ARG, 1) : 1;
-
- /* An existing LV needs to have its lock freed once it becomes a data LV. */
- if (is_lockd_type(vg->lock_type) && lv->lock_args) {
- lockd_data_args = dm_pool_strdup(cmd->mem, lv->lock_args);
- lockd_data_name = dm_pool_strdup(cmd->mem, lv->name);
- memcpy(&lockd_data_id, &lv->lvid.id[1], sizeof(struct id));
- }
-
- /*
- * If an existing LV is to be used as the metadata LV,
- * verify that it's in a usable state. These checks are
- * not done by command def rules because this LV is not
- * processed by process_each_lv.
- */
-
- if ((pool_metadata_name = arg_str_value(cmd, poolmetadata_ARG, NULL))) {
- if (!(metadata_lv = find_lv(vg, pool_metadata_name))) {
- log_error("Unknown pool metadata LV %s.", pool_metadata_name);
- return 0;
- }
-
- /* An existing LV needs to have its lock freed once it becomes a meta LV. */
- if (is_lockd_type(vg->lock_type) && metadata_lv->lock_args) {
- lockd_meta_args = dm_pool_strdup(cmd->mem, metadata_lv->lock_args);
- lockd_meta_name = dm_pool_strdup(cmd->mem, metadata_lv->name);
- memcpy(&lockd_meta_id, &metadata_lv->lvid.id[1], sizeof(struct id));
- }
-
- if (metadata_lv == lv) {
- log_error("Can't use same LV for pool data and metadata LV %s.",
- display_lvname(metadata_lv));
- return 0;
- }
-
- if (!lv_is_visible(metadata_lv)) {
- log_error("Can't convert internal LV %s.",
- display_lvname(metadata_lv));
- return 0;
- }
-
- if (lv_is_locked(metadata_lv)) {
- log_error("Can't convert locked LV %s.",
- display_lvname(metadata_lv));
- return 0;
- }
-
- if (lv_is_mirror(metadata_lv)) {
- log_error("Mirror logical volumes cannot be used for pool metadata.");
- log_print_unless_silent("Try \"%s\" segment type instead.", SEG_TYPE_NAME_RAID1);
- return 0;
- }
-
- /* FIXME Tidy up all these type restrictions. */
- if (lv_is_cache_type(metadata_lv) ||
- lv_is_thin_type(metadata_lv) ||
- lv_is_cow(metadata_lv) || lv_is_merging_cow(metadata_lv) ||
- lv_is_origin(metadata_lv) || lv_is_merging_origin(metadata_lv) ||
- lv_is_external_origin(metadata_lv) ||
- lv_is_virtual(metadata_lv)) {
- log_error("Pool metadata LV %s is of an unsupported type.",
- display_lvname(metadata_lv));
- return 0;
- }
- }
-
- /*
- * Determine the size of the metadata LV and the chunk size. When an
- * existing LV is to be used for metadata, this introduces some
- * constraints/defaults. When chunk_size=0 and/or meta_extents=0 are
- * passed to the "update params" function, defaults are calculated and
- * returned.
- */
-
- if (arg_is_set(cmd, chunksize_ARG)) {
- passed_args |= PASS_ARG_CHUNK_SIZE;
- chunk_size = arg_uint_value(cmd, chunksize_ARG, 0);
- if (!validate_pool_chunk_size(cmd, pool_segtype, chunk_size))
- return_0;
- } else {
- /* A default will be chosen by the "update" function. */
- chunk_size = 0;
- }
-
- if (arg_is_set(cmd, poolmetadatasize_ARG)) {
- meta_size = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0));
- meta_extents = extents_from_size(cmd, meta_size, vg->extent_size);
- passed_args |= PASS_ARG_POOL_METADATA_SIZE;
- } else if (metadata_lv) {
- meta_extents = metadata_lv->le_count;
- passed_args |= PASS_ARG_POOL_METADATA_SIZE;
- } else {
- /* A default will be chosen by the "update" function. */
- meta_extents = 0;
- }
-
- /* Tell the "update" function to ignore these, they are handled below. */
- passed_args |= PASS_ARG_DISCARDS | PASS_ARG_ZERO;
-
- /*
- * Validate and/or choose defaults for meta_extents and chunk_size,
- * this involves some complicated calculations.
- */
-
- if (to_cachepool) {
- if (!update_cache_pool_params(pool_segtype, vg, target_attr,
- passed_args, lv->le_count,
- &meta_extents,
- &chunk_calc,
- &chunk_size))
- return_0;
- } else {
- if (!update_thin_pool_params(pool_segtype, vg, target_attr,
- passed_args, lv->le_count,
- &meta_extents,
- &chunk_calc,
- &chunk_size,
- NULL, NULL))
- return_0;
- }
-
- if ((uint64_t)chunk_size > ((uint64_t)lv->le_count * vg->extent_size)) {
- log_error("Pool data LV %s is too small (%s) for specified chunk size (%s).",
- display_lvname(lv),
- display_size(cmd, (uint64_t)lv->le_count * vg->extent_size),
- display_size(cmd, chunk_size));
- return 0;
- }
-
- if (metadata_lv && (meta_extents > metadata_lv->le_count)) {
- log_error("Pool metadata LV %s is too small (%u extents) for required metadata (%u extents).",
- display_lvname(metadata_lv), metadata_lv->le_count, meta_extents);
- return 0;
- }
-
- log_verbose("Pool metadata extents %u chunk_size %u", meta_extents, chunk_size);
-
-
- /*
- * Verify that user wants to use these LVs.
- */
-
- log_warn("WARNING: Converting logical volume %s%s%s to %s pool's data%s %s metadata wiping.",
- display_lvname(lv),
- metadata_lv ? " and " : "",
- metadata_lv ? display_lvname(metadata_lv) : "",
- to_cachepool ? "cache" : "thin",
- metadata_lv ? " and metadata volumes" : " volume",
- zero_metadata ? "with" : "WITHOUT");
-
- if (zero_metadata)
- log_warn("THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)");
- else if (to_cachepool)
- log_warn("WARNING: Using mismatched cache pool metadata MAY DESTROY YOUR DATA!");
-
- if (!arg_count(cmd, yes_ARG) &&
- yes_no_prompt("Do you really want to convert %s%s%s? [y/n]: ",
- display_lvname(lv),
- metadata_lv ? " and " : "",
- metadata_lv ? display_lvname(metadata_lv) : "") == 'n') {
- log_error("Conversion aborted.");
- return 0;
- }
-
- /*
- * The internal LV names for pool data/meta LVs.
- */
-
- if ((dm_snprintf(meta_name, sizeof(meta_name), "%s%s", lv->name, to_cachepool ? "_cmeta" : "_tmeta") < 0) ||
- (dm_snprintf(data_name, sizeof(data_name), "%s%s", lv->name, to_cachepool ? "_cdata" : "_tdata") < 0)) {
- log_error("Failed to create internal lv names, pool name is too long.");
- return 0;
- }
-
- /*
- * If a new metadata LV needs to be created, collect the settings for
- * the new LV and create it.
- *
- * If an existing LV is used for metadata, deactivate/activate/wipe it.
- */
-
- if (!metadata_lv) {
- uint32_t meta_stripes;
- uint32_t meta_stripe_size;
- uint32_t meta_readahead;
- alloc_policy_t meta_alloc;
- unsigned meta_stripes_supplied;
- unsigned meta_stripe_size_supplied;
-
- if (!get_stripe_params(cmd, get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED),
- &meta_stripes,
- &meta_stripe_size,
- &meta_stripes_supplied,
- &meta_stripe_size_supplied))
- return_0;
-
- meta_readahead = arg_uint_value(cmd, readahead_ARG, cmd->default_settings.read_ahead);
- meta_alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
-
- if (!archive(vg))
- return_0;
-
- if (!(metadata_lv = alloc_pool_metadata(lv,
- meta_name,
- meta_readahead,
- meta_stripes,
- meta_stripe_size,
- meta_extents,
- meta_alloc,
- use_pvh)))
- return_0;
- } else {
- if (!deactivate_lv(cmd, metadata_lv)) {
- log_error("Aborting. Failed to deactivate %s.",
- display_lvname(metadata_lv));
- return 0;
- }
-
- if (!archive(vg))
- return_0;
-
- if (zero_metadata) {
- metadata_lv->status |= LV_TEMPORARY;
- if (!activate_lv_local(cmd, metadata_lv)) {
- log_error("Aborting. Failed to activate metadata lv.");
- return 0;
- }
-
- if (!wipe_lv(metadata_lv, (struct wipe_params) { .do_zero = 1 })) {
- log_error("Aborting. Failed to wipe metadata lv.");
- return 0;
- }
- }
- }
-
- /*
- * Deactivate the data LV and metadata LV.
- * We are changing target type, so deactivate first.
- */
-
- if (!deactivate_lv(cmd, metadata_lv)) {
- log_error("Aborting. Failed to deactivate metadata lv. "
- "Manual intervention required.");
- return 0;
- }
-
- if (!deactivate_lv(cmd, lv)) {
- log_error("Aborting. Failed to deactivate logical volume %s.",
- display_lvname(lv));
- return 0;
- }
-
- /*
- * When the LV referenced by the original function arg "lv"
- * is renamed, it is then referenced as "data_lv".
- *
- * pool_name pool name taken from lv arg
- * data_name sub lv name, generated
- * meta_name sub lv name, generated
- *
- * pool_lv new lv for pool object, created here
- * data_lv sub lv, was lv arg, now renamed
- * metadata_lv sub lv, existing or created here
- */
-
- data_lv = lv;
- pool_name = lv->name; /* Use original LV name for pool name */
-
- /*
- * Rename the original LV arg to the internal data LV naming scheme.
- *
- * Since we wish to have underlaying devs to match _[ct]data
- * rename data LV to match pool LV subtree first,
- * also checks for visible LV.
- *
- * FIXME: any more types prohibited here?
- */
-
- if (!lv_rename_update(cmd, data_lv, data_name, 0))
- return_0;
-
- /*
- * Create LV structures for the new pool LV object,
- * and connect it to the data/meta LVs.
- */
-
- if (!(pool_lv = lv_create_empty(pool_name, NULL,
- (to_cachepool ? CACHE_POOL : THIN_POOL) | VISIBLE_LV | LVM_READ | LVM_WRITE,
- ALLOC_INHERIT, vg))) {
- log_error("Creation of pool LV failed.");
- return 0;
- }
-
- /* Allocate a new pool segment */
- if (!(seg = alloc_lv_segment(pool_segtype, pool_lv, 0, data_lv->le_count,
- pool_lv->status, 0, NULL, 1,
- data_lv->le_count, 0, 0, 0, NULL)))
- return_0;
-
- /* Add the new segment to the layer LV */
- dm_list_add(&pool_lv->segments, &seg->list);
- pool_lv->le_count = data_lv->le_count;
- pool_lv->size = data_lv->size;
-
- if (!attach_pool_data_lv(seg, data_lv))
- return_0;
-
- /*
- * Create a new lock for a thin pool LV. A cache pool LV has no lock.
- * Locks are removed from existing LVs that are being converted to
- * data and meta LVs (they are unlocked and deleted below.)
- */
- if (is_lockd_type(vg->lock_type)) {
- if (to_cachepool) {
- data_lv->lock_args = NULL;
- metadata_lv->lock_args = NULL;
- } else {
- data_lv->lock_args = NULL;
- metadata_lv->lock_args = NULL;
-
- if (!strcmp(vg->lock_type, "sanlock"))
- pool_lv->lock_args = "pending";
- else if (!strcmp(vg->lock_type, "dlm"))
- pool_lv->lock_args = "dlm";
- /* The lock_args will be set in vg_write(). */
- }
- }
-
- /*
- * Apply settings to the new pool seg, from command line, from
- * defaults, sometimes adjusted.
- */
-
- seg->transaction_id = 0;
- seg->chunk_size = chunk_size;
-
- if (to_cachepool) {
- cache_mode_t cache_mode = 0;
- const char *policy_name = NULL;
- struct dm_config_tree *policy_settings = NULL;
-
- if (!get_cache_params(cmd, &cache_mode, &policy_name, &policy_settings))
- return_0;
-
- if (cache_mode &&
- !cache_set_cache_mode(seg, cache_mode))
- return_0;
-
- if ((policy_name || policy_settings) &&
- !cache_set_policy(seg, policy_name, policy_settings))
- return_0;
-
- if (policy_settings)
- dm_config_destroy(policy_settings);
- } else {
- const char *discards_name;
-
- if (arg_is_set(cmd, zero_ARG))
- seg->zero_new_blocks = arg_int_value(cmd, zero_ARG, 0);
- else
- seg->zero_new_blocks = find_config_tree_bool(cmd, allocation_thin_pool_zero_CFG, vg->profile);
-
- if (arg_is_set(cmd, discards_ARG))
- seg->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN);
- else {
- if (!(discards_name = find_config_tree_str(cmd, allocation_thin_pool_discards_CFG, vg->profile)))
- return_0;
- if (!set_pool_discards(&seg->discards, discards_name))
- return_0;
- }
- }
-
- /*
- * Rename deactivated metadata LV to have _tmeta suffix.
- * Implicit checks if metadata_lv is visible.
- */
- if (pool_metadata_name &&
- !lv_rename_update(cmd, metadata_lv, meta_name, 0))
- return_0;
-
- if (!attach_pool_metadata_lv(seg, metadata_lv))
- return_0;
-
- if (!handle_pool_metadata_spare(vg,
- metadata_lv->le_count,
- use_pvh,
- arg_int_value(cmd, poolmetadataspare_ARG, DEFAULT_POOL_METADATA_SPARE)))
- return_0;
-
- if (!vg_write(vg) || !vg_commit(vg))
- return_0;
-
- if (seg->zero_new_blocks &&
- seg->chunk_size >= DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE * 2)
- log_warn("WARNING: Pool zeroing and large %s chunk size slows down provisioning.",
- display_size(cmd, seg->chunk_size));
-
- if (activate_pool && !lockd_lv(cmd, pool_lv, "ex", LDLV_PERSISTENT)) {
- log_error("Failed to lock pool LV %s.", display_lvname(pool_lv));
- goto out;
- }
-
- if (activate_pool &&
- !activate_lv_excl(cmd, pool_lv)) {
- log_error("Failed to activate pool logical volume %s.",
- display_lvname(pool_lv));
- /* Deactivate subvolumes */
- if (!deactivate_lv(cmd, seg_lv(seg, 0)))
- log_error("Failed to deactivate pool data logical volume %s.",
- display_lvname(seg_lv(seg, 0)));
- if (!deactivate_lv(cmd, seg->metadata_lv))
- log_error("Failed to deactivate pool metadata logical volume %s.",
- display_lvname(seg->metadata_lv));
- goto out;
- }
-
- r = 1;
-
-out:
- backup(vg);
-
- if (r)
- log_print_unless_silent("Converted %s to %s pool.",
- display_lvname(lv),
- to_cachepool ? "cache" : "thin");
-
- /*
- * Unlock and free the locks from existing LVs that became pool data
- * and meta LVs.
- */
- if (lockd_data_name) {
- if (!lockd_lv_name(cmd, vg, lockd_data_name, &lockd_data_id, lockd_data_args, "un", LDLV_PERSISTENT))
- log_error("Failed to unlock pool data LV %s/%s", vg->name, lockd_data_name);
- lockd_free_lv(cmd, vg, lockd_data_name, &lockd_data_id, lockd_data_args);
- }
-
- if (lockd_meta_name) {
- if (!lockd_lv_name(cmd, vg, lockd_meta_name, &lockd_meta_id, lockd_meta_args, "un", LDLV_PERSISTENT))
- log_error("Failed to unlock pool metadata LV %s/%s", vg->name, lockd_meta_name);
- lockd_free_lv(cmd, vg, lockd_meta_name, &lockd_meta_id, lockd_meta_args);
- }
-
- return r;
-#if 0
-revert_new_lv:
- /* TBD */
- if (!pool_metadata_lv_name) {
- if (!deactivate_lv(cmd, metadata_lv)) {
- log_error("Failed to deactivate metadata lv.");
- return 0;
- }
- if (!lv_remove(metadata_lv) || !vg_write(vg) || !vg_commit(vg))
- log_error("Manual intervention may be required to remove "
- "abandoned LV(s) before retrying.");
- else
- backup(vg);
- }
-
- return 0;
-#endif
-}
-
-/*
- * Convert origin into a cache LV by attaching a cache pool.
- */
-static int _lvconvert_cache(struct cmd_context *cmd,
- struct logical_volume *origin_lv,
- struct lvconvert_params *lp)
-{
- struct logical_volume *pool_lv = lp->pool_data_lv;
- struct logical_volume *cache_lv;
-
- if (!validate_lv_cache_create_pool(pool_lv))
- return_0;
-
- if (!archive(origin_lv->vg))
- return_0;
-
- if (!(cache_lv = lv_cache_create(pool_lv, origin_lv)))
- return_0;
-
- if (!cache_set_cache_mode(first_seg(cache_lv), lp->cache_mode))
- return_0;
-
- if (!cache_set_policy(first_seg(cache_lv), lp->policy_name, lp->policy_settings))
- return_0;
-
- cache_check_for_warns(first_seg(cache_lv));
-
- if (!lv_update_and_reload(cache_lv))
- return_0;
-
- log_print_unless_silent("Logical volume %s is now cached.",
- display_lvname(cache_lv));
-
- return 1;
-}
-
-static int _lvconvert_to_cache_vol(struct cmd_context *cmd,
- struct logical_volume *lv,
- struct logical_volume *cachepool_lv)
-{
- struct logical_volume *cache_lv;
- cache_mode_t cache_mode = 0;
- const char *policy_name = NULL;
- struct dm_config_tree *policy_settings = NULL;
-
- if (!validate_lv_cache_create_pool(cachepool_lv))
- return_0;
-
- if (!get_cache_params(cmd, &cache_mode, &policy_name, &policy_settings))
- return_0;
-
- if (!archive(lv->vg))
- return_0;
-
- if (!(cache_lv = lv_cache_create(cachepool_lv, lv)))
- return_0;
-
- if (!cache_set_cache_mode(first_seg(cache_lv), cache_mode))
- return_0;
-
- if (!cache_set_policy(first_seg(cache_lv), policy_name, policy_settings))
- return_0;
-
- if (policy_settings)
- dm_config_destroy(policy_settings);
-
- cache_check_for_warns(first_seg(cache_lv));
-
- if (!lv_update_and_reload(cache_lv))
- return_0;
-
- log_print_unless_silent("Logical volume %s is now cached.",
- display_lvname(cache_lv));
-
- return 1;
-}
-
-/*
- * Functions called to perform a specific operation on a specific LV type.
- *
- * _convert_<lvtype>_<operation>
- *
- * For cases where an operation does not apply to the LV itself, but
- * is implicitly redirected to a sub-LV, these functions locate the
- * correct sub-LV and call the operation on that sub-LV. If a sub-LV
- * of the proper type is not found, these functions report the error.
- *
- * FIXME: the _lvconvert_foo() functions can be cleaned up since they
- * are now only called for valid combinations of LV type and operation.
- * After that happens, the code remaining in those functions can be
- * moved into the _convert_lvtype_operation() functions below.
- */
-
-/*
- * Separate a COW snapshot LV from its origin.
- * lvconvert --splitsnapshot LV
- */
-static int _convert_cow_snapshot_splitsnapshot(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_splitsnapshot(cmd, lv);
-}
-
-/*
- * Merge a COW snapshot LV into its origin.
- * lvconvert --merge LV
- */
-static int _convert_cow_snapshot_merge(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* return _lvconvert_merge_old_snapshot(cmd, lv, lp); */
-}
-
-/*
- * Merge a snapshot thin LV into its origin.
- * lvconvert --merge LV
- */
-
-static int _convert_thin_volume_merge(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_merge_thin_snapshot(cmd, lv);
-}
-
-/*
- * Split and preserve a cache pool from the data portion of a thin pool LV.
- * lvconvert --splitcache LV
- */
-static int _convert_thin_pool_splitcache(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- struct logical_volume *sublv1;
-
- sublv1 = seg_lv(first_seg(lv), 0); /* cached _tdata ? */
-
- if (!lv_is_cache(sublv1)) {
- log_error("Sub LV %s must be cache.", display_lvname(sublv1));
- return 0;
- }
-
- /* return _lvconvert_split_cached(cmd, sublv1); */
- return 0;
-}
-
-/*
- * Split and remove a cache pool from the data portion of a thin pool LV.
- * lvconvert --uncache LV
- */
-static int _convert_thin_pool_uncache(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- struct logical_volume *sublv1 = NULL;
-
- sublv1 = seg_lv(first_seg(lv), 0); /* cached _tdata ? */
-
- if (!lv_is_cache(sublv1)) {
- log_error("Sub LV %s must be cache.", display_lvname(sublv1));
- return 0;
- }
-
- /* return _lvconvert_uncache(cmd, sublv1, lp); */
- return 0;
-}
-
-/*
- * Convert the data portion of a thin pool LV to a cache LV.
- * lvconvert --type cache LV
- *
- * Required options:
- * --cachepool LV
- *
- * Auxiliary operation:
- * Converts the --cachepool arg to a cache pool if it is not already.
- *
- * Alternate syntax:
- * lvconvert --cache LV
- */
-static int _convert_thin_pool_cache(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* lvconvert --type cache includes an implicit conversion of the cachepool arg to type cache-pool. */
- if (!_lvconvert_pool(cmd, lv, lp)) {
- log_error("Implicit conversion of --cachepool arg to type cache-pool failed.");
- return 0;
- }
-
- /* Do we need to grab the tdata sub LV to pass on? */
-
- return _lvconvert_cache(cmd, lv, lp);
-}
-
-/*
- * Replace the metadata LV in a thin pool LV.
- * lvconvert --poolmetadata NewLV --thinpool LV
- * FIXME: this will change so --swap-poolmetadata defines the operation.
- * FIXME: should be lvconvert --swap-poolmetadata NewLV LV
- */
-static int _convert_thin_pool_swapmetadata(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_pool(cmd, lv, lp);
-}
-
-/*
- * Split and preserve a cache pool from a cache LV.
- * lvconvert --splitcache LV
- */
-static int _convert_cache_volume_splitcache(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* return _lvconvert_split_cached(cmd, lv); */
- return 0;
-}
-
-/*
- * Split and remove a cache pool from a cache LV.
- * lvconvert --uncache LV
- */
-static int _convert_cache_volume_uncache(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* return _lvconvert_uncache(cmd, lv, lp); */
- return 0;
-}
-
-/*
- * Split images from the raid1|mirror origin of a cache LV and use them to create a new LV.
- * lvconvert --splitmirrors Number LV
- *
- * Required options:
- * --trackchanges | --name Name
- */
-static int _convert_cache_volume_splitmirrors(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- struct logical_volume *sublv1;
-
- sublv1 = seg_lv(first_seg(lv), 0);
-
- if (lv_is_raid(sublv1))
- return _lvconvert_raid(sublv1, lp);
-
- if (lv_is_mirror(sublv1))
- return _lvconvert_mirrors(cmd, lv, lp);
-
- log_error("Sub LV %s must be raid or mirror.", display_lvname(sublv1));
- return 0;
-}
-
-/*
- * Convert a cache LV to a thin pool (using the cache LV for thin pool data).
- * lvconvert --type thin-pool LV
- *
- * Convert a cache LV to a thin volume with cached external origin using given
- * thinpool tpLV (when not yet Thinpool convert it to thin-pool first).
- * Conversion is 2-step process in this case.
- * Only writethrough cacheLV can be converted as external origin is read-only.
- * lvconvert --thin cacheLV --thinpool tpLV
- *
- * Alternate syntax:
- * This is equivalent to above, but not preferred because it's ambiguous and inconsistent.
- * lvconvert --thinpool LV
- */
-static int _convert_cache_volume_thin_pool(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- int is_clean;
- const struct lv_segment *pool_seg;
-
- if (!_lvconvert_pool(cmd, lv, lp))
- return_0;
-
- if (lv_is_cache(lv) && !lv_is_pool_data(lv)) {
- pool_seg = first_seg(first_seg(lv)->pool_lv);
- if (pool_seg->cache_mode != CACHE_MODE_WRITETHROUGH) {
- log_error("Cannot convert cache volume %s with %s cache mode to external origin.",
- display_lvname(lv),
- get_cache_mode_name(pool_seg));
- log_error("To proceed, run 'lvchange --cachemode writethrough %s'.",
- display_lvname(lv));
- return 0;
- }
-
- if (!lv_cache_wait_for_clean(lv, &is_clean))
- return_0;
-
- if (!is_clean) {
- log_error("Cache %s is not clean, refusing to convert to external origin.",
- display_lvname(lv));
- return 0;
- }
-
- if (!_lvconvert_thin(cmd, lv, lp))
- return_0;
- }
-
- return 1;
-}
-
-/*
- * Convert/Recombine cacheLV to be an origin for snapshot
- * lvconvert --type snapshot cacheLV snapshotLV
- */
-static int _convert_cache_volume_snapshot(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_snapshot(cmd, lv, lp->origin_name);
-}
-
-/*
- * Split a cache volume from a cache pool LV.
- * lvconvert --splitcache LV
- */
-static int _convert_cache_pool_splitcache(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- struct logical_volume *sublv1;
- struct lv_segment *seg;
-
- /* When passed used cache-pool of used cached LV -> split cached LV */
-
- if ((dm_list_size(&lv->segs_using_this_lv) == 1) &&
- (seg = get_only_segment_using_this_lv(lv)) &&
- seg_is_cache(seg))
- sublv1 = seg->lv;
- else {
- log_error("Sub LV of cache type not found.");
- return 0;
- }
-
- if (!lv_is_cache(sublv1)) {
- log_error("Sub LV %s must be cache.", display_lvname(sublv1));
- return 0;
- }
-
- /* return _lvconvert_split_cached(cmd, sublv1); */
- return 0;
-}
-
-/*
- * Replace the metadata LV in a cache pool LV.
- * lvconvert --poolmetadata NewLV --cachepool LV
- * FIXME: this will change so --swap-poolmetadata defines the operation.
- * FIXME: should be lvconvert --swap-poolmetadata NewLV LV
- */
-static int _convert_cache_pool_swapmetadata(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_pool(cmd, lv, lp);
-}
-
-/*
- * Change the number of images in a mirror LV.
- * lvconvert --mirrors Number LV
- */
-static int _convert_mirror_number(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_mirrors(cmd, lv, lp);
-}
-
-/*
- * Split images from a mirror LV and use them to create a new LV.
- * lvconvert --splitmirrors Number LV
- *
- * Required options:
- * --name Name
- */
-
-static int _convert_mirror_splitmirrors(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_mirrors(cmd, lv, lp);
-}
-
-/*
- * Change the type of log used by a mirror LV.
- * lvconvert --mirrorlog Type LV
- */
-static int _convert_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_mirrors(cmd, lv, lp);
-}
-
-/*
- * Convert mirror LV to linear LV.
- * lvconvert --type linear LV
- *
- * Alternate syntax:
- * lvconvert --mirrors 0 LV
- */
-static int _convert_mirror_linear(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_mirrors(cmd, lv, lp);
-}
-
-/*
- * Convert mirror LV to raid1 LV.
- * lvconvert --type raid1 LV
- */
-static int _convert_mirror_raid(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_raid(lv, lp);
-}
-
-/*
- * Change the number of images in a raid1 LV.
- * lvconvert --mirrors Number LV
- */
-static int _convert_raid_number(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_raid(lv, lp);
-}
-
-/*
- * Split images from a raid1 LV and use them to create a new LV.
- * lvconvert --splitmirrors Number LV
- *
- * Required options:
- * --trackchanges | --name Name
- */
-static int _convert_raid_splitmirrors(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* FIXME: split the splitmirrors section out of _lvconvert_raid and call it here. */
- return _lvconvert_raid(lv, lp);
-}
-
-/*
- * Merge a raid1 LV into originalLV if the raid1 LV was
- * previously split from the originalLV using --trackchanges.
- * lvconvert --merge LV
- */
-static int _convert_raid_merge(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* FIXME: split the merge section out of _lvconvert_raid and call it here. */
- return _lvconvert_raid(lv, lp);
-}
-
-/*
- * Combine a raid* LV with a snapshot LV that was previously
- * split from the raid* LV using --splitsnapshot.
- * lvconvert --type snapshot LV SnapshotLV
- *
- * Alternate syntax:
- * lvconvert --snapshot LV SnapshotLV
- */
-static int _convert_raid_snapshot(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_snapshot(cmd, lv, lp->origin_name);
-}
-
-/*
- * Convert a raid* LV to a thin LV with an external origin.
- * lvconvert --type thin LV
- *
- * Required options:
- * --thinpool LV
- *
- * Auxiliary operation:
- * Converts the --thinpool arg to a thin pool if it is not already.
- *
- * Alternate syntax:
- * lvconvert --thin LV
- */
-static int _convert_raid_thin(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* lvconvert --thin includes an implicit conversion of the thinpool arg to type thin-pool. */
- if (!_lvconvert_pool(cmd, lv, lp)) {
- log_error("Implicit conversion of --thinpool arg to type thin-pool failed.");
- return 0;
- }
-
- return _lvconvert_thin(cmd, lv, lp);
-}
-
-/*
- * Convert a raid* LV to a cache LV.
- * lvconvert --type cache LV
- *
- * Required options:
- * --cachepool LV
- *
- * Auxiliary operation:
- * Converts the --cachepool arg to a cache pool if it is not already.
- *
- * Alternate syntax:
- * lvconvert --cache LV
- */
-static int _convert_raid_cache(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* lvconvert --type cache includes an implicit conversion of the cachepool arg to type cache-pool. */
- if (!_lvconvert_pool(cmd, lv, lp)) {
- log_error("Implicit conversion of --cachepool arg to type cache-pool failed.");
- return 0;
- }
-
- return _lvconvert_cache(cmd, lv, lp);
-}
-
-/*
- * Convert a raid* LV to a thin-pool LV.
- * lvconvert --type thin-pool LV
- *
- * Alternate syntax:
- * This is equivalent to above, but not preferred because it's ambiguous and inconsistent.
- * lvconvert --thinpool LV
- */
-static int _convert_raid_thin_pool(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_pool(cmd, lv, lp);
-}
-
-/*
- * Convert a raid* LV to cache-pool LV.
- * lvconvert --type cache-pool LV
- */
-static int _convert_raid_cache_pool(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_pool(cmd, lv, lp);
-}
-
-/*
- * Convert a raid* LV to use a different raid level.
- * lvconvert --type raid* LV
- */
-static int _convert_raid_raid(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_raid(lv, lp);
-}
-
-/*
- * Convert a raid* LV to a mirror LV.
- * lvconvert --type mirror LV
- */
-static int _convert_raid_mirror(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_raid(lv, lp);
-}
-
-/*
- * Convert a raid* LV to a striped LV.
- * lvconvert --type striped LV
- */
-static int _convert_raid_striped(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_raid(lv, lp);
-}
-
-/*
- * Convert a raid* LV to a linear LV.
- * lvconvert --type linear LV
- */
-static int _convert_raid_linear(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_raid(lv, lp);
-}
-
-/*
- * Merge a striped/linear LV into a raid1 LV if the striped/linear LV was
- * previously split from the raid1 LV using --trackchanges.
- * lvconvert --merge LV
- */
-static int _convert_striped_merge(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_raid(lv, lp);
-}
-
-/*
- * Combine a linear/striped LV with a snapshot LV that was previously
- * split from the linear/striped LV using --splitsnapshot.
- * lvconvert --type snapshot LV SnapshotLV
- *
- * Alternate syntax:
- * lvconvert --snapshot LV SnapshotLV
- */
-static int _convert_striped_snapshot(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_snapshot(cmd, lv, lp->origin_name);
-}
-
-/*
- * Convert a striped/linear LV to a thin LV with an external origin.
- * lvconvert --type thin LV
- *
- * Required options:
- * --thinpool LV
- *
- * Auxiliary operation:
- * Converts the --thinpool arg to a thin pool if it is not already.
- *
- * Alternate syntax:
- * lvconvert --thin LV
- */
-static int _convert_striped_thin(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* lvconvert --thin includes an implicit conversion of the thinpool arg to type thin-pool. */
- if (!_lvconvert_pool(cmd, lv, lp)) {
- log_error("Conversion of --thinpool arg to type thin-pool failed.");
- return 0;
- }
-
- return _lvconvert_thin(cmd, lv, lp);
-}
-
-/*
- * Convert a striped/linear LV to a cache LV.
- * lvconvert --type cache LV
- *
- * Required options:
- * --cachepool LV
- *
- * Auxiliary operation:
- * Converts the --cachepool arg to a cache pool if it is not already.
- *
- * Alternate syntax:
- * lvconvert --cache LV
- */
-
-static int _convert_striped_cache(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* lvconvert --cache includes an implicit conversion of the cachepool arg to type cache-pool. */
- if (!_lvconvert_pool(cmd, lv, lp)) {
- log_error("Conversion of --cachepool arg to type cache-pool failed.");
- return 0;
- }
-
- return _lvconvert_cache(cmd, lv, lp);
-}
-
-/*
- * Convert a striped/linear LV to a thin-pool LV.
- * lvconvert --type thin-pool LV
- *
- * Alternate syntax:
- * This is equivalent to above, but not preferred because it's ambiguous and inconsistent.
- * lvconvert --thinpool LV
- */
-static int _convert_striped_thin_pool(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_pool(cmd, lv, lp);
-}
-
-/*
- * Convert a striped/linear LV to a cache-pool LV.
- * lvconvert --type cache-pool LV
- */
-static int _convert_striped_cache_pool(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_pool(cmd, lv, lp);
-}
-
-/*
- * Convert a striped/linear LV to a mirror LV.
- * lvconvert --type mirror LV
- *
- * Required options:
- * --mirrors Number
- *
- * Alternate syntax:
- * This is equivalent to above when global/mirror_segtype_default="mirror".
- * lvconvert --mirrors Number LV
- */
-static int _convert_striped_mirror(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_mirrors(cmd, lv, lp);
-}
-
-/*
- * Convert a striped/linear LV to a raid* LV.
- * lvconvert --type raid* LV
- *
- * Required options:
- * --mirrors Number
- *
- * Alternate syntax:
- * This is equivalent to above when global/mirror_segtype_default="raid1".
- * lvconvert --mirrors Number LV
- */
-static int _convert_striped_raid(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- return _lvconvert_raid(lv, lp);
-}
-
-/*
- * Functions called to perform all valid operations on a given LV type.
- *
- * _convert_<lvtype>
- */
-static int _convert_cow_snapshot(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- if (lp->splitsnapshot)
- return _convert_cow_snapshot_splitsnapshot(cmd, lv, lp);
-
- /* FIXME: add --merge-snapshot to make this distinct from --merge-mirror. */
- if (lp->merge)
- return _convert_cow_snapshot_merge(cmd, lv, lp);
-
- log_error("Operation not permitted on COW snapshot LV %s.", display_lvname(lv));
- log_error("Operations permitted on a COW snapshot LV are:\n"
- " --splitsnapshot\n"
- " --merge\n");
- return 0;
-}
-
-static int _convert_thin_volume(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- /* FIXME: add --merge-snapshot to make this distinct from --merge-mirror. */
- if (lp->merge)
- return _convert_thin_volume_merge(cmd, lv, lp);
-
- log_error("Operation not permitted on thin LV %s.", display_lvname(lv));
- log_error("Operations permitted on a thin LV are:\n"
- " --merge\n");
- return 0;
-}
-
-static int _convert_thin_pool(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- if (lp->splitcache)
- return _convert_thin_pool_splitcache(cmd, lv, lp);
-
- if (lp->split)
- return _convert_thin_pool_splitcache(cmd, lv, lp);
-
- if (lp->uncache)
- return _convert_thin_pool_uncache(cmd, lv, lp);
-
- if (lp->cache)
- return _convert_thin_pool_cache(cmd, lv, lp);
-
- /* FIXME: swapping the thin pool metadata LV needs a specific option like --swapmetadata */
- if (arg_is_set(cmd, poolmetadata_ARG))
- return _convert_thin_pool_swapmetadata(cmd, lv, lp);
-
- /* FIXME: add --swapmetadata to list of permitted operations. */
-
- log_error("Operation not permitted on thin pool LV %s.", display_lvname(lv));
- log_error("Operations permitted on a thin pool LV are:\n"
- " --splitcache (operates on cache sub LV)\n"
- " --uncache (operates on cache sub LV)\n"
- " --type cache (operates on data sub LV)\n"
- " --repair\n");
- return 0;
-}
-
-static int _convert_cache_volume(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- if (lp->splitcache)
- return _convert_cache_volume_splitcache(cmd, lv, lp);
-
- if (lp->split)
- return _convert_cache_volume_splitcache(cmd, lv, lp);
-
- if (lp->uncache)
- return _convert_cache_volume_uncache(cmd, lv, lp);
-
- if (arg_is_set(cmd, splitmirrors_ARG))
- return _convert_cache_volume_splitmirrors(cmd, lv, lp);
-
- if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL) ||
- arg_is_set(cmd, thinpool_ARG))
- return _convert_cache_volume_thin_pool(cmd, lv, lp);
-
- if (!strcmp(lp->type_str, SEG_TYPE_NAME_SNAPSHOT) ||
- arg_is_set(cmd, snapshot_ARG))
- return _convert_cache_volume_snapshot(cmd, lv, lp);
-
- /* The --thinpool alternative for --type thin-pool is not preferred, so not shown. */
-
- log_error("Operation not permitted on cache LV %s.", display_lvname(lv));
- log_error("Operations permitted on a cache LV are:\n"
- " --splitcache\n"
- " --uncache\n"
- " --splitmirrors (operates on mirror or raid sub LV)\n"
- " --type thin-pool\n");
- return 0;
-}
-
-static int _convert_cache_pool(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- if (lp->splitcache)
- return _convert_cache_pool_splitcache(cmd, lv, lp);
-
- if (lp->split)
- return _convert_cache_pool_splitcache(cmd, lv, lp);
+ }
+ }
- /* FIXME: swapping the cache pool metadata LV needs a specific option like --swapmetadata */
- if (arg_is_set(cmd, poolmetadata_ARG))
- return _convert_cache_pool_swapmetadata(cmd, lv, lp);
+ /*
+ * Apply settings to the new pool seg, from command line, from
+ * defaults, sometimes adjusted.
+ */
- /* FIXME: add --swapmetadata to list of permitted operations. */
+ seg->transaction_id = 0;
+ seg->chunk_size = chunk_size;
- log_error("Operation not permitted on cache pool LV %s.", display_lvname(lv));
- log_error("Operations permitted on a cache pool LV are:\n"
- " --splitcache (operates on cache LV)\n");
- return 0;
-}
+ if (to_cachepool) {
+ cache_mode_t cache_mode = 0;
+ const char *policy_name = NULL;
+ struct dm_config_tree *policy_settings = NULL;
-static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- if (arg_is_set(cmd, mirrors_ARG))
- return _convert_mirror_number(cmd, lv, lp);
+ if (!get_cache_params(cmd, &cache_mode, &policy_name, &policy_settings))
+ return_0;
- if (arg_is_set(cmd, splitmirrors_ARG))
- return _convert_mirror_splitmirrors(cmd, lv, lp);
+ if (cache_mode &&
+ !cache_set_cache_mode(seg, cache_mode))
+ return_0;
- if (arg_is_set(cmd, mirrorlog_ARG) || arg_is_set(cmd, corelog_ARG))
- return _convert_mirror_log(cmd, lv, lp);
+ if ((policy_name || policy_settings) &&
+ !cache_set_policy(seg, policy_name, policy_settings))
+ return_0;
- if (_linear_type_requested(lp->type_str))
- return _convert_mirror_linear(cmd, lv, lp);
+ if (policy_settings)
+ dm_config_destroy(policy_settings);
+ } else {
+ const char *discards_name;
- if (segtype_is_raid(lp->segtype))
- return _convert_mirror_raid(cmd, lv, lp);
+ if (arg_is_set(cmd, zero_ARG))
+ seg->zero_new_blocks = arg_int_value(cmd, zero_ARG, 0);
+ else
+ seg->zero_new_blocks = find_config_tree_bool(cmd, allocation_thin_pool_zero_CFG, vg->profile);
- log_error("Unknown operation on mirror LV %s.", display_lvname(lv));
- return 0;
-}
+ if (arg_is_set(cmd, discards_ARG))
+ seg->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN);
+ else {
+ if (!(discards_name = find_config_tree_str(cmd, allocation_thin_pool_discards_CFG, vg->profile)))
+ return_0;
+ if (!set_pool_discards(&seg->discards, discards_name))
+ return_0;
+ }
+ }
-static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- if (arg_is_set(cmd, mirrors_ARG))
- return _convert_raid_number(cmd, lv, lp);
+ /*
+ * Rename deactivated metadata LV to have _tmeta suffix.
+ * Implicit checks if metadata_lv is visible.
+ */
+ if (pool_metadata_name &&
+ !lv_rename_update(cmd, metadata_lv, meta_name, 0))
+ return_0;
- if (arg_is_set(cmd, splitmirrors_ARG))
- return _convert_raid_splitmirrors(cmd, lv, lp);
+ if (!attach_pool_metadata_lv(seg, metadata_lv))
+ return_0;
- if (segtype_is_raid(lp->segtype))
- return _convert_raid_raid(cmd, lv, lp);
+ if (!handle_pool_metadata_spare(vg,
+ metadata_lv->le_count,
+ use_pvh,
+ arg_int_value(cmd, poolmetadataspare_ARG, DEFAULT_POOL_METADATA_SPARE)))
+ return_0;
- if (segtype_is_mirror(lp->segtype))
- return _convert_raid_mirror(cmd, lv, lp);
+ if (!vg_write(vg) || !vg_commit(vg))
+ return_0;
- if (!strcmp(lp->type_str, SEG_TYPE_NAME_STRIPED))
- return _convert_raid_striped(cmd, lv, lp);
+ if (seg->zero_new_blocks &&
+ seg->chunk_size >= DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE * 2)
+ log_warn("WARNING: Pool zeroing and large %s chunk size slows down provisioning.",
+ display_size(cmd, seg->chunk_size));
- if (_linear_type_requested(lp->type_str))
- return _convert_raid_linear(cmd, lv, lp);
+ if (activate_pool && !lockd_lv(cmd, pool_lv, "ex", LDLV_PERSISTENT)) {
+ log_error("Failed to lock pool LV %s.", display_lvname(pool_lv));
+ goto out;
+ }
- log_error("Unknown operation on raid LV %s.", display_lvname(lv));
- return 0;
-}
+ if (activate_pool &&
+ !activate_lv_excl(cmd, pool_lv)) {
+ log_error("Failed to activate pool logical volume %s.",
+ display_lvname(pool_lv));
+ /* Deactivate subvolumes */
+ if (!deactivate_lv(cmd, seg_lv(seg, 0)))
+ log_error("Failed to deactivate pool data logical volume %s.",
+ display_lvname(seg_lv(seg, 0)));
+ if (!deactivate_lv(cmd, seg->metadata_lv))
+ log_error("Failed to deactivate pool metadata logical volume %s.",
+ display_lvname(seg->metadata_lv));
+ goto out;
+ }
-static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
-{
- const char *mirrors_type = find_config_tree_str(cmd, global_mirror_segtype_default_CFG, NULL);
+ r = 1;
- if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR))
- return _convert_striped_mirror(cmd, lv, lp);
+out:
+ backup(vg);
- if (segtype_is_raid(lp->segtype))
- return _convert_striped_raid(cmd, lv, lp);
+ if (r)
+ log_print_unless_silent("Converted %s to %s pool.",
+ display_lvname(lv),
+ to_cachepool ? "cache" : "thin");
- /* --mirrors can mean --type mirror or --type raid1 depending on config setting. */
+ /*
+ * Unlock and free the locks from existing LVs that became pool data
+ * and meta LVs.
+ */
+ if (lockd_data_name) {
+ if (!lockd_lv_name(cmd, vg, lockd_data_name, &lockd_data_id, lockd_data_args, "un", LDLV_PERSISTENT))
+ log_error("Failed to unlock pool data LV %s/%s", vg->name, lockd_data_name);
+ lockd_free_lv(cmd, vg, lockd_data_name, &lockd_data_id, lockd_data_args);
+ }
- if (arg_is_set(cmd, mirrors_ARG) && mirrors_type && !strcmp(mirrors_type, SEG_TYPE_NAME_MIRROR))
- return _convert_striped_mirror(cmd, lv, lp);
+ if (lockd_meta_name) {
+ if (!lockd_lv_name(cmd, vg, lockd_meta_name, &lockd_meta_id, lockd_meta_args, "un", LDLV_PERSISTENT))
+ log_error("Failed to unlock pool metadata LV %s/%s", vg->name, lockd_meta_name);
+ lockd_free_lv(cmd, vg, lockd_meta_name, &lockd_meta_id, lockd_meta_args);
+ }
- if (arg_is_set(cmd, mirrors_ARG) && mirrors_type && !strcmp(mirrors_type, SEG_TYPE_NAME_RAID1))
- return _convert_striped_raid(cmd, lv, lp);
+ return r;
+#if 0
+revert_new_lv:
+ /* TBD */
+ if (!pool_metadata_lv_name) {
+ if (!deactivate_lv(cmd, metadata_lv)) {
+ log_error("Failed to deactivate metadata lv.");
+ return 0;
+ }
+ if (!lv_remove(metadata_lv) || !vg_write(vg) || !vg_commit(vg))
+ log_error("Manual intervention may be required to remove "
+ "abandoned LV(s) before retrying.");
+ else
+ backup(vg);
+ }
- log_error("Unknown operation on striped or linear LV %s.", display_lvname(lv));
return 0;
+#endif
}
-/*
- * Main entry point.
- * lvconvert performs a specific <operation> on a specific <lv_type>.
- *
- * The <operation> is specified by command line args.
- * The <lv_type> is found using lv_is_foo(lv) functions.
- *
- * for each lvtype,
- * _convert_lvtype();
- * for each arg_is_set(operation)
- * _convert_lvtype_operation();
- *
- * FIXME: this code (identifying/routing each unique operation through
- * _convert_lvtype_op) was designed to work based on the new type that
- * the user entered after --type, not the final segment type in lp->type_str.
- * Sometimes the two differ because tricks are played with lp->type_str.
- * So, when the use of arg_type_str(type_ARG) here was replaced with
- * lp->type_str, some commands are no longer identified/routed correctly.
- */
-static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
- struct lvconvert_params *lp)
+static int _lvconvert_to_cache_vol(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct logical_volume *cachepool_lv)
{
- struct lv_segment *seg = first_seg(lv);
- int ret = 0;
+ struct logical_volume *cache_lv;
+ cache_mode_t cache_mode = 0;
+ const char *policy_name = NULL;
+ struct dm_config_tree *policy_settings = NULL;
- /* Set up segtype either from type_str or else to match the existing one. */
- if (!*lp->type_str)
- lp->segtype = seg->segtype;
- else if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str)))
- goto_out;
+ if (!validate_lv_cache_create_pool(cachepool_lv))
+ return_0;
- if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) {
- if (!lp->mirrors_supplied && !seg_is_raid1(seg)) {
- log_error("Conversions to --type mirror require -m/--mirrors");
- goto out;
- }
- }
+ if (!get_cache_params(cmd, &cache_mode, &policy_name, &policy_settings))
+ return_0;
- /* lv->segtype can't be NULL */
- if (activation() && lp->segtype->ops->target_present &&
- !lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) {
- log_error("%s: Required device-mapper target(s) not "
- "detected in your kernel.", lp->segtype->name);
- goto out;
- }
+ if (!archive(lv->vg))
+ return_0;
- /* Process striping parameters */
- /* FIXME This is incomplete */
- if (_mirror_or_raid_type_requested(cmd, lp->type_str) || _raid0_type_requested(lp->type_str) ||
- _striped_type_requested(lp->type_str) || lp->mirrorlog || lp->corelog) {
- /* FIXME Handle +/- adjustments too? */
- if (!get_stripe_params(cmd, lp->segtype, &lp->stripes, &lp->stripe_size, &lp->stripes_supplied, &lp->stripe_size_supplied))
- goto_out;
+ if (!(cache_lv = lv_cache_create(cachepool_lv, lv)))
+ return_0;
- if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str))
- /* FIXME Shouldn't need to override get_stripe_params which defaults to 1 stripe (i.e. linear)! */
- /* The default keeps existing number of stripes, handled inside the library code */
- if (!arg_is_set(cmd, stripes_long_ARG))
- lp->stripes = 0;
- }
+ if (!cache_set_cache_mode(first_seg(cache_lv), cache_mode))
+ return_0;
- if (lv_is_cache(lv))
- lv = seg_lv(first_seg(lv), 0);
+ if (!cache_set_policy(first_seg(cache_lv), policy_name, policy_settings))
+ return_0;
- if (lv_is_mirror(lv)) {
- ret = _convert_mirror(cmd, lv, lp);
- goto out;
- }
+ if (policy_settings)
+ dm_config_destroy(policy_settings);
- if (lv_is_raid(lv)) {
- ret = _convert_raid(cmd, lv, lp);
- goto out;
- }
+ cache_check_for_warns(first_seg(cache_lv));
- /*
- * FIXME: add lv_is_striped() and lv_is_linear()?
- * This does not include raid0 which is caught by the test above.
- * If operations differ between striped and linear, split this case.
- */
- if (segtype_is_striped(seg->segtype) || segtype_is_linear(seg->segtype)) {
- ret = _convert_striped(cmd, lv, lp);
- goto out;
- }
+ if (!lv_update_and_reload(cache_lv))
+ return_0;
- /*
- * The intention is to explicitly check all cases above and never
- * reach here, but this covers anything that was missed.
- */
- log_error("Cannot convert LV %s.", display_lvname(lv));
+ log_print_unless_silent("Logical volume %s is now cached.",
+ display_lvname(cache_lv));
-out:
- return ret ? ECMD_PROCESSED : ECMD_FAILED;
+ return 1;
}
static struct convert_poll_id_list* _convert_poll_id_list_create(struct cmd_context *cmd,
@@ -4990,11 +3589,6 @@ int lvconvert_replace_pv_cmd(struct cmd_context *cmd, int argc, char **argv)
/*
- * snapshot-related lvconvert utilities
- */
-
-
-/*
* Merge a COW snapshot LV into its origin.
*/
@@ -5661,7 +4255,7 @@ static int _lvconvert_raid_types_single(struct cmd_context *cmd, struct logical_
lp->lv_to_poll = lv;
- ret = _lvconvert(cmd, lv, lp);
+ ret = _lvconvert_raid_types(cmd, lv, lp);
if (ret != ECMD_PROCESSED)
return_ECMD_FAILED;
@@ -5805,8 +4399,8 @@ static int _lvconvert_change_mirrorlog_single(struct cmd_context *cmd, struct lo
lp->pvh = use_pvh;
- /* FIXME: extract the mirrorlog functionality out of _lvconvert()? */
- return _lvconvert(cmd, lv, lp);
+ /* FIXME: extract the mirrorlog functionality out of _lvconvert_raid_types()? */
+ return _lvconvert_raid_types(cmd, lv, lp);
}
int lvconvert_change_mirrorlog_cmd(struct cmd_context * cmd, int argc, char **argv)
@@ -5861,8 +4455,8 @@ static int _lvconvert_split_mirror_images_single(struct cmd_context *cmd, struct
lp->pvh = use_pvh;
- /* FIXME: extract the split functionality out of _lvconvert()? */
- return _lvconvert(cmd, lv, lp);
+ /* FIXME: extract the split functionality out of _lvconvert_raid_types()? */
+ return _lvconvert_raid_types(cmd, lv, lp);
}
int lvconvert_split_mirror_images_cmd(struct cmd_context * cmd, int argc, char **argv)
7 years, 3 months