From: David Teigland Date: Fri, 10 Feb 2017 17:36:11 +0000 (-0600) Subject: commands: move command def parsing into lvm binary X-Git-Tag: v2_02_169~394 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=c3faa5816d223b0a77a248aed9a88e73461268ce;p=lvm2.git commands: move command def parsing into lvm binary It was previously done at build time by the ccmd binary. --- diff --git a/tools/Makefile.in b/tools/Makefile.in index 8f53851c3..1761be409 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -18,6 +18,7 @@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES =\ + command.c \ dumpconfig.c \ formats.c \ lvchange.c \ @@ -77,7 +78,6 @@ SOURCES2 =\ TARGETS =\ .commands \ - command-lines.h \ liblvm2cmd.a \ lvm @@ -102,7 +102,7 @@ CLEAN_TARGETS = liblvm2cmd.$(LIB_SUFFIX) $(TARGETS_DM) \ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION) lvm-static.o \ liblvm2cmd-static.a dmsetup.static lvm.static \ $(LDDEPS) .exported_symbols_generated \ - ccmd command-lines.h command-lines-count.h + cmds.h command-lines-input.h command-count.h ifeq ("@CMDLIB@", "yes") TARGETS += liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION) @@ -176,35 +176,40 @@ 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: $(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 +command-count.h: $(srcdir)/command-lines.in Makefile + set -o pipefail && \ + ( cat $(top_srcdir)/doc/license.txt && \ + echo "/* Do not edit. This file is generated by the Makefile. */" && \ + echo -n "#define COMMAND_COUNT " && \ + $(GREP) '^ID:' $(srcdir)/command-lines.in | $(WC) -l \ + ) > $@ + +cmds.h: $(srcdir)/command-lines.in Makefile + set -o pipefail && \ + ( cat $(top_srcdir)/doc/license.txt && \ + echo "/* Do not edit. This file is generated by the Makefile. */" && \ + echo "cmd(CMD_NONE, none)" && \ + $(GREP) '^ID:' $(srcdir)/command-lines.in | $(SORT) -u | $(AWK) '{print "cmd(" $$2 "_CMD, " $$2 ")"}' && \ + echo "cmd(CMD_COUNT, count)" \ + ) > $@ + +command-lines-input.h: $(srcdir)/command-lines.in 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};" \ + ( cat $(top_srcdir)/doc/license.txt && \ + echo "/* Do not edit. This file is generated by the Makefile. */" && \ + echo -en "const char _command_input[] =\n\n\"" && \ + $(GREP) -Ev '^#|\-\-\-|^$$' $(srcdir)/command-lines.in | $(AWK) 'BEGIN {ORS = "\\n\"\n\""} //' && \ + echo "\\n\";" \ ) > $@ -$(SOURCES:%.c=%.d): command-lines.h command-lines-count.h +$(SOURCES:%.c=%.d) $(SOURCES2:%.c=%.d): command-lines-input.h command-count.h cmds.h ifneq ("$(CFLOW_CMD)", "") CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) diff --git a/tools/ccmd-main.c b/tools/ccmd-main.c deleted file mode 100644 index 85d5656de..000000000 --- a/tools/ccmd-main.c +++ /dev/null @@ -1,1130 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 \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 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 deleted file mode 100644 index 34a9c3888..000000000 --- a/tools/ccmd-man.c +++ /dev/null @@ -1,997 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 -b|--bbb - */ - - 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 deleted file mode 100644 index 15b2f9642..000000000 --- a/tools/ccmd-util.c +++ /dev/null @@ -1,936 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 _ */ - - 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_ to _LVT */ - -int lv_to_enum(char *name) -{ - return lvt_name_to_enum(name + 3); -} - -/* - * LV__ 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 deleted file mode 100644 index 1e1812512..000000000 --- a/tools/ccmd.h +++ /dev/null @@ -1,144 +0,0 @@ - -#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/command-lines.in b/tools/command-lines.in index 4cc51fea4..30573f452 100644 --- a/tools/command-lines.in +++ b/tools/command-lines.in @@ -1,12 +1,15 @@ +# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. +# Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved. # -# When this file is changed, tools/command-lines.h -# and tools/command-lines-count.h must be regenerated -# with: +# This file is part of LVM2. # -# tools/create-commands --output count tools/command-lines.in > tools/command-lines-count.h -# tools/create-commands --output struct tools/command-lines.in > tools/command-lines.h +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions +# of the GNU Lesser General Public License v.2.1. # - +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Syntax # @@ -261,7 +264,7 @@ RULE: --permission not lv_is_external_origin lv_is_raid_metadata lv_is_raid_imag RULE: --alloc --contiguous --metadataprofile --permission --persistent --profile --readahead not lv_is_thick_origin RULE: --alloc --discards --zero --cachemode --cachepolicy --cachesettings not lv_is_partial -# It's unfortunate that acativate needs to be optionally allowed here, +# It's unfortunate that activate needs to be optionally allowed here, # like above, it was previouly allowed in combination. lvchange --resync VG|LV_raid_mirror|Tag|Select ... diff --git a/tools/command.c b/tools/command.c new file mode 100644 index 000000000..59c9ea007 --- /dev/null +++ b/tools/command.c @@ -0,0 +1,2694 @@ +/* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This file can be compiled by itself as a man page generator. + */ +#ifdef MAN_PAGE_GENERATOR + +#define log_error(fmt, args...) \ +do { \ + printf(fmt "\n", ##args); \ +} while (0) + +/* 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; } + +/* needed to include commands.h when building man page generator */ +#define CACHE_VGMETADATA 0x00000001 +#define PERMITTED_READ_ONLY 0x00000002 +#define ALL_VGS_IS_DEFAULT 0x00000004 +#define ENABLE_ALL_DEVS 0x00000008 +#define ALLOW_UUID_AS_NAME 0x00000010 +#define LOCKD_VG_SH 0x00000020 +#define NO_METADATA_PROCESSING 0x00000040 +#define REQUIRES_FULL_LABEL_SCAN 0x00000080 +#define MUST_USE_ALL_ARGS 0x00000100 +#define NO_LVMETAD_AUTOSCAN 0x00000200 +#define ENABLE_DUPLICATE_DEVS 0x00000400 +#define DISALLOW_TAG_ARGS 0x00000800 +#define GET_VGNAME_FROM_OPTIONS 0x00001000 + +/* create foo_CMD enums for command def ID's in command-lines.in */ + +enum { +#define cmd(a, b) a , +#include "cmds.h" +#undef cmd +}; + +/* 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 +}; + +#else + +#include "tools.h" + +#endif + +#include "command.h" /* defines struct command */ +#include "command-count.h" /* defines COMMAND_COUNT */ + + +/* see opt_names[] below, 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; +}; + +/* see val_names[] below, 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; +}; + +/* see lvp_names[] below, 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" */ +}; + +/* see lvt_names[] below, 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" */ +}; + +/* see cmd_names[] below, one for each unique "ID" in command-lines.in */ + +struct cmd_name { + const char *enum_name; /* "foo_CMD" */ + int cmd_enum; /* foo_CMD */ + const char *name; /* "foo" from string after ID: */ +}; + +/* 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 IDs */ + +struct cmd_name cmd_names[CMD_COUNT + 1] = { +#define cmd(a, b) { # a, a, # b }, +#include "cmds.h" +#undef cmd +}; + +/* + * command_names[] and commands[] are defined in lvmcmdline.c when building lvm, + * but need to be defined here when building the stand-alone man page generator. + */ + +#ifdef MAN_PAGE_GENERATOR +struct command_name command_names[MAX_COMMAND_NAMES] = { +#define xx(a, b, c...) { # a, b, c }, +#include "commands.h" +#undef xx +}; +struct command commands[COMMAND_COUNT]; +#else +extern struct command_name command_names[MAX_COMMAND_NAMES]; /* defined in lvmcmdline.c */ +extern struct command commands[COMMAND_COUNT]; /* defined in lvmcmdline.c */ +#endif + +/* 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 */ + +#define MAX_LINE 1024 +#define MAX_LINE_ARGC 256 +#define DESC_LINE 1024 + +/* + * Contains _command_input[] which is command-lines.in with comments + * removed and wrapped as a string. The _command_input[] string is + * used to populate commands[]. + */ +#include "command-lines-input.h" + +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 _ */ + + 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; + } + + log_error("Parsing command defs: unknown opt str: %s %s", str, long_name); + exit(EXIT_FAILURE); + } + + 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; + } + + log_error("Parsing command defs: unknown opt str: \"%s\"", str); + exit(EXIT_FAILURE); +} + +/* "foo" string to foo_CMD int */ + +int command_id_to_enum(const char *str) +{ + int i; + + for (i = 1; i < CMD_COUNT; i++) { + if (!strcmp(str, cmd_names[i].name)) + return cmd_names[i].cmd_enum; + } + log_error("Parsing command defs: unknown cmd name %s", str); + exit(EXIT_FAILURE); +} + +/* "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; + } + log_error("Parsing command defs: unknown lv property %s", str); + exit(EXIT_FAILURE); +} + +/* "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; + } + log_error("Parsing command defs: unknown lv type %s", str); + exit(EXIT_FAILURE); +} + +/* LV_ to _LVT */ + +static int lv_to_enum(char *name) +{ + return lvt_name_to_enum(name + 3); +} + +/* + * LV__ 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) + */ + +static 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 struct command_name *find_command_name(const char *name) +{ + int i; + + for (i = 0; i < MAX_COMMAND_NAMES; i++) { + if (!command_names[i].name) + break; + if (!strcmp(command_names[i].name, name)) + return &command_names[i]; + } + return NULL; +} + +static const char *is_command_name(char *str) +{ + int i; + + for (i = 0; i < MAX_COMMAND_NAMES; i++) { + if (!command_names[i].name) + break; + if (!strcmp(command_names[i].name, str)) + return command_names[i].name; + } + return NULL; +} + +static int is_opt_name(char *str) +{ + if (!strncmp(str, "--", 2)) + return 1; + + if ((str[0] == '-') && (str[1] != '-')) { + log_error("Parsing command defs: options must be specified in long form: %s", str); + exit(EXIT_FAILURE); + } + + 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) { + log_error("Parsing command defs: unknown pos arg: %s", name); + exit(EXIT_FAILURE); + } + + 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; + + 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 { + log_error("Parsing command defs: unknown opt arg: %s", name); + exit(EXIT_FAILURE); + } + } + + + 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 { + log_error("Parsing command defs: invalid OO definition"); + exit(EXIT_FAILURE); + } + + 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. */ + +static char *get_oo_line(const 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, const char *str) +{ + char *oo_line; + char *line; + char *line_argv[MAX_LINE_ARGC]; + int line_argc; + + if (!(oo_line = get_oo_line(str))) { + log_error("Parsing command defs: no OO line found for %s", str); + exit(EXIT_FAILURE); + } + + if (!(line = strdup(oo_line))) + exit(EXIT_FAILURE); + + 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(EXIT_FAILURE); + + *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] == '-') { + log_error("Parsing command defs: option %s must be followed by an arg.", str); + exit(EXIT_FAILURE); + } + + /* 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(EXIT_FAILURE); +} + +/* + * 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 { + log_error("Parsing command defs: unknown pos arg: %s", str); + exit(EXIT_FAILURE); + } +} + +/* 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 { + log_error("Parsing command defs: can't parse argc %d argv %s prev %s", + i, argv[i], argv[i-1]); + exit(EXIT_FAILURE); + } + } +} + +/* 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 { + log_error("Parsing command defs: can't parse argc %d argv %s prev %s", + i, argv[i], argv[i-1]); + exit(EXIT_FAILURE); + } + } +} + +/* 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 { + log_error("Parsing command defs: can't parse argc %d argv %s prev %s", + i, argv[i], argv[i-1]); + exit(EXIT_FAILURE); + } + } +} + +/* + * 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))) { + log_error("Parsing command defs: no OO line found for %s", str); + exit(EXIT_FAILURE); + } + + if (!(line = strdup(oo_line))) + exit(EXIT_FAILURE); + + 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 { + log_error("Parsing command defs: can't parse argc %d argv %s prev %s", + i, argv[i], argv[i-1]); + exit(EXIT_FAILURE); + } + + } +} + +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) { + log_error("Parsing command defs: too many rules for cmd"); + exit(EXIT_FAILURE); + } + + 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)))) { + log_error("Parsing command defs: no mem"); + exit(EXIT_FAILURE); + } + memset(rule->opts, 0, MAX_RULE_OPTS * sizeof(int)); + } + + if (!rule->check_opts) { + if (!(rule->check_opts = malloc(MAX_RULE_OPTS * sizeof(int)))) { + log_error("Parsing command defs: no mem"); + exit(EXIT_FAILURE); + } + 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). */ + +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; +} + +/* 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_COMMAND_NAMES; cn++) { + if (!command_names[cn].name) + break; + + for (ci = 0; ci < COMMAND_COUNT; ci++) { + cmd = &commands[ci]; + + if (strcmp(cmd->name, command_names[cn].name)) + continue; + + command_names[cn].variants++; + } + + for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { + + for (ci = 0; ci < COMMAND_COUNT; ci++) { + cmd = &commands[ci]; + + if (strcmp(cmd->name, command_names[cn].name)) + continue; + + if (cmd->ro_count) + command_names[cn].variant_has_ro = 1; + if (cmd->rp_count) + command_names[cn].variant_has_rp = 1; + if (cmd->oo_count) + command_names[cn].variant_has_oo = 1; + if (cmd->op_count) + command_names[cn].variant_has_op = 1; + + for (ro = 0; ro < cmd->ro_count; ro++) { + command_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)) + command_names[cn].all_options[extents_ARG] = 1; + } + for (oo = 0; oo < cmd->oo_count; oo++) + command_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 */ + command_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 int copy_line(char *line, int max_line, int *position) +{ + int p = *position; + int i = 0; + + memset(line, 0, max_line); + + while (1) { + line[i] = _command_input[p]; + i++; + p++; + + if (_command_input[p] == '\n') { + p++; + break; + } + + if (i == (max_line - 1)) + break; + } + *position = p; + return 1; +} + +int define_commands(void) +{ + struct command *cmd; + char line[MAX_LINE]; + char line_orig[MAX_LINE]; + char *line_argv[MAX_LINE_ARGC]; + const char *name; + char *n; + int line_argc; + int cmd_count = 0; + int prev_was_oo_def = 0; + int prev_was_oo = 0; + int prev_was_op = 0; + int copy_pos = 0; + + create_opt_names_alpha(); + + /* Process each line of command-lines-input.h (from command-lines.in) */ + + while (copy_line(line, MAX_LINE, ©_pos)) { + if (line[0] == '\n') + break; + + if ((n = strchr(line, '\n'))) + *n = '\0'; + + memcpy(line_orig, line, sizeof(line)); + split_line(line, &line_argc, line_argv, ' '); + + if (!line_argc) + continue; + + /* New cmd def begins: command_name */ + if ((name = is_command_name(line_argv[0]))) { + if (cmd_count >= COMMAND_COUNT) { + return 0; + } + + /* + * FIXME: when running one specific command name, + * we can optimize by not parsing command defs + * that don't start with that command name. + */ + + cmd = &commands[cmd_count]; + cmd->command_index = cmd_count; + cmd_count++; + cmd->name = strdup(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; + } + + /* + * All other kinds of lines are processed in the + * context of the existing command[]. + */ + + 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_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; + } + } + + /* + * For usage. + * Looks at all variants of each command name and figures out + * which options are common to all variants (for compact output) + */ + factor_common_options(); + + /* + * For usage. + * Predefined string of options common to all commands + * (for compact output) + */ + include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON"); + + return 1; +} + +/* type_LVT to "type" */ + +static const char *lvt_enum_to_name(int lvt_enum) +{ + return lvt_names[lvt_enum].name; +} + +static void _print_usage_description(struct command *cmd) +{ + const char *desc = cmd->desc; + char buf[MAX_LINE] = {0}; + int di = 0; + int bi = 0; + + for (di = 0; di < strlen(desc); di++) { + if (!strncmp(&desc[di], "DESC:", 5)) { + if (bi) { + buf[bi] = '\0'; + printf(" %s\n", buf); + memset(buf, 0, sizeof(buf)); + bi = 0; + } + /* skip DESC: */ + di += 5; + continue; + } + + if (!bi && desc[di] == ' ') + continue; + + buf[bi++] = desc[di]; + + if (bi == (MAX_LINE - 1)) + break; + } + + if (bi) { + buf[bi] = '\0'; + printf(" %s\n", buf); + } +} + +static void print_usage_def(struct arg_def *def) +{ + int val_enum; + int lvt_enum; + int sep = 0; + + 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 (!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_usage(struct command *cmd) +{ + struct command_name *cname = find_command_name(cmd->name); + int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0; + int ro, rp, oo, op, opt_enum, first; + + if (cmd->desc) + _print_usage_description(cmd); + + printf(" %s", cmd->name); + + if (cmd->ro_count) { + first = 1; + + for (ro = 0; ro < cmd->ro_count; ro++) { + if (onereq) { + if (first) + printf("\n\t("); + else + printf(",\n\t "); + first = 0; + } + + printf(" %s", opt_names[cmd->required_opt_args[ro].opt].long_opt); + if (cmd->required_opt_args[ro].def.val_bits) { + printf(" "); + print_usage_def(&cmd->required_opt_args[ro].def); + } + } + if (onereq) + printf(" )\n"); + } + + if (cmd->rp_count) { + if (onereq) + printf("\t"); + for (rp = 0; rp < cmd->rp_count; rp++) { + if (cmd->required_pos_args[rp].def.val_bits) { + printf(" "); + print_usage_def(&cmd->required_pos_args[rp].def); + } + } + } + + if (!cmd->oo_count) + goto op_count; + + if (cmd->oo_count) { + first = 1; + + for (oo = 0; oo < cmd->oo_count; oo++) { + opt_enum = cmd->optional_opt_args[oo].opt; + + /* + * Skip common opts in lvm_all and cname->common_options. + */ + + if (is_lvm_all_opt(opt_enum)) + continue; + + if ((cname->variants > 1) && cname->common_options[opt_enum]) + continue; + + if (first) + printf("\n\t["); + else + printf(",\n\t "); + first = 0; + + printf(" %s", opt_names[opt_enum].long_opt); + if (cmd->optional_opt_args[oo].def.val_bits) { + printf(" "); + print_usage_def(&cmd->optional_opt_args[oo].def); + } + } + + if (first) + printf("\n\t["); + else + printf(",\n\t "); + printf(" COMMON_OPTIONS ]"); + } + + op_count: + if (!cmd->op_count) + goto done; + + printf("\n\t["); + + if (cmd->op_count) { + for (op = 0; op < cmd->op_count; op++) { + if (cmd->optional_pos_args[op].def.val_bits) { + printf(" "); + print_usage_def(&cmd->optional_pos_args[op].def); + } + } + } + + printf(" ]"); + done: + printf("\n"); + return; +} + + +void print_usage_common(struct command_name *cname, struct command *cmd) +{ + int oo, opt_enum, first; + + printf(" Common options:"); + + /* + * when there's more than one variant, options that + * are common to all commands with a common name. + */ + + if (cname->variants < 2) + goto all; + + first = 1; + + 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 (first) + printf("\n\t["); + else + printf(",\n\t "); + first = 0; + + 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_usage_def(&cmd->optional_opt_args[oo].def); + } + 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 (first) + printf("\n\t["); + else + printf(",\n\t "); + first = 0; + + printf(" %s", opt_names[opt_enum].long_opt); + if (lvm_all.optional_opt_args[oo].def.val_bits) { + printf(" "); + print_usage_def(&lvm_all.optional_opt_args[oo].def); + } + } + + printf(" ]\n"); +} + +#ifdef MAN_PAGE_GENERATOR + +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(char *lvmname, struct command *cmd) +{ + struct command_name *cname; + int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0; + int i, sep, ro, rp, oo, op, opt_enum; + int need_ro_indent_end = 0; + + if (!(cname = find_command_name(cmd->name))) + return; + + printf("\\fB%s\\fP", lvmname); + + 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++; + } + + /* 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++; + } + + 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 -b|--bbb + */ + + if (cmd->ro_count) { + sep = 0; + + for (ro = 0; ro < cmd->ro_count; ro++) { + + /* avoid long line wrapping */ + if ((cmd->ro_count > 2) && (sep == 2)) { + printf("\n.RS 5\n"); + need_ro_indent_end = 1; + } + + 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); + } + + sep++; + } + } + + /* 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"); + } + + if (need_ro_indent_end) + printf(".RE\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; + + 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; + + 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 command_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 command_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) { + log_error("Parsing command defs: print_man_option_desc line too long"); + exit(EXIT_FAILURE); + } + + 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 command_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 command_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; + + 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; +} + +static void include_description_file(char *name, char *des_file) +{ + char buf[1024 * 1024]; + int fd; + + memset(buf, 0, sizeof(buf)); + + fd = open(des_file, O_RDONLY); + + if (fd < 0) + return; + + read(fd, buf, sizeof(buf) - 1); + + printf(".SH DESCRIPTION\n"); + printf("%s\n", buf); + + close(fd); +} + +void print_man(char *name, char *des_file, int include_primary, int include_secondary) +{ + struct command_name *cname; + struct command *cmd, *prev_cmd = NULL; + char *lvmname = name; + const char *desc; + int i, j, ro, rp, oo, op; + + if (!strncmp(name, "lvm-", 4)) + name += 4; + + cname = find_command_name(name); + + printf(".TH %s 8 \"LVM TOOLS #VERSION#\" \"Sistina Software UK\"\n", + upper_command_name(lvmname)); + + for (i = 0; i < COMMAND_COUNT; i++) { + + cmd = &commands[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 (name && strcmp(name, cmd->name)) + continue; + + if (!prev_cmd || strcmp(prev_cmd->name, cmd->name)) { + printf(".SH NAME\n"); + printf(".\n"); + if (cname->desc) + printf("%s \\- %s\n", lvmname, cname->desc); + else + printf("%s\n", lvmname); + 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", lvmname); + else if (cname->variant_has_ro && !cname->variant_has_rp) + printf("\\fB%s\\fP \\fIrequired_option_args\\fP\n", lvmname); + else if (!cname->variant_has_ro && cname->variant_has_rp) + printf("\\fB%s\\fP \\fIrequired_position_args\\fP\n", lvmname); + else if (!cname->variant_has_ro && !cname->variant_has_rp) + printf("\\fB%s\\fP\n", lvmname); + + 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"); + } + + if (des_file) { + include_description_file(lvmname, des_file); + printf(".P\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(lvmname, cmd); + + if (i == (COMMAND_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; + } +} + +int main(int argc, char *argv[]) +{ + memset(&commands, 0, sizeof(commands)); + + if (argc < 2) { + log_error("Usage: %s [/path/to/description-file]", argv[0]); + exit(EXIT_FAILURE); + } + + define_commands(); + + print_man(argv[1], (argc > 2) ? argv[2] : NULL, 1, 1); + + return 0; +} + +#endif diff --git a/tools/command.h b/tools/command.h index c9be260b2..b3fae030c 100644 --- a/tools/command.h +++ b/tools/command.h @@ -22,21 +22,33 @@ struct cmd_context; typedef int (*command_fn) (struct cmd_context *cmd, int argc, char **argv); /* new per-command-line-id functions */ -typedef int (*command_line_fn) (struct cmd_context *cmd, int argc, char **argv); +typedef int (*command_id_fn) (struct cmd_context *cmd, int argc, char **argv); struct command_function { - int command_line_enum; - command_line_fn fn; + int command_enum; + command_id_fn fn; }; +#define MAX_COMMAND_NAMES 64 + struct command_name { const char *name; const char *desc; /* general command description from commands.h */ unsigned int flags; + command_fn fn; /* old style */ /* union of {required,optional}_opt_args for all commands with this name */ - int valid_args[ARG_COUNT]; + int valid_args[ARG_COUNT]; /* used for getopt */ int num_args; + + /* the following are for generating help and man page output */ + int common_options[ARG_COUNT]; /* options common to all defs */ + int all_options[ARG_COUNT]; /* 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 ? */ }; /* @@ -158,14 +170,13 @@ struct cmd_rule { /* a register of the lvm commands */ struct command { const char *name; - const char *desc; /* specific command description from command-lines.h */ - const char *usage; /* excludes common options like --help, --debug */ - const char *usage_common; /* includes commmon options like --help, --debug */ - const char *command_line_id; - int command_line_enum; /* _CMD */ + const char *desc; /* specific command description from command-lines.in */ + const char *command_id; /* ID string in command-lines.in */ + int command_enum; /* _CMD */ + int command_index; /* position in commands[] */ - command_fn fn; /* old style */ struct command_function *functions; /* new style */ + command_fn fn; /* old style */ unsigned int cmd_flags; /* CMD_FLAG_ */ @@ -198,4 +209,9 @@ struct command { int pos_count; /* temp counter used by create-command */ }; +int define_commands(void); +int command_id_to_enum(const char *str); +void print_usage(struct command *cmd); +void print_usage_common(struct command_name *cname, struct command *cmd); + #endif diff --git a/tools/lvchange.c b/tools/lvchange.c index b75d0581d..1c00b76f1 100644 --- a/tools/lvchange.c +++ b/tools/lvchange.c @@ -1016,9 +1016,7 @@ static int _lvchange_properties_check(struct cmd_context *cmd, { if (!lv_is_visible(lv)) { if (lv_is_named_arg) - log_error("Operation not permitted (%s %d) on hidden LV %s.", - cmd->command->command_line_id, cmd->command->command_line_enum, - display_lvname(lv)); + log_error("Operation not permitted on hidden LV %s.", display_lvname(lv)); return 0; } @@ -1129,9 +1127,7 @@ static int _lvchange_activate_check(struct cmd_context *cmd, { if (!lv_is_visible(lv)) { if (lv_is_named_arg) - log_error("Operation not permitted (%s %d) on hidden LV %s.", - cmd->command->command_line_id, cmd->command->command_line_enum, - display_lvname(lv)); + log_error("Operation not permitted on hidden LV %s.", display_lvname(lv)); return 0; } @@ -1185,9 +1181,7 @@ static int _lvchange_refresh_check(struct cmd_context *cmd, { if (!lv_is_visible(lv)) { if (lv_is_named_arg) - log_error("Operation not permitted (%s %d) on hidden LV %s.", - cmd->command->command_line_id, cmd->command->command_line_enum, - display_lvname(lv)); + log_error("Operation not permitted on hidden LV %s.", display_lvname(lv)); return 0; } @@ -1367,9 +1361,7 @@ static int _lvchange_persistent_check(struct cmd_context *cmd, { if (!lv_is_visible(lv)) { if (lv_is_named_arg) - log_error("Operation not permitted (%s %d) on hidden LV %s.", - cmd->command->command_line_id, cmd->command->command_line_enum, - display_lvname(lv)); + log_error("Operation not permitted on hidden LV %s.", display_lvname(lv)); return 0; } @@ -1385,8 +1377,8 @@ int lvchange_persistent_cmd(struct cmd_context *cmd, int argc, char **argv) int lvchange(struct cmd_context *cmd, int argc, char **argv) { - log_error(INTERNAL_ERROR "Missing function for command definition %s.", - cmd->command->command_line_id); + log_error(INTERNAL_ERROR "Missing function for command definition %d:%s.", + cmd->command->command_index, cmd->command->command_id); return ECMD_FAILED; } diff --git a/tools/lvconvert.c b/tools/lvconvert.c index 2ccf26495..75bdcb97e 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -17,7 +17,6 @@ #include "polldaemon.h" #include "lv_alloc.h" #include "lvconvert_poll.h" -#include "command-lines-count.h" typedef enum { /* Split: @@ -3764,7 +3763,7 @@ static int _lvconvert_to_pool_single(struct cmd_context *cmd, int to_thinpool = 0; int to_cachepool = 0; - switch (cmd->command->command_line_enum) { + switch (cmd->command->command_enum) { case lvconvert_to_thinpool_CMD: to_thinpool = 1; break; @@ -3813,7 +3812,7 @@ int lvconvert_to_pool_noarg_cmd(struct cmd_context *cmd, int argc, char **argv) char *pool_data_name; int i, p; - switch (cmd->command->command_line_enum) { + switch (cmd->command->command_enum) { case lvconvert_to_thinpool_noarg_CMD: pool_data_name = (char *)arg_str_value(cmd, thinpool_ARG, NULL); new_command = get_command(lvconvert_to_thinpool_CMD); @@ -3827,9 +3826,9 @@ int lvconvert_to_pool_noarg_cmd(struct cmd_context *cmd, int argc, char **argv) return 0; }; - log_debug("Changing command line id %s %d to standard form %s %d", - cmd->command->command_line_id, cmd->command->command_line_enum, - new_command->command_line_id, new_command->command_line_enum); + log_debug("Changing command %d:%s to standard form %d:%s", + cmd->command->command_index, cmd->command->command_id, + new_command->command_index, new_command->command_id); /* Make the LV the first position arg. */ @@ -4092,7 +4091,7 @@ int lvconvert_swap_pool_metadata_noarg_cmd(struct cmd_context *cmd, int argc, ch struct command *new_command; char *pool_name; - switch (cmd->command->command_line_enum) { + switch (cmd->command->command_enum) { case lvconvert_swap_thinpool_metadata_CMD: pool_name = (char *)arg_str_value(cmd, thinpool_ARG, NULL); break; @@ -4106,9 +4105,9 @@ int lvconvert_swap_pool_metadata_noarg_cmd(struct cmd_context *cmd, int argc, ch new_command = get_command(lvconvert_swap_pool_metadata_CMD); - log_debug("Changing command line id %s %d to standard form %s %d", - cmd->command->command_line_id, cmd->command->command_line_enum, - new_command->command_line_id, new_command->command_line_enum); + log_debug("Changing command %d:%s to standard form %d:%s", + cmd->command->command_index, cmd->command->command_id, + new_command->command_index, new_command->command_id); /* Make the LV the first position arg. */ @@ -4172,7 +4171,7 @@ static int _lvconvert_split_cachepool_single(struct cmd_context *cmd, return ECMD_FAILED; } - switch (cmd->command->command_line_enum) { + switch (cmd->command->command_enum) { case lvconvert_split_and_keep_cachepool_CMD: ret = _lvconvert_split_and_keep_cachepool(cmd, cache_lv, cachepool_lv); break; @@ -4193,7 +4192,7 @@ static int _lvconvert_split_cachepool_single(struct cmd_context *cmd, int lvconvert_split_cachepool_cmd(struct cmd_context *cmd, int argc, char **argv) { - if (cmd->command->command_line_enum == lvconvert_split_and_remove_cachepool_CMD) { + if (cmd->command->command_enum == lvconvert_split_and_remove_cachepool_CMD) { cmd->handles_missing_pvs = 1; cmd->partial_activation = 1; } @@ -4272,8 +4271,7 @@ static int _lvconvert_raid_types_check(struct cmd_context *cmd, struct logical_v case thinpool_LVT: case cachepool_LVT: case snapshot_LVT: - log_error("Operation not permitted (%s %d) on LV %s type %s.", - cmd->command->command_line_id, cmd->command->command_line_enum, + log_error("Operation not permitted on LV %s type %s.", display_lvname(lv), lvtype ? lvtype->name : "unknown"); return 0; } @@ -4281,9 +4279,7 @@ static int _lvconvert_raid_types_check(struct cmd_context *cmd, struct logical_v return 1; fail_hidden: - log_error("Operation not permitted (%s %d) on hidden LV %s.", - cmd->command->command_line_id, cmd->command->command_line_enum, - display_lvname(lv)); + log_error("Operation not permitted on hidden LV %s.", display_lvname(lv)); return 0; } @@ -4342,9 +4338,7 @@ static int _lvconvert_visible_check(struct cmd_context *cmd, struct logical_volu int lv_is_named_arg) { if (!lv_is_visible(lv)) { - log_error("Operation not permitted (%s %d) on hidden LV %s.", - cmd->command->command_line_id, cmd->command->command_line_enum, - display_lvname(lv)); + log_error("Operation not permitted on hidden LV %s.", display_lvname(lv)); return 0; } @@ -4547,8 +4541,8 @@ int lvconvert_merge_cmd(struct cmd_context *cmd, int argc, char **argv) int lvconvert(struct cmd_context *cmd, int argc, char **argv) { - log_error(INTERNAL_ERROR "Missing function for command definition %s.", - cmd->command->command_line_id); + log_error(INTERNAL_ERROR "Missing function for command definition %d:%s.", + cmd->command->command_index, cmd->command->command_id); return ECMD_FAILED; } diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 4039dd9e6..121a9dd43 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -49,7 +49,6 @@ extern char *optarg; # define OPTIND_INIT 1 #endif -#include "command-lines-count.h" /* * Table of valid --option values. @@ -69,16 +68,6 @@ static struct arg_props _arg_props[ARG_COUNT + 1] = { #undef arg }; -/* - * Table of valid command names - */ -#define MAX_COMMAND_NAMES 64 -struct command_name command_names[MAX_COMMAND_NAMES] = { -#define xx(a, b, c...) { # a, b, c }, -#include "commands.h" -#undef xx -}; - /* * Table of LV properties */ @@ -97,11 +86,20 @@ static struct lv_types _lv_types[LVT_COUNT + 1] = { #undef lvt }; +/* + * Table of command names + */ +struct command_name command_names[MAX_COMMAND_NAMES] = { +#define xx(a, b, c...) { # a, b, c, a}, +#include "commands.h" +#undef xx +}; /* - * Table of valid command lines + * Table of commands (as defined in command-lines.in) */ -static struct command commands[COMMAND_COUNT]; +struct command commands[COMMAND_COUNT]; + static struct cmdline_context _cmdline; /* @@ -111,7 +109,7 @@ static struct cmdline_context _cmdline; * to use these functions instead of the old per-command-name function. * For now, any command id not included here uses the old command fn. */ -struct command_function command_functions[COMMAND_ID_COUNT] = { +struct command_function command_functions[CMD_COUNT] = { { lvmconfig_general_CMD, lvmconfig }, { lvchange_properties_CMD, lvchange_properties_cmd }, { lvchange_resync_CMD, lvchange_resync_cmd }, @@ -1061,7 +1059,7 @@ static void _set_valid_args_for_command_name(int ci) command_names[ci].num_args = num_args; } -static struct command_name *_find_command_name(const char *name) +static struct command_name *find_command_name(const char *name) { int i; @@ -1074,39 +1072,50 @@ static struct command_name *_find_command_name(const char *name) return NULL; } -static struct command_function *_find_command_function(int command_line_enum) +static struct command_function *_find_command_id_function(int command_enum) { int i; - if (!command_line_enum) + if (!command_enum) return NULL; - for (i = 0; i < COMMAND_ID_COUNT; i++) { - if (command_functions[i].command_line_enum == command_line_enum) + for (i = 0; i < CMD_COUNT; i++) { + if (command_functions[i].command_enum == command_enum) return &command_functions[i]; } return NULL; } -static void _define_commands(void) -{ -/* command-lines.h defines command[] structs, generated from command-lines.in */ -#include "command-lines.h" /* generated from command-lines.in */ -} - void lvm_register_commands(void) { int i; memset(&commands, 0, sizeof(commands)); - _define_commands(); + /* + * populate commands[] array with command definitions + * by parsing command-lines.in/command-lines-input.h + */ + if (!define_commands()) { + log_error("Failed to parse command definitions."); + return; + } _cmdline.commands = commands; _cmdline.num_commands = COMMAND_COUNT; - for (i = 0; i < COMMAND_COUNT; i++) - commands[i].functions = _find_command_function(commands[i].command_line_enum); + for (i = 0; i < COMMAND_COUNT; i++) { + commands[i].command_enum = command_id_to_enum(commands[i].command_id); + + /* new style */ + commands[i].functions = _find_command_id_function(commands[i].command_enum); + + /* old style */ + if (!commands[i].functions) { + struct command_name *cname = find_command_name(commands[i].name); + commands[i].fn = cname->fn; + } + } _cmdline.command_names = command_names; @@ -1139,7 +1148,7 @@ struct command *get_command(int cmd_enum) int i; for (i = 0; i < COMMAND_COUNT; i++) { - if (commands[i].command_line_enum == cmd_enum) + if (commands[i].command_enum == cmd_enum) return &commands[i]; } @@ -1283,194 +1292,6 @@ static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp return 0; } - -#define HELP_LINE_SIZE 1024 - -static void _print_usage(const char *usage_str, int only_required) -{ - char buf[HELP_LINE_SIZE]; - int optional_ui = 0; - int optional_pos_ui = 0; - int ui; - int bi; - - if (!usage_str || !strlen(usage_str)) - return; - - /* - * copy the required opt_args/pos_args - * - * The optional portions of the usage string are enclosed - * in [] and follow the required portions. - * - * The optional portion begins with [ followed by a space, - * i.e. "[ " to distinguish the option usage which may - * include [ in cases like --option Number[units]. - */ - - memset(buf, 0, sizeof(buf)); - bi = 0; - - 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_str[ui] == '[') && (usage_str[ui+1] == ' ')) { - optional_ui = ui; - break; - } - - if (usage_str[ui] == '\0') - break; - - if (usage_str[ui] == '(') { - buf[bi++] = '\n'; - buf[bi++] = '\t'; - } - - buf[bi++] = usage_str[ui]; - - if (usage_str[ui] == ')') { - buf[bi++] = '\n'; - buf[bi++] = '\t'; - } - - if (usage_str[ui] == ',') { - buf[bi++] = '\n'; - buf[bi++] = '\t'; - buf[bi++] = ' '; - } - - if (bi == (HELP_LINE_SIZE - 1)) - break; - } - - /* - * print the required opt_args/pos_args - */ - - if (bi) - log_print("%s", buf); - - if (only_required) - return; - - /* - * copy the optional opt_args - */ - - if (!optional_ui) - goto out; - - memset(buf, 0, sizeof(buf)); - bi = 0; - - for (ui = optional_ui; ui < strlen(usage_str); ui++) { - - /* The second "[ " indicates the start of the optional pos_args. */ - if ((ui > optional_ui) && (usage_str[ui] == '[') && (usage_str[ui+1] == ' ')) { - optional_pos_ui = ui; - break; - } - - if (usage_str[ui] == '\0') - break; - if (usage_str[ui] == '\n') - break; - - if (!bi) - buf[bi++] = '\t'; - - buf[bi++] = usage_str[ui]; - - if (usage_str[ui] == ',') { - buf[bi++] = '\n'; - buf[bi++] = '\t'; - buf[bi++] = ' '; - } - - if (bi == (HELP_LINE_SIZE - 1)) - break; - } - - /* - * print the optional opt_args - */ - - if (bi) - log_print("%s", buf); - - /* - * copy the optional pos_args - */ - - if (!optional_pos_ui) - goto out; - - memset(buf, 0, sizeof(buf)); - bi = 0; - - for (ui = optional_pos_ui; ui < strlen(usage_str); ui++) { - if (usage_str[ui] == '\0') - break; - if (usage_str[ui] == '\n') - break; - - if (!bi) - buf[bi++] = '\t'; - - buf[bi++] = usage_str[ui]; - - if (bi == (HELP_LINE_SIZE - 1)) - break; - } - - /* - * print the optional pos_args - */ - - if (bi) - log_print("%s", buf); - out: - return; -} - -static void _print_description(int ci) -{ - const char *desc = _cmdline.commands[ci].desc; - char buf[HELP_LINE_SIZE] = {0}; - int di = 0; - int bi = 0; - - for (di = 0; di < strlen(desc); di++) { - if (!strncmp(&desc[di], "DESC:", 5)) { - if (bi) { - buf[bi] = '\0'; - log_print("%s", buf); - memset(buf, 0, sizeof(buf)); - bi = 0; - } - /* skip DESC: */ - di += 5; - continue; - } - - if (!bi && desc[di] == ' ') - continue; - - buf[bi++] = desc[di]; - - if (bi == (HELP_LINE_SIZE - 1)) - break; - } - - if (bi) { - buf[bi] = '\0'; - log_print("%s", buf); - } -} - /* * Match what the user typed with a one specific command definition/prototype * from commands[]. If nothing matches, it's not a valid command. The match @@ -1683,7 +1504,7 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path, log_error("Failed to find a matching command definition."); if (close_ro) { log_warn("Closest command usage is:"); - _print_usage(_cmdline.commands[close_i].usage, 1); + print_usage(&_cmdline.commands[close_i]); } return NULL; } @@ -1698,8 +1519,7 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path, if (best_unused_count) { for (i = 0; i < best_unused_count; i++) { - log_error("Invalid option for command (%s %d): %s.", - commands[best_i].command_line_id, best_i, + log_error("Invalid option for command: %s.", arg_long_option_name(best_unused_options[i])); } return NULL; @@ -1729,8 +1549,7 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path, break; if (count >= (commands[best_i].rp_count + commands[best_i].op_count)) { - log_error("Invalid positional argument for command (%s %d): %s.", - commands[best_i].command_line_id, best_i, argv[count]); + log_error("Invalid positional argument for command: %s.", argv[count]); /* FIXME: to warn/ignore, clear so it can't be used when processing. */ /* @@ -1774,22 +1593,21 @@ out: if (opts_match_count && (rule->rule == RULE_INVALID)) { memset(buf, 0, sizeof(buf)); opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf)); - log_error("Invalid options for command (%s %d): %s", - commands[best_i].command_line_id, best_i, buf); + log_error("Invalid options for command: %s", buf); return NULL; } if (opts_unmatch_count && (rule->rule == RULE_REQUIRE)) { memset(buf, 0, sizeof(buf)); opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf)); - log_error("Required options for command (%s %d): %s", - commands[best_i].command_line_id, best_i, buf); + log_error("Required options for command: %s", buf); return NULL; } } } - log_debug("command line id: %s %d", commands[best_i].command_line_id, best_i); + log_debug("Using command index %d id %s enum %d.", + best_i, commands[best_i].command_id, commands[best_i].command_enum); return &commands[best_i]; } @@ -1801,8 +1619,8 @@ static void _short_usage(const char *name) static int _usage(const char *name, int help_count) { - struct command_name *cname = _find_command_name(name); - const char *usage_common = NULL; + struct command_name *cname = find_command_name(name); + struct command *cmd; int i; if (!cname) { @@ -1812,28 +1630,20 @@ static int _usage(const char *name, int help_count) log_print("%s - %s\n", name, cname->desc); - for (i = 0; i < _cmdline.num_commands; i++) { + for (i = 0; i < COMMAND_COUNT; i++) { if (strcmp(_cmdline.commands[i].name, name)) continue; if ((_cmdline.commands[i].cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && (help_count < 3)) continue; - if (strlen(_cmdline.commands[i].desc)) - _print_description(i); - - usage_common = _cmdline.commands[i].usage_common; - - _print_usage(_cmdline.commands[i].usage, 0); - log_print(" "); /* for built-in \n */ + print_usage(&_cmdline.commands[i]); + cmd = &_cmdline.commands[i]; + printf("\n"); } /* Common options are printed once for all variants of a command name. */ - if (usage_common) { - log_print("Common options:"); - _print_usage(usage_common, 0); - log_print(" "); /* for built-in \n */ - } + print_usage_common(cname, cmd); if (help_count > 1) { /* @@ -1957,7 +1767,7 @@ static int _find_arg(const char *cmd_name, int goval) int arg_enum; int i; - if (!(cname = _find_command_name(cmd_name))) + if (!(cname = find_command_name(cmd_name))) return -1; for (i = 0; i < cname->num_args; i++) { @@ -1989,7 +1799,7 @@ static int _process_command_line(struct cmd_context *cmd, int *argc, char ***arg int goval; /* the number returned from getopt_long identifying what it found */ int i; - if (!(cname = _find_command_name(cmd->name))) + if (!(cname = find_command_name(cmd->name))) return_0; if (!(cmd->opt_arg_values = dm_pool_zalloc(cmd->mem, sizeof(*cmd->opt_arg_values) * ARG_COUNT))) { @@ -2686,7 +2496,7 @@ 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))) { + if (!(cmd->cname = find_command_name(cmd->name))) { log_error("Command name not found.\n"); return EINVALID_CMD_LINE; } @@ -2857,7 +2667,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) } if (cmd->command->functions) - /* A command-line--specific function is used */ + /* A command-line-specific function is used */ ret = cmd->command->functions->fn(cmd, argc, argv); else /* The old style command-name function is used */ @@ -3388,3 +3198,4 @@ int lvm2_main(int argc, char **argv) lvm_fin(cmd); return lvm_return_code(ret); } + diff --git a/tools/toollib.c b/tools/toollib.c index 2c0096fbd..3b479894b 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -2692,8 +2692,8 @@ static int _check_lv_types(struct cmd_context *cmd, struct logical_volume *lv, i return 1; if (!val_bit_is_set(cmd->command->required_pos_args[pos-1].def.val_bits, lv_VAL)) { - log_error(INTERNAL_ERROR "Command (%s %d) arg position %d does not permit an LV (%llx)", - cmd->command->command_line_id, cmd->command->command_line_enum, + log_error(INTERNAL_ERROR "Command %d:%s arg position %d does not permit an LV (%llx)", + cmd->command->command_index, cmd->command->command_id, pos, (unsigned long long)cmd->command->required_pos_args[pos-1].def.val_bits); return 0; } @@ -3109,9 +3109,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, if (!_check_lv_types(cmd, lvl->lv, lv_arg_pos)) { /* FIXME: include this result in report log? */ if (lv_is_named_arg) { - log_error("Operation not permitted (%s %d) on LV %s.", - cmd->command->command_line_id, cmd->command->command_line_enum, - display_lvname(lvl->lv)); + log_error("Operation not permitted on LV %s.", display_lvname(lvl->lv)); ret_max = ECMD_FAILED; } continue; @@ -3120,9 +3118,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, if (!_check_lv_rules(cmd, lvl->lv)) { /* FIXME: include this result in report log? */ if (lv_is_named_arg) { - log_error("Operation not permitted (%s %d) on LV %s.", - cmd->command->command_line_id, cmd->command->command_line_enum, - display_lvname(lvl->lv)); + log_error("Operation not permitted on LV %s.", display_lvname(lvl->lv)); ret_max = ECMD_FAILED; } continue; diff --git a/tools/tools.h b/tools/tools.h index 392490f6b..4e1d87f01 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -50,6 +50,13 @@ #define CMD_LEN 256 #define MAX_ARGS 64 +/* define the enums for each unique ID in command defs in command-lines.in */ +enum { +#define cmd(a, b) a , +#include "cmds.h" +#undef cmd +}; + /* define the enums for the values accepted by command line --options, foo_VAL */ enum { #define val(a, b, c, d) a , @@ -84,6 +91,7 @@ enum { }; #include "command.h" +#include "command-count.h" #define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */ #define ARG_GROUPABLE 0x00000002 /* E.g. --addtag */