1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

command: refactor to use const command structure

Refactor code so the definitions may become 'static const'
and with configure_command_option_values() we update options
val_enum for actually running command option when used.

Also update _update_relative_opt() which is used for
generating man pages and command help.

Introduce enumeration for lvm2 commands - so we may
use enum cmd_COMMAND instead of string checking.

So running command now does not modified opt_names.
This commit is contained in:
Zdenek Kabelac 2024-05-01 14:36:28 +02:00
parent 0b064aedb3
commit b4670db008
5 changed files with 106 additions and 83 deletions

View File

@ -47,7 +47,7 @@ static const struct val_name val_names[VAL_COUNT + 1] = {
/* create table of option names, e.g. --foo, and corresponding enum from args.h */ /* create table of option names, e.g. --foo, and corresponding enum from args.h */
static struct opt_name opt_names[ARG_COUNT + 1] = { static const struct opt_name opt_names[ARG_COUNT + 1] = {
#define arg(a, b, c, d, e, f, g) { # a, b, a, "--" c, d, e, f, g }, #define arg(a, b, c, d, e, f, g) { # a, b, a, "--" c, d, e, f, g },
#include "args.h" #include "args.h"
#undef arg #undef arg
@ -85,7 +85,7 @@ static const struct cmd_name cmd_names[CMD_COUNT + 1] = {
#ifdef MAN_PAGE_GENERATOR #ifdef MAN_PAGE_GENERATOR
static struct command_name command_names[] = { static struct command_name command_names[] = {
#define xx(a, b, c...) { # a, b, c }, #define xx(a, b, c...) { # a, b, c, NULL, a ## _COMMAND },
#include "commands.h" #include "commands.h"
#undef xx #undef xx
{ .name = NULL } { .name = NULL }
@ -95,7 +95,7 @@ static struct command commands[COMMAND_COUNT];
#else /* MAN_PAGE_GENERATOR */ #else /* MAN_PAGE_GENERATOR */
struct command_name command_names[] = { struct command_name command_names[] = {
#define xx(a, b, c...) { # a, b, c, a}, #define xx(a, b, c...) { # a, b, c, a, a ## _COMMAND },
#include "commands.h" #include "commands.h"
#undef xx #undef xx
{ .name = NULL } { .name = NULL }
@ -130,7 +130,7 @@ const struct lv_type *get_lv_type(int lvt_enum)
/* array of pointers into opt_names[] that is sorted alphabetically (by long opt name) */ /* array of pointers into opt_names[] that is sorted alphabetically (by long opt name) */
static struct opt_name *opt_names_alpha[ARG_COUNT + 1]; static const struct opt_name *opt_names_alpha[ARG_COUNT + 1];
/* lvm_all is for recording options that are common for all lvm commands */ /* lvm_all is for recording options that are common for all lvm commands */
@ -1517,6 +1517,7 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
return 1; return 1;
} }
#ifndef MAN_PAGE_GENERATOR
/* /*
* The opt_names[] table describes each option. It is indexed by the * The opt_names[] table describes each option. It is indexed by the
* option typedef, e.g. size_ARG. The size_ARG entry specifies the * option typedef, e.g. size_ARG. The size_ARG entry specifies the
@ -1533,8 +1534,10 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
* (they are created at build time), but different commands accept different * (they are created at build time), but different commands accept different
* types of values for the same option, e.g. one command will accept * types of values for the same option, e.g. one command will accept
* signed size values (ssizemb_VAL), while another does not accept a signed * signed size values (ssizemb_VAL), while another does not accept a signed
* number, (sizemb_VAL). This function deals with this problem by tweaking * number, (sizemb_VAL).
* the opt_names[] table at run time according to the specific command being run. *
* To resolve the issue, at run time command 'reconfigures' its opt_names[]
* values by querying particular arg_enum for particular command.
* i.e. it changes size_ARG to accept sizemb_VAL or ssizemb_VAL depending * i.e. it changes size_ARG to accept sizemb_VAL or ssizemb_VAL depending
* on the command. * on the command.
* *
@ -1558,53 +1561,57 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
* so the commands[] entry for the cmd def already references the * so the commands[] entry for the cmd def already references the
* correct ssizemb_VAL. * correct ssizemb_VAL.
*/ */
void configure_command_option_values(const char *name) int configure_command_option_values(const struct command_name *cname, int arg_enum, int val_enum)
{ {
if (!strcmp(name, "lvresize")) { switch (cname->lvm_command_enum) {
/* relative +|- allowed for LV, + allowed for metadata */ case lvconvert_COMMAND:
opt_names[size_ARG].val_enum = ssizemb_VAL; switch (arg_enum) {
opt_names[extents_ARG].val_enum = sextents_VAL; case mirrors_ARG: return snumber_VAL;
opt_names[poolmetadatasize_ARG].val_enum = psizemb_VAL; }
return; break;
} case lvcreate_COMMAND:
if (!strcmp(name, "lvextend")) {
/* relative + allowed */
opt_names[size_ARG].val_enum = psizemb_VAL;
opt_names[extents_ARG].val_enum = pextents_VAL;
opt_names[poolmetadatasize_ARG].val_enum = psizemb_VAL;
return;
}
if (!strcmp(name, "lvreduce")) {
/* relative - allowed */
opt_names[size_ARG].val_enum = nsizemb_VAL;
opt_names[extents_ARG].val_enum = nextents_VAL;
return;
}
if (!strcmp(name, "lvconvert")) {
opt_names[mirrors_ARG].val_enum = snumber_VAL;
return;
}
if (!strcmp(name, "lvcreate")) {
/* /*
* lvcreate is a bit of a mess because it has previously * lvcreate is accepts also sizes with + (positive) value,
* accepted + but used it as an absolute value, so we * so we have to recognize it. But we don't want to show
* have to recognize it. (We don't want to show the + * the + option in man/help as it can be seen confusing,
* option in man/help, though, since it's confusing,
* so there's a special case when printing man/help * so there's a special case when printing man/help
* output to show sizemb_VAL/extents_VAL rather than * output to show sizemb_VAL/extents_VAL rather than
* psizemb_VAL/pextents_VAL.) * psizemb_VAL/pextents_VAL.)
*/ */
opt_names[size_ARG].val_enum = psizemb_VAL; switch (arg_enum) {
opt_names[extents_ARG].val_enum = pextents_VAL; case size_ARG: return psizemb_VAL;
opt_names[poolmetadatasize_ARG].val_enum = psizemb_VAL; case extents_ARG: return pextents_VAL;
opt_names[mirrors_ARG].val_enum = pnumber_VAL; case poolmetadatasize_ARG: return psizemb_VAL;
return; case mirrors_ARG: return pnumber_VAL;
}
break;
case lvextend_COMMAND:
/* relative + allowed */
switch (arg_enum) {
case size_ARG: return psizemb_VAL;
case extents_ARG: return pextents_VAL;
case poolmetadatasize_ARG: return psizemb_VAL;
}
break;
case lvreduce_COMMAND:
/* relative - allowed */
switch (arg_enum) {
case size_ARG: return nsizemb_VAL;
case extents_ARG: return nextents_VAL;
}
break;
case lvresize_COMMAND:
switch (arg_enum) {
case size_ARG: return ssizemb_VAL;
case extents_ARG: return sextents_VAL;
case poolmetadatasize_ARG: return psizemb_VAL;
}
break;
} }
return val_enum;
} }
#endif
/* type_LVT to "type" */ /* type_LVT to "type" */
@ -1644,38 +1651,49 @@ static void _print_usage_description(struct command *cmd)
} }
} }
static void _update_relative_opt(const char *name, int opt_enum, int *val_enum) /* Function remappas existing command definitions val_enums for printing
* within man pages or command's help lines */
static int _update_relative_opt(const char *name, int opt_enum, int val_enum)
{ {
/* check for relative sign */ /* check for relative sign */
switch (opt_enum) { if (!strcmp(name, "lvconvert"))
case extents_ARG: switch (opt_enum) {
case mirrors_ARG: case mirrors_ARG: return snumber_VAL;
case poolmetadatasize_ARG: }
case size_ARG: else if (!strcmp(name, "lvcreate"))
/* /*
* Suppress the [+] prefix for lvcreate which we have to * Suppress the [+] prefix for lvcreate which we have to
* accept for backwards compat, but don't want to advertise. * accept for backwards compat, but don't want to advertise.
* 'command-lines.in' currently uses PNumber in definition
*/ */
if (!strcmp(name, "lvcreate")) { switch (opt_enum) {
switch (*val_enum) { case mirrors_ARG: return number_VAL;
case psizemb_VAL:
*val_enum = sizemb_VAL;
break;
case pextents_VAL:
*val_enum = extents_VAL;
break;
case pnumber_VAL:
if (opt_enum == mirrors_ARG)
*val_enum = number_VAL;
break;
}
} }
} else if (!strcmp(name, "lvextend"))
switch (opt_enum) {
case extents_ARG: return pextents_VAL;
case poolmetadatasize_ARG:
case size_ARG: return psizemb_VAL;
}
else if (!strcmp(name, "lvreduce"))
switch (opt_enum) {
case extents_ARG: return nextents_VAL;
case poolmetadatasize_ARG:
case size_ARG: return nsizemb_VAL;
}
else if (!strcmp(name, "lvresize"))
switch (opt_enum) {
case extents_ARG: return sextents_VAL;
case poolmetadatasize_ARG:
case size_ARG: return ssizemb_VAL;
}
return val_enum;
} }
static void _print_val_usage(struct command *cmd, int opt_enum, int val_enum) static void _print_val_usage(struct command *cmd, int opt_enum, int val_enum)
{ {
_update_relative_opt(cmd->name, opt_enum, &val_enum); val_enum = _update_relative_opt(cmd->name, opt_enum, val_enum);
if (!val_names[val_enum].usage) if (!val_names[val_enum].usage)
printf("%s", val_names[val_enum].name); printf("%s", val_names[val_enum].name);

View File

@ -35,6 +35,7 @@ struct command_name {
const char *desc; /* general command description from commands.h */ const char *desc; /* general command description from commands.h */
unsigned int flags; unsigned int flags;
command_fn fn; /* old style */ command_fn fn; /* old style */
uint16_t lvm_command_enum; /* as declared in commands.h with _COMMAND */
/* union of {required,optional}_opt_args for all commands with this name */ /* union of {required,optional}_opt_args for all commands with this name */
uint16_t valid_args[ARG_COUNT]; /* used for getopt */ uint16_t valid_args[ARG_COUNT]; /* used for getopt */
@ -274,7 +275,7 @@ void print_usage_common_lvm(const struct command_name *cname, struct command *cm
void print_usage_notes(const struct command_name *cname); void print_usage_notes(const struct command_name *cname);
void factor_common_options(void); void factor_common_options(void);
int command_has_alternate_extents(const char *name); int command_has_alternate_extents(const char *name);
void configure_command_option_values(const char *name); int configure_command_option_values(const struct command_name *cname, int arg_enum, int val_enum);
const struct command_name *find_command_name(const char *name); const struct command_name *find_command_name(const char *name);
#endif #endif

View File

@ -49,6 +49,13 @@ enum {
#undef lvt #undef lvt
}; };
enum {
#define xx(a, b...) a ## _COMMAND,
#include "commands.h"
#undef xx
LVM_COMMAND_COUNT
};
#define PERMITTED_READ_ONLY 0x00000002 #define PERMITTED_READ_ONLY 0x00000002
/* Process all VGs if none specified on the command line. */ /* Process all VGs if none specified on the command line. */
#define ALL_VGS_IS_DEFAULT 0x00000004 #define ALL_VGS_IS_DEFAULT 0x00000004

View File

@ -2021,8 +2021,6 @@ static int _usage(const char *name, int longhelp, int skip_notes)
return 0; return 0;
} }
configure_command_option_values(name);
/* /*
* Looks at all variants of each command name and figures out * Looks at all variants of each command name and figures out
* which options are common to all variants (for compact output) * which options are common to all variants (for compact output)
@ -2200,6 +2198,7 @@ static int _process_command_line(struct cmd_context *cmd, int *argc, char ***arg
struct arg_values *av; struct arg_values *av;
struct arg_value_group_list *current_group = NULL; struct arg_value_group_list *current_group = NULL;
int arg_enum; /* e.g. foo_ARG */ int arg_enum; /* e.g. foo_ARG */
int val_enum;
int goval; /* the number returned from getopt_long identifying what it found */ int goval; /* the number returned from getopt_long identifying what it found */
int i; int i;
@ -2291,8 +2290,8 @@ static int _process_command_line(struct cmd_context *cmd, int *argc, char ***arg
} }
av->value = optarg; av->value = optarg;
val_enum = configure_command_option_values(cmd->cname, arg_enum, a->val_enum);
if (!get_val_name(a->val_enum)->fn(cmd, av)) { if (!get_val_name(val_enum)->fn(cmd, av)) {
log_error("Invalid argument for %s: %s", a->long_opt, optarg); log_error("Invalid argument for %s: %s", a->long_opt, optarg);
return 0; return 0;
} }
@ -3072,8 +3071,6 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
init_log_command(find_config_tree_bool(cmd, log_command_names_CFG, NULL), 0); init_log_command(find_config_tree_bool(cmd, log_command_names_CFG, NULL), 0);
configure_command_option_values(cmd->name);
/* eliminate '-' from all options starting with -- */ /* eliminate '-' from all options starting with -- */
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {

View File

@ -119,6 +119,10 @@ static const char *_lvt_enum_to_name(int lvt_enum)
return lv_types[lvt_enum].name; return lv_types[lvt_enum].name;
} }
static int _get_val_enum(const struct command_name *cname, int opt_enum)
{
return _update_relative_opt(cname->name, opt_enum, opt_names[opt_enum].val_enum);
}
/* /*
* FIXME: this just replicates the val usage strings * FIXME: this just replicates the val usage strings
* that officially lives in vals.h. Should there * that officially lives in vals.h. Should there
@ -137,8 +141,6 @@ static void _print_val_man(const struct command_name *cname, int opt_enum, int v
_was_hyphen = 0; _was_hyphen = 0;
_update_relative_opt(cname->name, opt_enum, &val_enum);
switch (val_enum) { switch (val_enum) {
case sizemb_VAL: case sizemb_VAL:
printf("\\fISize\\fP[m|UNIT]"); printf("\\fISize\\fP[m|UNIT]");
@ -232,7 +234,7 @@ static void _print_val_man(const struct command_name *cname, int opt_enum, int v
static void _print_def_man(const struct command_name *cname, int opt_enum, struct arg_def *def, int usage, uint64_t *lv_type_bits) static void _print_def_man(const struct command_name *cname, int opt_enum, struct arg_def *def, int usage, uint64_t *lv_type_bits)
{ {
int val_enum; int val_enum, tmp_val;
int sep = 0; int sep = 0;
if (lv_type_bits) if (lv_type_bits)
@ -264,7 +266,8 @@ static void _print_def_man(const struct command_name *cname, int opt_enum, struc
printf("\\fI%s\\fP", val_names[val_enum].name); printf("\\fI%s\\fP", val_names[val_enum].name);
} }
} else { } else {
_print_val_man(cname, opt_enum, val_enum); tmp_val = _update_relative_opt(cname->name, opt_enum, val_enum);
_print_val_man(cname, opt_enum, tmp_val);
} }
sep = 1; sep = 1;
@ -577,7 +580,7 @@ static void _print_man_usage(char *lvmname, struct command *cmd)
* in opt_names[] according to the command name. * in opt_names[] according to the command name.
*/ */
printf("[ \\fB-l\\fP|\\fB--extents\\fP "); printf("[ \\fB-l\\fP|\\fB--extents\\fP ");
_print_val_man(cname, extents_ARG, opt_names[extents_ARG].val_enum); _print_val_man(cname, extents_ARG, _get_val_enum(cname, extents_ARG));
printf_hyphen(']'); printf_hyphen(']');
sep = 1; sep = 1;
@ -1020,7 +1023,7 @@ static void _print_man_all_options_list(const struct command_name *cname)
printf(" \\fB%s\\fP", _man_long_opt_name(cname->name, opt_enum)); printf(" \\fB%s\\fP", _man_long_opt_name(cname->name, opt_enum));
} }
val_enum = opt_names[opt_enum].val_enum; val_enum = _get_val_enum(cname, opt_enum);
if (!val_names[val_enum].fn) { if (!val_names[val_enum].fn) {
/* takes no arg */ /* takes no arg */
@ -1059,7 +1062,7 @@ static void _print_man_all_options_desc(const struct command_name *cname)
if (!cname->all_options[opt_enum]) if (!cname->all_options[opt_enum])
continue; continue;
val_enum = opt_names[opt_enum].val_enum; val_enum = _get_val_enum(cname, opt_enum);
if (val_names[val_enum].usage && if (val_names[val_enum].usage &&
(strlen(val_names[val_enum].usage) > _LONG_LINE)) { (strlen(val_names[val_enum].usage) > _LONG_LINE)) {
@ -1781,9 +1784,6 @@ int main(int argc, char *argv[])
if (!define_commands(&cmdtool, NULL)) if (!define_commands(&cmdtool, NULL))
goto out_free; goto out_free;
if (!check)
configure_command_option_values(cmdname);
factor_common_options(); factor_common_options();
if (primary && cmdname) if (primary && cmdname)