From 0dfb3028c433aecd63335513bf36b92f4b72e731 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 07:50:40 +0000 Subject: [PATCH 01/11] Allow global options before subcommand; split help text into sections --- nvme.c | 13 ++++- nvme.h | 13 ++++- util/argconfig.c | 139 +++++++++++++++++++++++++++++++++++++++++------ util/argconfig.h | 6 ++ 4 files changed, 151 insertions(+), 20 deletions(-) diff --git a/nvme.c b/nvme.c index 6a8350b9ab..a6026f20fd 100644 --- a/nvme.c +++ b/nvme.c @@ -11383,7 +11383,18 @@ int main(int argc, char **argv) if (err) return err; - err = handle_plugin(argc - 1, &argv[1], nvme.extensions); + /* + * Parse any global options that appear before the subcommand so that + * e.g. `alias nvme="nvme -v"; nvme list` works correctly instead of + * treating "-v" as an unknown subcommand. After this call optind + * points to the first non-option argument (the subcommand name). + */ + NVME_ARGS(global_opts); + err = argconfig_parse_global(argc, argv, global_opts); + if (err) + return 1; + + err = handle_plugin(argc - optind, &argv[optind], nvme.extensions); if (err == -ENOTTY) general_help(&builtin, NULL); diff --git a/nvme.h b/nvme.h index c3a7003317..2f96087263 100644 --- a/nvme.h +++ b/nvme.h @@ -69,16 +69,23 @@ struct nvme_args { #endif /* CONFIG_JSONC */ /* - * the ordering of the arguments matters, as the argument parser uses the first match, thus any - * command which defines -t shorthand will match first. + * Global options are placed after a OPT_GROUP separator so they appear in a + * dedicated "Global options" section in help output. Command-specific options + * (##__VA_ARGS__) are placed first so that their short-option bindings take + * precedence over the global ones when both share the same letter (e.g. some + * plugins use -v for "value"). The leading OPT_GROUP("Options") entry exists + * solely to allow GCC's ##__VA_ARGS__ comma deletion to work correctly when no + * command-specific options are present. */ #define NVME_ARGS(n, ...) \ struct argconfig_commandline_options n[] = { \ + OPT_GROUP("Options"), \ + ##__VA_ARGS__, \ + OPT_GROUP("Global options"), \ OPT_INCR("verbose", 'v', &nvme_args.verbose, \ "Increase output verbosity"), \ OPT_FMT("output-format", 'o', &nvme_args.output_format, \ DESC_OUTPUT_FORMAT), \ - ##__VA_ARGS__, \ OPT_UINT("timeout", 0, &nvme_args.timeout, \ "timeout value, in milliseconds"), \ OPT_FLAG("dry-run", 0, &nvme_args.dry_run, \ diff --git a/util/argconfig.c b/util/argconfig.c index 5e74548270..48b364f918 100644 --- a/util/argconfig.c +++ b/util/argconfig.c @@ -129,6 +129,9 @@ static void show_option(const struct argconfig_commandline_options *option) void argconfig_print_help(const char *program_desc, struct argconfig_commandline_options *s) { + const char *pending_header = "Options"; + bool header_printed = false; + fprintf(stderr, "\033[1mUsage: %s\033[0m\n\n", append_usage_str); @@ -138,9 +141,18 @@ void argconfig_print_help(const char *program_desc, if (!s || !s->option) return; - fprintf(stderr, "\n\033[1mOptions:\033[0m\n"); - for (; s->option; s++) + for (; s->option; s++) { + if (s->config_type == CFG_GROUP_SEPARATOR) { + pending_header = s->help; + header_printed = false; + continue; + } + if (!header_printed) { + fprintf(stderr, "\n\033[1m%s:\033[0m\n", pending_header); + header_printed = true; + } show_option(s); + } } static int argconfig_error(char *type, const char *opt, const char *arg) @@ -214,6 +226,8 @@ static int argconfig_parse_type(struct argconfig_commandline_options *s) case CFG_FLAG: *(bool *)value = true; break; + case CFG_GROUP_SEPARATOR: + break; } return ret; @@ -252,6 +266,8 @@ static void argconfig_set_opt_val(enum argconfig_types type, union argconfig_val case CFG_STRING: *(char **)val = opt_val->string; break; + case CFG_GROUP_SEPARATOR: + break; } } @@ -305,8 +321,9 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, { __cleanup_free char *short_opts = NULL; __cleanup_free struct option *long_opts = NULL; + __cleanup_free int *long_opt_map = NULL; struct argconfig_commandline_options *s; - int c, option_index = 0, short_index = 0, options_count = 0; + int c, lo_index = 0, opt_index = 0, short_index = 0, options_count = 0; int ret = 0; errno = 0; @@ -315,13 +332,17 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, long_opts = calloc(options_count + 2, sizeof(struct option)); short_opts = calloc(options_count * 3 + 3, sizeof(*short_opts)); + long_opt_map = calloc(options_count + 2, sizeof(*long_opt_map)); - if (!long_opts || !short_opts) { + if (!long_opts || !short_opts || !long_opt_map) { fprintf(stderr, "failed to allocate memory for opts: %s\n", libnvme_strerror(errno)); return -errno; } - for (s = options; s->option; s++) { + for (s = options, opt_index = 0; s->option; s++, opt_index++) { + s->seen = false; + if (s->config_type == CFG_GROUP_SEPARATOR) + continue; if (s->short_option) { short_opts[short_index++] = s->short_option; if (s->argument_type == required_argument || @@ -331,36 +352,38 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, short_opts[short_index++] = ':'; } if (!is_null_or_empty(s->option)) { - long_opts[option_index].name = s->option; - long_opts[option_index].has_arg = s->argument_type; + long_opts[lo_index].name = s->option; + long_opts[lo_index].has_arg = s->argument_type; + long_opt_map[lo_index] = opt_index; + lo_index++; } - s->seen = false; - option_index++; } - long_opts[option_index].name = "help"; - long_opts[option_index].val = 'h'; + long_opts[lo_index].name = "help"; + long_opts[lo_index].val = 'h'; short_opts[short_index++] = '?'; short_opts[short_index] = 'h'; optind = 0; - while ((c = getopt_long_only(argc, argv, short_opts, long_opts, &option_index)) != -1) { + while ((c = getopt_long_only(argc, argv, short_opts, long_opts, &lo_index)) != -1) { if (c) { if (c == '?' || c == 'h') { argconfig_print_help(program_desc, options); ret = -EINVAL; break; } - for (option_index = 0; option_index < options_count; option_index++) { - if (c == options[option_index].short_option) + for (opt_index = 0; opt_index < options_count; opt_index++) { + if (c == options[opt_index].short_option) break; } - if (option_index == options_count) + if (opt_index == options_count) continue; + } else { + opt_index = long_opt_map[lo_index]; } - s = &options[option_index]; + s = &options[opt_index]; s->seen = true; if (!s->default_value) @@ -377,6 +400,90 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, return ret; } +/* + * Parse global (pre-subcommand) options from argc/argv. Stops at the first + * non-option argument (i.e. the subcommand name) so that subcommand-specific + * options are left in place for the subcommand dispatcher. After a successful + * call, optind points to the first non-option argument (the subcommand). + * + * Returns 0 on success, negative errno on failure. + */ +int argconfig_parse_global(int argc, char *argv[], + struct argconfig_commandline_options *options) +{ + __cleanup_free char *short_opts = NULL; + __cleanup_free struct option *long_opts = NULL; + __cleanup_free int *long_opt_map = NULL; + struct argconfig_commandline_options *s; + int c, lo_index = 0, opt_index = 0, short_index = 0, options_count = 0; + int ret = 0; + + errno = 0; + for (s = options; s->option; s++) + options_count++; + + long_opts = calloc(options_count + 2, sizeof(struct option)); + /* '+' prefix: stop at the first non-option argument (the subcommand) */ + short_opts = calloc(options_count * 3 + 4, sizeof(*short_opts)); + long_opt_map = calloc(options_count + 2, sizeof(*long_opt_map)); + + if (!long_opts || !short_opts || !long_opt_map) { + fprintf(stderr, "failed to allocate memory for opts: %s\n", libnvme_strerror(errno)); + return -errno; + } + + short_opts[short_index++] = '+'; + + for (s = options, opt_index = 0; s->option; s++, opt_index++) { + s->seen = false; + if (s->config_type == CFG_GROUP_SEPARATOR) + continue; + if (s->short_option) { + short_opts[short_index++] = s->short_option; + if (s->argument_type == required_argument || + s->argument_type == optional_argument) + short_opts[short_index++] = ':'; + if (s->argument_type == optional_argument) + short_opts[short_index++] = ':'; + } + if (!is_null_or_empty(s->option)) { + long_opts[lo_index].name = s->option; + long_opts[lo_index].has_arg = s->argument_type; + long_opt_map[lo_index] = opt_index; + lo_index++; + } + } + + optind = 0; + while ((c = getopt_long(argc, argv, short_opts, long_opts, &lo_index)) != -1) { + if (c == '?' || c == 'h') + break; + + if (c) { + for (opt_index = 0; opt_index < options_count; opt_index++) { + if (c == options[opt_index].short_option) + break; + } + if (opt_index == options_count) + continue; + } else { + opt_index = long_opt_map[lo_index]; + } + + s = &options[opt_index]; + s->seen = true; + + if (!s->default_value) + continue; + + ret = argconfig_parse_val(s); + if (ret) + break; + } + + return ret; +} + #define DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(name, ret_t, ret_max) \ int argconfig_parse_comma_sep_array ## name(char *string, \ ret_t *val, \ diff --git a/util/argconfig.h b/util/argconfig.h index f27a20b3f6..407c703a92 100644 --- a/util/argconfig.h +++ b/util/argconfig.h @@ -54,6 +54,7 @@ enum argconfig_types { CFG_SHORT, CFG_POSITIVE, CFG_INCREMENT, + CFG_GROUP_SEPARATOR, }; #define OPT_ARGS(n) \ @@ -61,6 +62,9 @@ enum argconfig_types { #define OPT_END() { NULL } +#define OPT_GROUP(d) \ + {"", 0, NULL, CFG_GROUP_SEPARATOR, NULL, no_argument, d, false, NULL} + #define OPT_FLAG(l, s, v, d, ...) \ {l, s, NULL, CFG_FLAG, v, no_argument, d, false, __VA_ARGS__} @@ -175,6 +179,8 @@ void argconfig_print_help(const char *program_desc, struct argconfig_commandline_options *options); int argconfig_parse(int argc, char *argv[], const char *program_desc, struct argconfig_commandline_options *options); +int argconfig_parse_global(int argc, char *argv[], + struct argconfig_commandline_options *options); int argconfig_parse_comma_sep_array(char *string, int *ret, unsigned int max_length); int argconfig_parse_comma_sep_array_short(char *string, unsigned short *ret, unsigned int max_length); From 4e700e1cf2e5fb113565fc069166dd2710505da6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 07:53:52 +0000 Subject: [PATCH 02/11] Address code review: rename lo_index, clarify comments --- nvme.h | 10 ++++++---- util/argconfig.c | 37 +++++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/nvme.h b/nvme.h index 2f96087263..110d7a3f88 100644 --- a/nvme.h +++ b/nvme.h @@ -69,13 +69,15 @@ struct nvme_args { #endif /* CONFIG_JSONC */ /* - * Global options are placed after a OPT_GROUP separator so they appear in a + * Global options are placed after an OPT_GROUP separator so they appear in a * dedicated "Global options" section in help output. Command-specific options * (##__VA_ARGS__) are placed first so that their short-option bindings take * precedence over the global ones when both share the same letter (e.g. some - * plugins use -v for "value"). The leading OPT_GROUP("Options") entry exists - * solely to allow GCC's ##__VA_ARGS__ comma deletion to work correctly when no - * command-specific options are present. + * plugins use -v for "value"). The leading OPT_GROUP("Options") entry serves + * two purposes: it creates the "Options" section header for command-specific + * options in help output, and it allows GCC's ##__VA_ARGS__ comma deletion to + * work correctly when no command-specific options are present (the section + * header is then suppressed automatically because it has no following options). */ #define NVME_ARGS(n, ...) \ struct argconfig_commandline_options n[] = { \ diff --git a/util/argconfig.c b/util/argconfig.c index 48b364f918..2ce642d3e5 100644 --- a/util/argconfig.c +++ b/util/argconfig.c @@ -129,6 +129,11 @@ static void show_option(const struct argconfig_commandline_options *option) void argconfig_print_help(const char *program_desc, struct argconfig_commandline_options *s) { + /* + * Default section name used when options appear before the first + * OPT_GROUP separator. This fallback is not reached for NVME_ARGS() + * option arrays which always begin with an OPT_GROUP entry. + */ const char *pending_header = "Options"; bool header_printed = false; @@ -323,7 +328,7 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, __cleanup_free struct option *long_opts = NULL; __cleanup_free int *long_opt_map = NULL; struct argconfig_commandline_options *s; - int c, lo_index = 0, opt_index = 0, short_index = 0, options_count = 0; + int c, long_opt_index = 0, opt_index = 0, short_index = 0, options_count = 0; int ret = 0; errno = 0; @@ -352,21 +357,21 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, short_opts[short_index++] = ':'; } if (!is_null_or_empty(s->option)) { - long_opts[lo_index].name = s->option; - long_opts[lo_index].has_arg = s->argument_type; - long_opt_map[lo_index] = opt_index; - lo_index++; + long_opts[long_opt_index].name = s->option; + long_opts[long_opt_index].has_arg = s->argument_type; + long_opt_map[long_opt_index] = opt_index; + long_opt_index++; } } - long_opts[lo_index].name = "help"; - long_opts[lo_index].val = 'h'; + long_opts[long_opt_index].name = "help"; + long_opts[long_opt_index].val = 'h'; short_opts[short_index++] = '?'; short_opts[short_index] = 'h'; optind = 0; - while ((c = getopt_long_only(argc, argv, short_opts, long_opts, &lo_index)) != -1) { + while ((c = getopt_long_only(argc, argv, short_opts, long_opts, &long_opt_index)) != -1) { if (c) { if (c == '?' || c == 'h') { argconfig_print_help(program_desc, options); @@ -380,7 +385,7 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, if (opt_index == options_count) continue; } else { - opt_index = long_opt_map[lo_index]; + opt_index = long_opt_map[long_opt_index]; } s = &options[opt_index]; @@ -415,7 +420,7 @@ int argconfig_parse_global(int argc, char *argv[], __cleanup_free struct option *long_opts = NULL; __cleanup_free int *long_opt_map = NULL; struct argconfig_commandline_options *s; - int c, lo_index = 0, opt_index = 0, short_index = 0, options_count = 0; + int c, long_opt_index = 0, opt_index = 0, short_index = 0, options_count = 0; int ret = 0; errno = 0; @@ -447,15 +452,15 @@ int argconfig_parse_global(int argc, char *argv[], short_opts[short_index++] = ':'; } if (!is_null_or_empty(s->option)) { - long_opts[lo_index].name = s->option; - long_opts[lo_index].has_arg = s->argument_type; - long_opt_map[lo_index] = opt_index; - lo_index++; + long_opts[long_opt_index].name = s->option; + long_opts[long_opt_index].has_arg = s->argument_type; + long_opt_map[long_opt_index] = opt_index; + long_opt_index++; } } optind = 0; - while ((c = getopt_long(argc, argv, short_opts, long_opts, &lo_index)) != -1) { + while ((c = getopt_long(argc, argv, short_opts, long_opts, &long_opt_index)) != -1) { if (c == '?' || c == 'h') break; @@ -467,7 +472,7 @@ int argconfig_parse_global(int argc, char *argv[], if (opt_index == options_count) continue; } else { - opt_index = long_opt_map[lo_index]; + opt_index = long_opt_map[long_opt_index]; } s = &options[opt_index]; From fbe708b0a661d67dd5080f5af55bdddce3501de8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 13:03:16 +0000 Subject: [PATCH 03/11] fix: move global option parsing into handle_plugin The plugin parser uses its own NVME_ARGS opts array, so seen flags set during the global pre-parse in main() were not reflected in each command function's own opts. This meant that global options like --dry-run, --no-ioctl-probing, --verbose etc. were silently ignored when specified before the subcommand name. Fix by moving argconfig_parse_global() from main() into handle_plugin() so global options are stripped from argv at each dispatch level before the subcommand name is read. main() now simply passes argc-1/argv+1. Also replace all argconfig_parse_seen() calls for the four global options with direct reads of nvme_args.*: - dry-run -> nvme_args.dry_run - no-ioctl-probing -> nvme_args.no_ioctl_probing - timeout (seen check) -> removed; nvme_args.timeout != default suffices - verbose -> nvme_args.verbose (nvme.c x36, netapp plugin x2) --- nvme.c | 94 ++++++++++++++++-------------------- plugin.c | 15 +++++- plugins/netapp/netapp-nvme.c | 4 +- 3 files changed, 57 insertions(+), 56 deletions(-) diff --git a/nvme.c b/nvme.c index a6026f20fd..acb5a75aaa 100644 --- a/nvme.c +++ b/nvme.c @@ -358,9 +358,8 @@ static void setup_transport_handle(struct libnvme_global_ctx *ctx, libnvme_transport_handle_set_submit_entry(hdl, nvme_submit_entry); libnvme_transport_handle_set_submit_exit(hdl, nvme_submit_exit); libnvme_transport_handle_set_decide_retry(hdl, nvme_decide_retry); - libnvme_set_dry_run(ctx, argconfig_parse_seen(opts, "dry-run")); - if (nvme_args.timeout != NVME_DEFAULT_IOCTL_TIMEOUT || - argconfig_parse_seen(opts, "timeout")) + libnvme_set_dry_run(ctx, nvme_args.dry_run); + if (nvme_args.timeout != NVME_DEFAULT_IOCTL_TIMEOUT) libnvme_transport_handle_set_timeout(hdl, nvme_args.timeout); } @@ -381,7 +380,7 @@ int parse_and_open(struct libnvme_global_ctx **ctx, return -ENOMEM; libnvme_set_ioctl_probing(ctx_new, - !argconfig_parse_seen(opts, "no-ioctl-probing")); + !nvme_args.no_ioctl_probing); ret = get_transport_handle(ctx_new, argc, argv, O_RDONLY, &hdl_new); if (ret) { @@ -416,7 +415,7 @@ int open_exclusive(struct libnvme_global_ctx **ctx, return -ENOMEM; libnvme_set_ioctl_probing(ctx_new, - !argconfig_parse_seen(opts, "no-ioctl-probing")); + !nvme_args.no_ioctl_probing); ret = get_transport_handle(ctx_new, argc, argv, flags, &hdl_new); if (ret) { @@ -546,7 +545,7 @@ static int get_smart_log(int argc, char **argv, struct command *acmd, struct plu if (cfg.raw_binary) flags = BINARY; - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; smart_log = libnvme_alloc(sizeof(*smart_log)); @@ -1109,7 +1108,7 @@ static int get_effects_log(int argc, char **argv, struct command *acmd, struct p if (cfg.raw_binary) flags = BINARY; - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; list_head_init(&log_pages); @@ -1181,7 +1180,7 @@ static int get_supported_log_pages(int argc, char **argv, struct command *acmd, return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; supports = libnvme_alloc(sizeof(*supports)); @@ -2496,7 +2495,7 @@ static int get_log(int argc, char **argv, struct command *acmd, struct plugin *p libnvme_transport_handle_get_name(hdl), cfg.log_id, cfg.namespace_id); d(log, cfg.log_len, 16, 1); - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) nvme_show_log(libnvme_transport_handle_get_name(hdl), &args, VERBOSE); } else { @@ -2546,7 +2545,7 @@ static int sanitize_log(int argc, char **argv, struct command *acmd, struct plug if (cfg.raw_binary) flags = BINARY; - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; sanitize_log = libnvme_alloc(sizeof(*sanitize_log)); @@ -2597,7 +2596,7 @@ static int get_fid_support_effects_log(int argc, char **argv, struct command *ac return err; } - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; fid_support_log = libnvme_alloc(sizeof(*fid_support_log)); @@ -2649,7 +2648,7 @@ static int get_mi_cmd_support_effects_log(int argc, char **argv, struct command return err; } - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; mi_cmd_support_log = libnvme_alloc(sizeof(*mi_cmd_support_log)); @@ -2773,7 +2772,7 @@ static int list_ns(int argc, char **argv, struct command *acmd, struct plugin *p return -EINVAL; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; ns_list = libnvme_alloc(sizeof(*ns_list)); @@ -2837,7 +2836,7 @@ static int id_ns_lba_format(int argc, char **argv, struct command *acmd, struct return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; ns = libnvme_alloc(sizeof(*ns)); @@ -3534,7 +3533,7 @@ static int list_subsys(int argc, char **argv, struct command *acmd, return -EINVAL; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; ctx = libnvme_create_global_ctx(stdout, log_level); @@ -3632,7 +3631,7 @@ static int list(int argc, char **argv, struct command *acmd, struct plugin *plug return -EINVAL; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; ctx = libnvme_create_global_ctx(stdout, log_level); @@ -3700,7 +3699,7 @@ int __id_ctrl(int argc, char **argv, struct command *acmd, struct plugin *plugin if (cfg.vendor_specific) flags |= VS; - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; ctrl = libnvme_alloc(sizeof(*ctrl)); @@ -3749,7 +3748,7 @@ static int nvm_id_ctrl(int argc, char **argv, struct command *acmd, return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; ctrl_nvm = libnvme_alloc(sizeof(*ctrl_nvm)); @@ -3806,7 +3805,7 @@ static int nvm_id_ns(int argc, char **argv, struct command *acmd, return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; if (!cfg.namespace_id) { @@ -3880,7 +3879,7 @@ static int nvm_id_ns_lba_format(int argc, char **argv, struct command *acmd, str return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; ns = libnvme_alloc(sizeof(*ns)); @@ -3951,7 +3950,7 @@ static int ns_descs(int argc, char **argv, struct command *acmd, struct plugin * if (cfg.raw_binary) flags = BINARY; - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; if (!cfg.namespace_id) { @@ -4032,7 +4031,7 @@ static int id_ns(int argc, char **argv, struct command *acmd, struct plugin *plu if (cfg.vendor_specific) flags |= VS; - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; if (!cfg.namespace_id) { @@ -4108,7 +4107,7 @@ static int cmd_set_independent_id_ns(int argc, char **argv, struct command *acmd if (cfg.raw_binary) flags = BINARY; - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; if (!cfg.namespace_id) { @@ -4270,7 +4269,7 @@ static int id_uuid(int argc, char **argv, struct command *acmd, struct plugin *p if (cfg.raw_binary) flags = BINARY; - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; uuid_list = libnvme_alloc(sizeof(*uuid_list)); @@ -4323,7 +4322,7 @@ static int id_iocs(int argc, char **argv, struct command *acmd, struct plugin *p return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; iocs = libnvme_alloc(sizeof(*iocs)); @@ -4527,7 +4526,7 @@ static int primary_ctrl_caps(int argc, char **argv, struct command *acmd, struct return err; } - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; caps = libnvme_alloc(sizeof(*caps)); @@ -4848,7 +4847,7 @@ static int self_test_log(int argc, char **argv, struct command *acmd, struct plu return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; log = libnvme_alloc(sizeof(*log)); @@ -5069,7 +5068,7 @@ static int get_feature(int argc, char **argv, struct command *acmd, return -1; } - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; nvme_show_init(); @@ -5519,7 +5518,7 @@ static int subsystem_reset(int argc, char **argv, struct command *acmd, struct p nvme_show_error("Subsystem-reset: NVM Subsystem Reset not supported."); else nvme_show_error("Subsystem-reset: %s", libnvme_strerror(-err)); - } else if (argconfig_parse_seen(opts, "verbose")) + } else if (nvme_args.verbose) printf("resetting subsystem through %s\n", libnvme_transport_handle_get_name(hdl)); return err; @@ -5547,7 +5546,7 @@ static int reset(int argc, char **argv, struct command *acmd, struct plugin *plu err = libnvme_reset_ctrl(hdl); if (err < 0) nvme_show_error("Reset: %s", libnvme_strerror(-err)); - else if (argconfig_parse_seen(opts, "verbose")) + else if (nvme_args.verbose) printf("resetting controller %s\n", libnvme_transport_handle_get_name(hdl)); return err; @@ -5582,7 +5581,7 @@ static int ns_rescan(int argc, char **argv, struct command *acmd, struct plugin err = libnvme_rescan_ns(hdl); if (err < 0) nvme_show_error("Namespace Rescan: %s\n", libnvme_strerror(-err)); - else if (argconfig_parse_seen(opts, "verbose")) + else if (nvme_args.verbose) printf("rescanning namespaces through %s\n", libnvme_transport_handle_get_name(hdl)); return err; @@ -5953,7 +5952,7 @@ static int show_registers(int argc, char **argv, struct command *acmd, struct pl return err; } - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; bar = mmap_registers(hdl, false); @@ -6230,7 +6229,7 @@ static int get_register(int argc, char **argv, struct command *acmd, struct plug return err; } - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; bar = mmap_registers(hdl, false); @@ -6581,7 +6580,7 @@ static int get_property(int argc, char **argv, struct command *acmd, struct plug return -EINVAL; } - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; err = nvme_get_single_property(hdl, &cfg, &value); @@ -7648,7 +7647,7 @@ static int write_zeroes(int argc, char **argv, printf("NVME Write Zeroes Success\n"); - if (!cfg.nsz || !argconfig_parse_seen(opts, "verbose")) + if (!cfg.nsz || !nvme_args.verbose) return err; if (cmd.result & 0x1) @@ -9142,7 +9141,7 @@ static int dir_receive(int argc, char **argv, struct command *acmd, struct plugi if (err) return err; - if (cfg.human_readable || argconfig_parse_seen(opts, "verbose")) + if (cfg.human_readable || nvme_args.verbose) flags |= VERBOSE; if (cfg.raw_binary) flags = BINARY; @@ -10316,7 +10315,7 @@ static int tls_key(int argc, char **argv, struct command *acmd, struct plugin *p return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) printf("exporting to %s\n", cfg.keyfile); return 0; @@ -10328,7 +10327,7 @@ static int tls_key(int argc, char **argv, struct command *acmd, struct plugin *p return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) printf("importing from %s\n", cfg.keyfile); } else { err = libnvme_revoke_tls_key(ctx, cfg.keyring, cfg.keytype, @@ -10339,7 +10338,7 @@ static int tls_key(int argc, char **argv, struct command *acmd, struct plugin *p return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) printf("revoking key\n"); } @@ -10383,7 +10382,7 @@ static int show_topology_cmd(int argc, char **argv, struct command *acmd, struct return err; } - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; if (!strcmp(cfg.ranking, "namespace")) { @@ -10832,7 +10831,7 @@ static int get_power_measurement_log(int argc, char **argv, struct command *acmd if (cfg.raw_binary) flags = BINARY; - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) flags |= VERBOSE; /* First read minimum size to discover the full log size */ @@ -11383,18 +11382,7 @@ int main(int argc, char **argv) if (err) return err; - /* - * Parse any global options that appear before the subcommand so that - * e.g. `alias nvme="nvme -v"; nvme list` works correctly instead of - * treating "-v" as an unknown subcommand. After this call optind - * points to the first non-option argument (the subcommand name). - */ - NVME_ARGS(global_opts); - err = argconfig_parse_global(argc, argv, global_opts); - if (err) - return 1; - - err = handle_plugin(argc - optind, &argv[optind], nvme.extensions); + err = handle_plugin(argc - 1, &argv[1], nvme.extensions); if (err == -ENOTTY) general_help(&builtin, NULL); diff --git a/plugin.c b/plugin.c index fa6d960cef..2012487cc5 100644 --- a/plugin.c +++ b/plugin.c @@ -6,6 +6,7 @@ #include +#include "nvme.h" #include "plugin.h" #include "util/argconfig.h" @@ -152,7 +153,6 @@ void general_help(struct plugin *plugin, char *str) int handle_plugin(int argc, char **argv, struct plugin *plugin) { - char *str = argv[0]; char use[0x100]; struct plugin *extension; struct program *prog = plugin->parent; @@ -160,12 +160,25 @@ int handle_plugin(int argc, char **argv, struct plugin *plugin) struct command *cr = NULL; bool cr_valid = false; int dash_count = 0; + char *str; if (!argc) { general_help(plugin, NULL); return 0; } + NVME_ARGS(global_opts); + argconfig_parse_global(argc, argv, global_opts); + argc -= optind; + argv += optind; + + if (!argc) { + general_help(plugin, NULL); + return 0; + } + + str = argv[0]; + if (!plugin->name) snprintf(use, sizeof(use), "%s %s [OPTIONS]", prog->name, str); else diff --git a/plugins/netapp/netapp-nvme.c b/plugins/netapp/netapp-nvme.c index 86216a389b..9382cb7217 100644 --- a/plugins/netapp/netapp-nvme.c +++ b/plugins/netapp/netapp-nvme.c @@ -968,7 +968,7 @@ static int netapp_smdevices(int argc, char **argv, struct command *acmd, if (num_smdevices) { if (fmt == NNORMAL || fmt == NCOLUMN) { - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) netapp_smdevices_print_verbose(smdevices, num_smdevices, fmt, devname); else @@ -1068,7 +1068,7 @@ static int netapp_ontapdevices(int argc, char **argv, struct command *acmd, if (num_ontapdevices) { if (fmt == NNORMAL || fmt == NCOLUMN) { - if (argconfig_parse_seen(opts, "verbose")) + if (nvme_args.verbose) netapp_ontapdevices_print_verbose(ontapdevices, num_ontapdevices, fmt, devname); else From 5306187406348260dba59fe8ccf200f8cf7fba05 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 13:29:03 +0000 Subject: [PATCH 04/11] fix: correct argv handling for argconfig_parse_global in handle_plugin getopt_long always skips argv[0] as the program name. The previous code called handle_plugin(argc-1, &argv[1], ...) from main(), stripping the program name, so inside handle_plugin the call to argconfig_parse_global treated the actual subcommand (argv[0]) as the program name and silently discarded it. After argc -= optind; argv += optind the subcommand was gone and general_help() fired instead of dispatching the command. Fix: - main() now passes argc, argv (with "nvme" at argv[0]) to handle_plugin - Normal plugin recursive dispatch uses handle_plugin(argc, argv, ...) so argv[0] (the plugin name, e.g. "intel") serves as the placeholder that getopt skips, and argv[1] is the subcommand - Combined invocation (e.g. "intel-smart-add-log") builds a temporary argv with the extension name prepended as the program-name placeholder Also add unit tests for argconfig_parse_global in unit/test-argconfig-parse.c covering: subcommand-only, short/long --verbose, repeated flags, --dry-run, option-after-subcommand (+ stop), options-only, and program-name-only cases. --- nvme.c | 2 +- plugin.c | 21 +++++- unit/test-argconfig-parse.c | 123 ++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 3 deletions(-) diff --git a/nvme.c b/nvme.c index acb5a75aaa..5c875adede 100644 --- a/nvme.c +++ b/nvme.c @@ -11382,7 +11382,7 @@ int main(int argc, char **argv) if (err) return err; - err = handle_plugin(argc - 1, &argv[1], nvme.extensions); + err = handle_plugin(argc, argv, nvme.extensions); if (err == -ENOTTY) general_help(&builtin, NULL); diff --git a/plugin.c b/plugin.c index 2012487cc5..98fad0abf9 100644 --- a/plugin.c +++ b/plugin.c @@ -227,7 +227,14 @@ int handle_plugin(int argc, char **argv, struct plugin *plugin) extension = plugin->next; while (extension) { if (!strcmp(str, extension->name)) - return handle_plugin(argc - 1, &argv[1], extension); + /* + * argv[0] is the extension name (e.g. "intel"). + * Pass it as-is so that argconfig_parse_global() + * inside the recursive call treats it as the + * program-name placeholder that getopt skips, and + * argv[1] becomes the subcommand. + */ + return handle_plugin(argc, argv, extension); extension = extension->next; } @@ -238,10 +245,20 @@ int handle_plugin(int argc, char **argv, struct plugin *plugin) extension = plugin->next; while (extension) { if (!strncmp(str, extension->name, strlen(extension->name))) { + /* + * Advance argv[0] past the "pluginname[-]" prefix so + * it points at the subcommand string. Then build a + * temporary argv with the extension name prepended as + * the program-name placeholder for getopt. + */ + char *sub_argv[argc + 1]; + argv[0] += strlen(extension->name); while (*argv[0] == '-') argv[0]++; - return handle_plugin(argc, &argv[0], extension); + sub_argv[0] = (char *)extension->name; + memcpy(&sub_argv[1], argv, argc * sizeof(*argv)); + return handle_plugin(argc + 1, sub_argv, extension); } extension = extension->next; } diff --git a/unit/test-argconfig-parse.c b/unit/test-argconfig-parse.c index e1e4073ccc..15b1ff7fee 100644 --- a/unit/test-argconfig-parse.c +++ b/unit/test-argconfig-parse.c @@ -212,6 +212,126 @@ void comma_sep_array_test(const struct comma_sep_array_test *test) } } +struct global_cfg { + int verbose; + bool dry_run; +}; + +static struct global_cfg gcfg; + +struct global_parse_test { + const char *desc; + char *argv[8]; + int argc; + /* + * Expected optind value after argconfig_parse_global() returns. + * This is the index of the first non-option argument (the subcommand) + * in argv, as seen by getopt – i.e. 1-based because getopt always + * skips argv[0] as the program name. + */ + int expected_optind; + int expected_ret; + int expected_verbose; + bool expected_dry_run; +}; + +static const struct global_parse_test global_parse_tests[] = { + { + "no global opts: subcommand only", + {"prog", "list"}, + 2, 1, 0, 0, false, + }, + { + "short -v before subcommand", + {"prog", "-v", "list"}, + 3, 2, 0, 1, false, + }, + { + "long --verbose before subcommand", + {"prog", "--verbose", "list"}, + 3, 2, 0, 1, false, + }, + { + "two -v flags before subcommand", + {"prog", "-v", "-v", "list"}, + 4, 3, 0, 2, false, + }, + { + "--dry-run before subcommand", + {"prog", "--dry-run", "list"}, + 3, 2, 0, 0, true, + }, + { + "multiple global opts before subcommand", + {"prog", "-v", "--dry-run", "list"}, + 4, 3, 0, 1, true, + }, + { + /* + * The '+' prefix in the short-opts string causes getopt to stop + * at the first non-option argument. Global opts that appear + * *after* the subcommand must be left for the subcommand's own + * argconfig_parse() call to handle. + */ + "subcommand before option: stop at first non-option", + {"prog", "list", "-v"}, + 3, 1, 0, 0, false, + }, + { + "only program name", + {"prog"}, + 1, 1, 0, 0, false, + }, + { + "option with no following subcommand", + {"prog", "--verbose"}, + 2, 2, 0, 1, false, + }, +}; + +static void do_global_parse_test(const struct global_parse_test *test) +{ + int ret; + + OPT_ARGS(opts) = { + OPT_INCR("verbose", 'v', &gcfg.verbose, "increase verbosity"), + OPT_FLAG("dry-run", 0, &gcfg.dry_run, "dry run mode"), + OPT_END() + }; + + gcfg.verbose = 0; + gcfg.dry_run = false; + + ret = argconfig_parse_global(test->argc, (char **)test->argv, opts); + + if (ret != test->expected_ret) { + printf("ERROR: global_parse {%s}: ret=%d expected=%d\n", + test->desc, ret, test->expected_ret); + test_rc = 1; + return; + } + + if (optind != test->expected_optind) { + printf("ERROR: global_parse {%s}: optind=%d expected=%d\n", + test->desc, optind, test->expected_optind); + test_rc = 1; + return; + } + + if (gcfg.verbose != test->expected_verbose) { + printf("ERROR: global_parse {%s}: verbose=%d expected=%d\n", + test->desc, gcfg.verbose, test->expected_verbose); + test_rc = 1; + return; + } + + if (gcfg.dry_run != test->expected_dry_run) { + printf("ERROR: global_parse {%s}: dry_run=%d expected=%d\n", + test->desc, gcfg.dry_run, test->expected_dry_run); + test_rc = 1; + } +} + int main(void) { unsigned int i; @@ -229,6 +349,9 @@ int main(void) for (i = 0; i < ARRAY_SIZE(comma_sep_array_tests); i++) comma_sep_array_test(&comma_sep_array_tests[i]); + for (i = 0; i < ARRAY_SIZE(global_parse_tests); i++) + do_global_parse_test(&global_parse_tests[i]); + if (f) fclose(f); From 58ada90c81b69f93ef5db5b5b805d08430ca43b8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 13:31:43 +0000 Subject: [PATCH 05/11] fix: replace VLA with malloc and use strdup to avoid const-cast in plugin.c --- plugin.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/plugin.c b/plugin.c index 98fad0abf9..a2a378db75 100644 --- a/plugin.c +++ b/plugin.c @@ -251,14 +251,28 @@ int handle_plugin(int argc, char **argv, struct plugin *plugin) * temporary argv with the extension name prepended as * the program-name placeholder for getopt. */ - char *sub_argv[argc + 1]; + char **sub_argv = malloc((argc + 1) * sizeof(*sub_argv)); + char *name_copy; + int ret; + + if (!sub_argv) + return -ENOMEM; argv[0] += strlen(extension->name); while (*argv[0] == '-') argv[0]++; - sub_argv[0] = (char *)extension->name; + + name_copy = strdup(extension->name); + if (!name_copy) { + free(sub_argv); + return -ENOMEM; + } + sub_argv[0] = name_copy; memcpy(&sub_argv[1], argv, argc * sizeof(*argv)); - return handle_plugin(argc + 1, sub_argv, extension); + ret = handle_plugin(argc + 1, sub_argv, extension); + free(name_copy); + free(sub_argv); + return ret; } extension = extension->next; } From 59d66a17281cf262a83d907bf268cad95b183baf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 13:33:55 +0000 Subject: [PATCH 06/11] fix: use __cleanup_free in plugin.c combined-invocation path --- plugin.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/plugin.c b/plugin.c index a2a378db75..787649d1c3 100644 --- a/plugin.c +++ b/plugin.c @@ -9,6 +9,7 @@ #include "nvme.h" #include "plugin.h" #include "util/argconfig.h" +#include "util/cleanup.h" static int version_cmd(struct plugin *plugin) { @@ -251,9 +252,8 @@ int handle_plugin(int argc, char **argv, struct plugin *plugin) * temporary argv with the extension name prepended as * the program-name placeholder for getopt. */ - char **sub_argv = malloc((argc + 1) * sizeof(*sub_argv)); - char *name_copy; - int ret; + __cleanup_free char **sub_argv = malloc((argc + 1) * sizeof(*sub_argv)); + __cleanup_free char *name_copy = NULL; if (!sub_argv) return -ENOMEM; @@ -263,16 +263,11 @@ int handle_plugin(int argc, char **argv, struct plugin *plugin) argv[0]++; name_copy = strdup(extension->name); - if (!name_copy) { - free(sub_argv); + if (!name_copy) return -ENOMEM; - } sub_argv[0] = name_copy; memcpy(&sub_argv[1], argv, argc * sizeof(*argv)); - ret = handle_plugin(argc + 1, sub_argv, extension); - free(name_copy); - free(sub_argv); - return ret; + return handle_plugin(argc + 1, sub_argv, extension); } extension = extension->next; } From 579676682ebd6bb9209c610aac9540f4bb010b1e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 14:57:48 +0000 Subject: [PATCH 07/11] Fix nvme --help global parsing and add regression unit test --- unit/test-argconfig-parse.c | 84 ++++++++++++++++++++++++++++++++++++- util/argconfig.c | 5 +++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/unit/test-argconfig-parse.c b/unit/test-argconfig-parse.c index 15b1ff7fee..393193830d 100644 --- a/unit/test-argconfig-parse.c +++ b/unit/test-argconfig-parse.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "../util/argconfig.h" #include "../util/cleanup.h" @@ -233,6 +234,7 @@ struct global_parse_test { int expected_ret; int expected_verbose; bool expected_dry_run; + const char *stderr_must_not_contain; }; static const struct global_parse_test global_parse_tests[] = { @@ -287,11 +289,79 @@ static const struct global_parse_test global_parse_tests[] = { {"prog", "--verbose"}, 2, 2, 0, 1, false, }, + { + "--help does not trigger unrecognized-option error", + {"prog", "--help"}, + 2, 2, 0, 0, false, + "unrecognized option '--help'", + }, }; +static int parse_global_capture_stderr(int argc, char *argv[], + struct argconfig_commandline_options *opts, + char *buf, size_t buf_size) +{ + FILE *tmp = NULL; + int ret; + int saved_stderr; + size_t n; + + tmp = tmpfile(); + if (!tmp) { + printf("ERROR: tmpfile failed: %s\n", libnvme_strerror(errno)); + test_rc = 1; + return -errno; + } + + saved_stderr = dup(STDERR_FILENO); + if (saved_stderr < 0) { + printf("ERROR: dup stderr failed: %s\n", libnvme_strerror(errno)); + test_rc = 1; + fclose(tmp); + return -errno; + } + + fflush(stderr); + if (dup2(fileno(tmp), STDERR_FILENO) < 0) { + printf("ERROR: redirect stderr failed: %s\n", libnvme_strerror(errno)); + close(saved_stderr); + test_rc = 1; + fclose(tmp); + return -errno; + } + + ret = argconfig_parse_global(argc, argv, opts); + fflush(stderr); + + if (fseek(tmp, 0, SEEK_SET) != 0) { + printf("ERROR: rewind captured stderr failed: %s\n", + libnvme_strerror(errno)); + close(saved_stderr); + test_rc = 1; + fclose(tmp); + return -errno; + } + + n = fread(buf, 1, buf_size - 1, tmp); + buf[n] = '\0'; + + if (dup2(saved_stderr, STDERR_FILENO) < 0) { + printf("ERROR: restoring stderr failed: %s\n", libnvme_strerror(errno)); + test_rc = 1; + close(saved_stderr); + fclose(tmp); + return -errno; + } + close(saved_stderr); + fclose(tmp); + + return ret; +} + static void do_global_parse_test(const struct global_parse_test *test) { int ret; + char stderr_buf[512] = ""; OPT_ARGS(opts) = { OPT_INCR("verbose", 'v', &gcfg.verbose, "increase verbosity"), @@ -302,7 +372,11 @@ static void do_global_parse_test(const struct global_parse_test *test) gcfg.verbose = 0; gcfg.dry_run = false; - ret = argconfig_parse_global(test->argc, (char **)test->argv, opts); + if (test->stderr_must_not_contain) + ret = parse_global_capture_stderr(test->argc, (char **)test->argv, + opts, stderr_buf, sizeof(stderr_buf)); + else + ret = argconfig_parse_global(test->argc, (char **)test->argv, opts); if (ret != test->expected_ret) { printf("ERROR: global_parse {%s}: ret=%d expected=%d\n", @@ -318,6 +392,14 @@ static void do_global_parse_test(const struct global_parse_test *test) return; } + if (test->stderr_must_not_contain && + strstr(stderr_buf, test->stderr_must_not_contain)) { + printf("ERROR: global_parse {%s}: stderr unexpectedly contains '%s'\n", + test->desc, test->stderr_must_not_contain); + test_rc = 1; + return; + } + if (gcfg.verbose != test->expected_verbose) { printf("ERROR: global_parse {%s}: verbose=%d expected=%d\n", test->desc, gcfg.verbose, test->expected_verbose); diff --git a/util/argconfig.c b/util/argconfig.c index 2ce642d3e5..537cd79bc6 100644 --- a/util/argconfig.c +++ b/util/argconfig.c @@ -459,6 +459,11 @@ int argconfig_parse_global(int argc, char *argv[], } } + long_opts[long_opt_index].name = "help"; + long_opts[long_opt_index].val = 'h'; + + short_opts[short_index++] = 'h'; + optind = 0; while ((c = getopt_long(argc, argv, short_opts, long_opts, &long_opt_index)) != -1) { if (c == '?' || c == 'h') From e9684df55688cebf8c3c622bf5926d3bd7d2ff70 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 15:09:41 +0000 Subject: [PATCH 08/11] Handle nvme --version in global parser and add regression test --- unit/test-argconfig-parse.c | 6 ++++++ util/argconfig.c | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/unit/test-argconfig-parse.c b/unit/test-argconfig-parse.c index 393193830d..cc4bbe6701 100644 --- a/unit/test-argconfig-parse.c +++ b/unit/test-argconfig-parse.c @@ -295,6 +295,12 @@ static const struct global_parse_test global_parse_tests[] = { 2, 2, 0, 0, false, "unrecognized option '--help'", }, + { + "--version does not trigger unrecognized-option error", + {"prog", "--version"}, + 2, 1, 0, 0, false, + "unrecognized option '--version'", + }, }; static int parse_global_capture_stderr(int argc, char *argv[], diff --git a/util/argconfig.c b/util/argconfig.c index 537cd79bc6..03c9420372 100644 --- a/util/argconfig.c +++ b/util/argconfig.c @@ -461,6 +461,10 @@ int argconfig_parse_global(int argc, char *argv[], long_opts[long_opt_index].name = "help"; long_opts[long_opt_index].val = 'h'; + long_opt_index++; + + long_opts[long_opt_index].name = "version"; + long_opts[long_opt_index].val = 'V'; short_opts[short_index++] = 'h'; @@ -468,6 +472,10 @@ int argconfig_parse_global(int argc, char *argv[], while ((c = getopt_long(argc, argv, short_opts, long_opts, &long_opt_index)) != -1) { if (c == '?' || c == 'h') break; + if (c == 'V') { + optind--; + break; + } if (c) { for (opt_index = 0; opt_index < options_count; opt_index++) { From eecae7c1a97985ef791fdd4a75eb5115b566b8e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 15:53:33 +0000 Subject: [PATCH 09/11] Update plugin -v/-o short options --- plugins/intel/intel-nvme.c | 4 ++-- plugins/lm/lm-nvme.c | 4 ++-- plugins/memblaze/memblaze-nvme.c | 2 +- plugins/micron/micron-nvme.c | 8 ++++---- plugins/sandisk/sandisk-nvme.c | 4 ++-- plugins/scaleflux/sfx-nvme.c | 4 ++-- plugins/sed/sed.c | 2 +- plugins/shannon/shannon-nvme.c | 2 +- plugins/toshiba/toshiba-nvme.c | 4 ++-- plugins/virtium/virtium-nvme.c | 2 +- plugins/wdc/wdc-nvme.c | 18 +++++++++--------- plugins/zns/zns.c | 6 +++--- 12 files changed, 30 insertions(+), 30 deletions(-) diff --git a/plugins/intel/intel-nvme.c b/plugins/intel/intel-nvme.c index d965e740b8..96b7244d95 100644 --- a/plugins/intel/intel-nvme.c +++ b/plugins/intel/intel-nvme.c @@ -1379,8 +1379,8 @@ static int get_internal_log(int argc, char **argv, struct command *acmd, OPT_INT("region", 'r', &cfg.core, core), OPT_INT("nlognum", 'm', &cfg.lnum, nlognum), OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_FILE("output-file", 'o', &cfg.file, file), - OPT_FLAG("verbose-nlog", 'v', &cfg.verbose, verbose)); + 'O', &cfg.file, file), + 'V', &cfg.verbose, verbose)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (err) { diff --git a/plugins/lm/lm-nvme.c b/plugins/lm/lm-nvme.c index 877738cf05..89b98e817a 100644 --- a/plugins/lm/lm-nvme.c +++ b/plugins/lm/lm-nvme.c @@ -319,7 +319,7 @@ static int lm_migration_send(int argc, char **argv, struct command *acmd, struct OPT_BYTE("csuuidi", 'U', &cfg.csuuidi, csuuidi), OPT_BYTE("csvi", 'V', &cfg.csvi, csvi), OPT_BYTE("uidx", 'u', &cfg.uidx, uidx), - OPT_LONG("offset", 'o', &cfg.offset, offset), + 'O', &cfg.offset, offset), OPT_UINT("numd", 'n', &cfg.numd, numd), OPT_FILE("input-file", 'f', &cfg.input, input)); @@ -446,7 +446,7 @@ static int lm_migration_recv(int argc, char **argv, struct command *acmd, struct OPT_BYTE("csuuidi", 'U', &cfg.csuuidi, csuuidi), OPT_BYTE("csvi", 'V', &cfg.csvi, csvi), OPT_BYTE("uidx", 'u', &cfg.uidx, uidx), - OPT_LONG("offset", 'o', &cfg.offset, offset), + 'O', &cfg.offset, offset), OPT_UINT("numd", 'n', &cfg.numd, numd), OPT_FILE("output-file", 'f', &cfg.output, output), OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_info)); diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c index a9ef52db5b..87a50701d2 100644 --- a/plugins/memblaze/memblaze-nvme.c +++ b/plugins/memblaze/memblaze-nvme.c @@ -523,7 +523,7 @@ static int mb_set_powermanager_status(int argc, char **argv, struct command *acm }; NVME_ARGS(opts, - OPT_UINT("value", 'v', &cfg.value, value), + 'V', &cfg.value, value), OPT_FLAG("save", 's', &cfg.save, save)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c index dc0f83da26..4d2a66d3e7 100644 --- a/plugins/micron/micron-nvme.c +++ b/plugins/micron/micron-nvme.c @@ -718,8 +718,8 @@ static int micron_smbus_option(int argc, char **argv, }; NVME_ARGS(opts, - OPT_STRING("option", 'o', "option", &opt.option, option), - OPT_UINT("value", 'v', &opt.value, value), + 'O', "option", &opt.option, option), + 'V', &opt.value, value), OPT_UINT("save", 's', &opt.save, save)); err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model); @@ -2888,7 +2888,7 @@ static int micron_latency_stats_track(int argc, char **argv, struct command *acm }; NVME_ARGS(opts, - OPT_STRING("option", 'o', "option", &opt.option, option), + 'O', "option", &opt.option, option), OPT_STRING("command", 'c', "command", &opt.command, cmdstr), OPT_UINT("threshold", 't', &opt.threshold, thrtime)); @@ -3260,7 +3260,7 @@ static int micron_telemetry_cntrl_option(int argc, char **argv, }; NVME_ARGS(opts, - OPT_STRING("option", 'o', "option", &opt.option, option), + 'O', "option", &opt.option, option), OPT_UINT("select", 's', &opt.select, select)); err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model); diff --git a/plugins/sandisk/sandisk-nvme.c b/plugins/sandisk/sandisk-nvme.c index 20140c2807..b2d7c9551b 100644 --- a/plugins/sandisk/sandisk-nvme.c +++ b/plugins/sandisk/sandisk-nvme.c @@ -428,11 +428,11 @@ static int sndk_vs_internal_fw_log(int argc, char **argv, }; NVME_ARGS(opts, - OPT_FILE("output-file", 'o', &cfg.file, file), + 'O', &cfg.file, file), OPT_UINT("transfer-size", 's', &cfg.xfer_size, size), OPT_UINT("data-area", 'd', &cfg.data_area, data_area), OPT_FILE("type", 't', &cfg.type, type), - OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), + 'V', &cfg.verbose, verbose), OPT_LONG("file-size", 'f', &cfg.file_size, file_size), OPT_LONG("offset", 'e', &cfg.offset, offset), OPT_END()); diff --git a/plugins/scaleflux/sfx-nvme.c b/plugins/scaleflux/sfx-nvme.c index 8e43ca4a93..946425cff6 100644 --- a/plugins/scaleflux/sfx-nvme.c +++ b/plugins/scaleflux/sfx-nvme.c @@ -954,7 +954,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *acmd, struct p NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id), - OPT_UINT("value", 'v', &cfg.value, value), + 'V', &cfg.value, value), OPT_FLAG("force", 's', &cfg.force, force)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); @@ -1379,7 +1379,7 @@ static int sfx_dump_evtlog(int argc, char **argv, struct command *acmd, struct p OPT_UINT("namespace_id", 'n', &cfg.namespace_id, namespace_id), OPT_UINT("storage_medium", 's', &cfg.storage_medium, storage_medium), OPT_FLAG("parse", 'p', &cfg.parse, parse), - OPT_FILE("output", 'o', &cfg.output, output)); + 'O', &cfg.output, output)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (err) diff --git a/plugins/sed/sed.c b/plugins/sed/sed.c index 0578a067de..860da6c2d0 100644 --- a/plugins/sed/sed.c +++ b/plugins/sed/sed.c @@ -54,7 +54,7 @@ OPT_ARGS(lock_opts) = { }; OPT_ARGS(discovery_opts) = { - OPT_FLAG("verbose", 'v', &sedopal_discovery_verbose, + 'V', &sedopal_discovery_verbose, "Print extended discovery information"), OPT_FLAG("udev", 'u', &sedopal_discovery_udev, "Print locking information in form suitable for udev rules"), diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c index 448748953e..887f59bd5e 100644 --- a/plugins/shannon/shannon-nvme.c +++ b/plugins/shannon/shannon-nvme.c @@ -281,7 +281,7 @@ static int set_additional_feature(int argc, char **argv, struct command *acmd, s NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id), - OPT_UINT("value", 'v', &cfg.value, value), + 'V', &cfg.value, value), OPT_UINT("data-len", 'l', &cfg.data_len, data_len), OPT_FILE("data", 'd', &cfg.file, data), OPT_FLAG("save", 's', &cfg.save, save)); diff --git a/plugins/toshiba/toshiba-nvme.c b/plugins/toshiba/toshiba-nvme.c index fc8ebad485..e0c89ab9fa 100644 --- a/plugins/toshiba/toshiba-nvme.c +++ b/plugins/toshiba/toshiba-nvme.c @@ -428,7 +428,7 @@ static int vendor_log(int argc, char **argv, struct command *acmd, struct plugin NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), - OPT_FILE("output-file", 'o', &cfg.output_file, output_file), + 'O', &cfg.output_file, output_file), OPT_UINT("log", 'l', &cfg.log, log)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); @@ -474,7 +474,7 @@ static int internal_log(int argc, char **argv, struct command *acmd, struct plug }; NVME_ARGS(opts, - OPT_FILE("output-file", 'o', &cfg.output_file, output_file), + 'O', &cfg.output_file, output_file), OPT_FLAG("prev-log", 'p', &cfg.prev_log, prev_log)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); diff --git a/plugins/virtium/virtium-nvme.c b/plugins/virtium/virtium-nvme.c index 732d3d508a..63afab7573 100644 --- a/plugins/virtium/virtium-nvme.c +++ b/plugins/virtium/virtium-nvme.c @@ -962,7 +962,7 @@ static int vt_save_smart_to_vtview_log(int argc, char **argv, NVME_ARGS(opts, OPT_DOUBLE("run-time", 'r', &cfg.run_time_hrs, run_time), OPT_DOUBLE("freq", 'f', &cfg.log_record_frequency_hrs, freq), - OPT_FILE("output-file", 'o', &cfg.output_file, output_file), + 'O', &cfg.output_file, output_file), OPT_STRING("test-name", 'n', "NAME", &cfg.test_name, test_name)); vt_generate_vtview_log_file_name(vt_default_log_file_name); diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c index 5f165480a5..2b73d1e3fb 100644 --- a/plugins/wdc/wdc-nvme.c +++ b/plugins/wdc/wdc-nvme.c @@ -3922,7 +3922,7 @@ static int wdc_cap_diag(int argc, char **argv, struct command *acmd, }; NVME_ARGS(opts, - OPT_FILE("output-file", 'o', &cfg.file, file), + 'O', &cfg.file, file), OPT_UINT("transfer-size", 's', &cfg.xfer_size, size)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); @@ -4350,11 +4350,11 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *acmd, }; NVME_ARGS(opts, - OPT_FILE("output-file", 'o', &cfg.file, file), + 'O', &cfg.file, file), OPT_UINT("transfer-size", 's', &cfg.xfer_size, size), OPT_UINT("data-area", 'd', &cfg.data_area, data_area), OPT_FILE("type", 't', &cfg.type, type), - OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), + 'V', &cfg.verbose, verbose), OPT_LONG("file-size", 'f', &cfg.file_size, file_size), OPT_LONG("offset", 'e', &cfg.offset, offset), OPT_END()); @@ -4727,7 +4727,7 @@ static int wdc_drive_log(int argc, char **argv, struct command *acmd, }; NVME_ARGS(opts, - OPT_FILE("output-file", 'o', &cfg.file, file)); + 'O', &cfg.file, file)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (ret) @@ -4773,7 +4773,7 @@ static int wdc_get_crash_dump(int argc, char **argv, struct command *acmd, }; NVME_ARGS(opts, - OPT_FILE("output-file", 'o', &cfg.file, file)); + 'O', &cfg.file, file)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (ret) @@ -4814,7 +4814,7 @@ static int wdc_get_pfail_dump(int argc, char **argv, struct command *acmd, }; NVME_ARGS(opts, - OPT_FILE("output-file", 'o', &cfg.file, file)); + 'O', &cfg.file, file)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (ret) @@ -10513,7 +10513,7 @@ static int wdc_namespace_resize(int argc, char **argv, NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_UINT("op-option", 'o', &cfg.op_option, op_option)); + 'O', &cfg.op_option, op_option)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (ret) @@ -10573,7 +10573,7 @@ static int wdc_reason_identifier(int argc, char **argv, NVME_ARGS(opts, OPT_UINT("log-id", 'i', &cfg.log_id, log_id), - OPT_FILE("file", 'o', &cfg.file, fname)); + 'O', &cfg.file, fname)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); @@ -12311,7 +12311,7 @@ static int wdc_enc_get_log(int argc, char **argv, struct command *acmd, struct p }; NVME_ARGS(opts, - OPT_FILE("output-file", 'o', &cfg.file, file), + 'O', &cfg.file, file), OPT_UINT("transfer-size", 's', &cfg.xfer_size, size), OPT_UINT("log-id", 'l', &cfg.log_id, log)); diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c index 749b6d05e5..bd93332239 100644 --- a/plugins/zns/zns.c +++ b/plugins/zns/zns.c @@ -187,7 +187,7 @@ static int id_ns(int argc, char **argv, struct command *acmd, struct plugin *plu NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_FLAG("vendor-specific", 'v', &cfg.vendor_specific, vendor_specific), + 'V', &cfg.vendor_specific, vendor_specific), OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); @@ -348,7 +348,7 @@ static int zone_mgmt_send(int argc, char **argv, struct command *acmd, struct pl NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba), - OPT_FLAG("zsaso", 'o', &cfg.zsaso, zsaso), + 'O', &cfg.zsaso, zsaso), OPT_FLAG("select-all", 'a', &cfg.select_all, select_all), OPT_BYTE("zsa", 'z', &cfg.zsa, zsa), OPT_UINT("data-len", 'l', &cfg.data_len, data_len), @@ -776,7 +776,7 @@ static int report_zones(int argc, char **argv, struct command *acmd, struct plug OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba), OPT_UINT("descs", 'd', &cfg.num_descs, num_descs), OPT_UINT("state", 'S', &cfg.state, state), - OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), + 'V', &cfg.verbose, verbose), OPT_FLAG("extended", 'e', &cfg.extended, ext), OPT_FLAG("partial", 'p', &cfg.partial, part)); From 2b2917607a5ad8bf40564de87aa79908c7a16fb3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 15:55:07 +0000 Subject: [PATCH 10/11] Use non-conflicting plugin short options --- plugins/intel/intel-nvme.c | 4 ++-- plugins/lm/lm-nvme.c | 4 ++-- plugins/memblaze/memblaze-nvme.c | 2 +- plugins/micron/micron-nvme.c | 8 ++++---- plugins/sandisk/sandisk-nvme.c | 4 ++-- plugins/scaleflux/sfx-nvme.c | 4 ++-- plugins/sed/sed.c | 2 +- plugins/shannon/shannon-nvme.c | 2 +- plugins/toshiba/toshiba-nvme.c | 4 ++-- plugins/virtium/virtium-nvme.c | 2 +- plugins/wdc/wdc-nvme.c | 18 +++++++++--------- plugins/zns/zns.c | 6 +++--- 12 files changed, 30 insertions(+), 30 deletions(-) diff --git a/plugins/intel/intel-nvme.c b/plugins/intel/intel-nvme.c index 96b7244d95..41b085aa17 100644 --- a/plugins/intel/intel-nvme.c +++ b/plugins/intel/intel-nvme.c @@ -1379,8 +1379,8 @@ static int get_internal_log(int argc, char **argv, struct command *acmd, OPT_INT("region", 'r', &cfg.core, core), OPT_INT("nlognum", 'm', &cfg.lnum, nlognum), OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - 'O', &cfg.file, file), - 'V', &cfg.verbose, verbose)); + OPT_FILE("output-file", 'O', &cfg.file, file), + OPT_FLAG("verbose-nlog", 'V', &cfg.verbose, verbose)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (err) { diff --git a/plugins/lm/lm-nvme.c b/plugins/lm/lm-nvme.c index 89b98e817a..61e2c4ae3f 100644 --- a/plugins/lm/lm-nvme.c +++ b/plugins/lm/lm-nvme.c @@ -319,7 +319,7 @@ static int lm_migration_send(int argc, char **argv, struct command *acmd, struct OPT_BYTE("csuuidi", 'U', &cfg.csuuidi, csuuidi), OPT_BYTE("csvi", 'V', &cfg.csvi, csvi), OPT_BYTE("uidx", 'u', &cfg.uidx, uidx), - 'O', &cfg.offset, offset), + OPT_LONG("offset", 'O', &cfg.offset, offset), OPT_UINT("numd", 'n', &cfg.numd, numd), OPT_FILE("input-file", 'f', &cfg.input, input)); @@ -446,7 +446,7 @@ static int lm_migration_recv(int argc, char **argv, struct command *acmd, struct OPT_BYTE("csuuidi", 'U', &cfg.csuuidi, csuuidi), OPT_BYTE("csvi", 'V', &cfg.csvi, csvi), OPT_BYTE("uidx", 'u', &cfg.uidx, uidx), - 'O', &cfg.offset, offset), + OPT_LONG("offset", 'O', &cfg.offset, offset), OPT_UINT("numd", 'n', &cfg.numd, numd), OPT_FILE("output-file", 'f', &cfg.output, output), OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_info)); diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c index 87a50701d2..0804ada730 100644 --- a/plugins/memblaze/memblaze-nvme.c +++ b/plugins/memblaze/memblaze-nvme.c @@ -523,7 +523,7 @@ static int mb_set_powermanager_status(int argc, char **argv, struct command *acm }; NVME_ARGS(opts, - 'V', &cfg.value, value), + OPT_UINT("value", 'V', &cfg.value, value), OPT_FLAG("save", 's', &cfg.save, save)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c index 4d2a66d3e7..5ca1d5e244 100644 --- a/plugins/micron/micron-nvme.c +++ b/plugins/micron/micron-nvme.c @@ -718,8 +718,8 @@ static int micron_smbus_option(int argc, char **argv, }; NVME_ARGS(opts, - 'O', "option", &opt.option, option), - 'V', &opt.value, value), + OPT_STRING("option", 'O', "option", &opt.option, option), + OPT_UINT("value", 'V', &opt.value, value), OPT_UINT("save", 's', &opt.save, save)); err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model); @@ -2888,7 +2888,7 @@ static int micron_latency_stats_track(int argc, char **argv, struct command *acm }; NVME_ARGS(opts, - 'O', "option", &opt.option, option), + OPT_STRING("option", 'O', "option", &opt.option, option), OPT_STRING("command", 'c', "command", &opt.command, cmdstr), OPT_UINT("threshold", 't', &opt.threshold, thrtime)); @@ -3260,7 +3260,7 @@ static int micron_telemetry_cntrl_option(int argc, char **argv, }; NVME_ARGS(opts, - 'O', "option", &opt.option, option), + OPT_STRING("option", 'O', "option", &opt.option, option), OPT_UINT("select", 's', &opt.select, select)); err = micron_parse_options(&ctx, &hdl, argc, argv, desc, opts, &model); diff --git a/plugins/sandisk/sandisk-nvme.c b/plugins/sandisk/sandisk-nvme.c index b2d7c9551b..ac60da6f3b 100644 --- a/plugins/sandisk/sandisk-nvme.c +++ b/plugins/sandisk/sandisk-nvme.c @@ -428,11 +428,11 @@ static int sndk_vs_internal_fw_log(int argc, char **argv, }; NVME_ARGS(opts, - 'O', &cfg.file, file), + OPT_FILE("output-file", 'O', &cfg.file, file), OPT_UINT("transfer-size", 's', &cfg.xfer_size, size), OPT_UINT("data-area", 'd', &cfg.data_area, data_area), OPT_FILE("type", 't', &cfg.type, type), - 'V', &cfg.verbose, verbose), + OPT_FLAG("verbose", 'V', &cfg.verbose, verbose), OPT_LONG("file-size", 'f', &cfg.file_size, file_size), OPT_LONG("offset", 'e', &cfg.offset, offset), OPT_END()); diff --git a/plugins/scaleflux/sfx-nvme.c b/plugins/scaleflux/sfx-nvme.c index 946425cff6..35b1050d83 100644 --- a/plugins/scaleflux/sfx-nvme.c +++ b/plugins/scaleflux/sfx-nvme.c @@ -954,7 +954,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *acmd, struct p NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id), - 'V', &cfg.value, value), + OPT_UINT("value", 'V', &cfg.value, value), OPT_FLAG("force", 's', &cfg.force, force)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); @@ -1379,7 +1379,7 @@ static int sfx_dump_evtlog(int argc, char **argv, struct command *acmd, struct p OPT_UINT("namespace_id", 'n', &cfg.namespace_id, namespace_id), OPT_UINT("storage_medium", 's', &cfg.storage_medium, storage_medium), OPT_FLAG("parse", 'p', &cfg.parse, parse), - 'O', &cfg.output, output)); + OPT_FILE("output", 'O', &cfg.output, output)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (err) diff --git a/plugins/sed/sed.c b/plugins/sed/sed.c index 860da6c2d0..ec61b4f0c5 100644 --- a/plugins/sed/sed.c +++ b/plugins/sed/sed.c @@ -54,7 +54,7 @@ OPT_ARGS(lock_opts) = { }; OPT_ARGS(discovery_opts) = { - 'V', &sedopal_discovery_verbose, + OPT_FLAG("verbose", 'V', &sedopal_discovery_verbose, "Print extended discovery information"), OPT_FLAG("udev", 'u', &sedopal_discovery_udev, "Print locking information in form suitable for udev rules"), diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c index 887f59bd5e..32ee8dc626 100644 --- a/plugins/shannon/shannon-nvme.c +++ b/plugins/shannon/shannon-nvme.c @@ -281,7 +281,7 @@ static int set_additional_feature(int argc, char **argv, struct command *acmd, s NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id), - 'V', &cfg.value, value), + OPT_UINT("value", 'V', &cfg.value, value), OPT_UINT("data-len", 'l', &cfg.data_len, data_len), OPT_FILE("data", 'd', &cfg.file, data), OPT_FLAG("save", 's', &cfg.save, save)); diff --git a/plugins/toshiba/toshiba-nvme.c b/plugins/toshiba/toshiba-nvme.c index e0c89ab9fa..682a8d0708 100644 --- a/plugins/toshiba/toshiba-nvme.c +++ b/plugins/toshiba/toshiba-nvme.c @@ -428,7 +428,7 @@ static int vendor_log(int argc, char **argv, struct command *acmd, struct plugin NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), - 'O', &cfg.output_file, output_file), + OPT_FILE("output-file", 'O', &cfg.output_file, output_file), OPT_UINT("log", 'l', &cfg.log, log)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); @@ -474,7 +474,7 @@ static int internal_log(int argc, char **argv, struct command *acmd, struct plug }; NVME_ARGS(opts, - 'O', &cfg.output_file, output_file), + OPT_FILE("output-file", 'O', &cfg.output_file, output_file), OPT_FLAG("prev-log", 'p', &cfg.prev_log, prev_log)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); diff --git a/plugins/virtium/virtium-nvme.c b/plugins/virtium/virtium-nvme.c index 63afab7573..221797c15b 100644 --- a/plugins/virtium/virtium-nvme.c +++ b/plugins/virtium/virtium-nvme.c @@ -962,7 +962,7 @@ static int vt_save_smart_to_vtview_log(int argc, char **argv, NVME_ARGS(opts, OPT_DOUBLE("run-time", 'r', &cfg.run_time_hrs, run_time), OPT_DOUBLE("freq", 'f', &cfg.log_record_frequency_hrs, freq), - 'O', &cfg.output_file, output_file), + OPT_FILE("output-file", 'O', &cfg.output_file, output_file), OPT_STRING("test-name", 'n', "NAME", &cfg.test_name, test_name)); vt_generate_vtview_log_file_name(vt_default_log_file_name); diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c index 2b73d1e3fb..42205e3589 100644 --- a/plugins/wdc/wdc-nvme.c +++ b/plugins/wdc/wdc-nvme.c @@ -3922,7 +3922,7 @@ static int wdc_cap_diag(int argc, char **argv, struct command *acmd, }; NVME_ARGS(opts, - 'O', &cfg.file, file), + OPT_FILE("output-file", 'O', &cfg.file, file), OPT_UINT("transfer-size", 's', &cfg.xfer_size, size)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); @@ -4350,11 +4350,11 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *acmd, }; NVME_ARGS(opts, - 'O', &cfg.file, file), + OPT_FILE("output-file", 'O', &cfg.file, file), OPT_UINT("transfer-size", 's', &cfg.xfer_size, size), OPT_UINT("data-area", 'd', &cfg.data_area, data_area), OPT_FILE("type", 't', &cfg.type, type), - 'V', &cfg.verbose, verbose), + OPT_FLAG("verbose", 'V', &cfg.verbose, verbose), OPT_LONG("file-size", 'f', &cfg.file_size, file_size), OPT_LONG("offset", 'e', &cfg.offset, offset), OPT_END()); @@ -4727,7 +4727,7 @@ static int wdc_drive_log(int argc, char **argv, struct command *acmd, }; NVME_ARGS(opts, - 'O', &cfg.file, file)); + OPT_FILE("output-file", 'O', &cfg.file, file)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (ret) @@ -4773,7 +4773,7 @@ static int wdc_get_crash_dump(int argc, char **argv, struct command *acmd, }; NVME_ARGS(opts, - 'O', &cfg.file, file)); + OPT_FILE("output-file", 'O', &cfg.file, file)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (ret) @@ -4814,7 +4814,7 @@ static int wdc_get_pfail_dump(int argc, char **argv, struct command *acmd, }; NVME_ARGS(opts, - 'O', &cfg.file, file)); + OPT_FILE("output-file", 'O', &cfg.file, file)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (ret) @@ -10513,7 +10513,7 @@ static int wdc_namespace_resize(int argc, char **argv, NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - 'O', &cfg.op_option, op_option)); + OPT_UINT("op-option", 'O', &cfg.op_option, op_option)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); if (ret) @@ -10573,7 +10573,7 @@ static int wdc_reason_identifier(int argc, char **argv, NVME_ARGS(opts, OPT_UINT("log-id", 'i', &cfg.log_id, log_id), - 'O', &cfg.file, fname)); + OPT_FILE("file", 'O', &cfg.file, fname)); ret = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); @@ -12311,7 +12311,7 @@ static int wdc_enc_get_log(int argc, char **argv, struct command *acmd, struct p }; NVME_ARGS(opts, - 'O', &cfg.file, file), + OPT_FILE("output-file", 'O', &cfg.file, file), OPT_UINT("transfer-size", 's', &cfg.xfer_size, size), OPT_UINT("log-id", 'l', &cfg.log_id, log)); diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c index bd93332239..fa8b8f8809 100644 --- a/plugins/zns/zns.c +++ b/plugins/zns/zns.c @@ -187,7 +187,7 @@ static int id_ns(int argc, char **argv, struct command *acmd, struct plugin *plu NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - 'V', &cfg.vendor_specific, vendor_specific), + OPT_FLAG("vendor-specific", 'V', &cfg.vendor_specific, vendor_specific), OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable)); err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts); @@ -348,7 +348,7 @@ static int zone_mgmt_send(int argc, char **argv, struct command *acmd, struct pl NVME_ARGS(opts, OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba), - 'O', &cfg.zsaso, zsaso), + OPT_FLAG("zsaso", 'O', &cfg.zsaso, zsaso), OPT_FLAG("select-all", 'a', &cfg.select_all, select_all), OPT_BYTE("zsa", 'z', &cfg.zsa, zsa), OPT_UINT("data-len", 'l', &cfg.data_len, data_len), @@ -776,7 +776,7 @@ static int report_zones(int argc, char **argv, struct command *acmd, struct plug OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba), OPT_UINT("descs", 'd', &cfg.num_descs, num_descs), OPT_UINT("state", 'S', &cfg.state, state), - 'V', &cfg.verbose, verbose), + OPT_FLAG("verbose", 'V', &cfg.verbose, verbose), OPT_FLAG("extended", 'e', &cfg.extended, ext), OPT_FLAG("partial", 'p', &cfg.partial, part)); From ffed7a738d3c22ac4ecfa7a0837e66d9dbdbea42 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 16:05:38 +0000 Subject: [PATCH 11/11] Changes before error encountered Agent-Logs-Url: https://github.com/igaw/nvme-cli/sessions/db80cb72-afb7-42e6-a40a-ed3c7cafd140 --- Documentation/nvme-intel-internal-log.txt | 4 ++-- Documentation/nvme-sndk-namespace-resize.txt | 6 +++--- .../nvme-sndk-vs-error-reason-identifier.txt | 8 ++++---- Documentation/nvme-sndk-vs-internal-log.txt | 20 +++++++++---------- .../nvme-toshiba-vs-internal-log.txt | 4 ++-- .../nvme-toshiba-vs-smart-add-log.txt | 4 ++-- .../nvme-virtium-save-smart-to-vtview-log.txt | 4 ++-- Documentation/nvme-wdc-cap-diag.txt | 8 ++++---- Documentation/nvme-wdc-drive-log.txt | 8 ++++---- Documentation/nvme-wdc-enc-get-log.txt | 8 ++++---- Documentation/nvme-wdc-get-crash-dump.txt | 8 ++++---- Documentation/nvme-wdc-get-pfail-dump.txt | 8 ++++---- Documentation/nvme-wdc-namespace-resize.txt | 6 +++--- .../nvme-wdc-vs-error-reason-identifier.txt | 8 ++++---- Documentation/nvme-wdc-vs-internal-log.txt | 18 ++++++++--------- Documentation/nvme-zns-zone-mgmt-send.txt | 4 ++-- 16 files changed, 63 insertions(+), 63 deletions(-) diff --git a/Documentation/nvme-intel-internal-log.txt b/Documentation/nvme-intel-internal-log.txt index 569f4d713c..c4d766294d 100644 --- a/Documentation/nvme-intel-internal-log.txt +++ b/Documentation/nvme-intel-internal-log.txt @@ -12,7 +12,7 @@ SYNOPSIS [--region=, r ] [--nlognum=, m ] [--namespace-id=, -n ] - [--output-file=, -o ] + [--output-file=, -O ] [] DESCRIPTION @@ -40,7 +40,7 @@ OPTIONS --namespace-id=:: Namespace to use. --o :: +-O :: --output-file=:: Output file; defaults to device name provided diff --git a/Documentation/nvme-sndk-namespace-resize.txt b/Documentation/nvme-sndk-namespace-resize.txt index 3eab9ec69a..fca662b2d1 100644 --- a/Documentation/nvme-sndk-namespace-resize.txt +++ b/Documentation/nvme-sndk-namespace-resize.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'nvme sndk namespace-resize' [--nsid=, -n ] - [--op_option=, -o ] + [--op_option=, -O ] [] DESCRIPTION @@ -29,7 +29,7 @@ OPTIONS --namespace-id=:: Namespace ID; ID of the namespace to resize --o :: +-O :: --op-option=:: Overprovisioning Option; defaults to 0xF Valid Values: @@ -46,7 +46,7 @@ EXAMPLES * Resizes namespace 1 to 50% of the original TNVMCAP reported value: + ------------ -# nvme sndk namespace-resize /dev/nvme0 -n 1 -o 3 +# nvme sndk namespace-resize /dev/nvme0 -n 1 -O 3 ------------ * Resizes namespace 2 to 7% of the original TNVMCAP reported value: + diff --git a/Documentation/nvme-sndk-vs-error-reason-identifier.txt b/Documentation/nvme-sndk-vs-error-reason-identifier.txt index ac771352d8..65b0d84e67 100644 --- a/Documentation/nvme-sndk-vs-error-reason-identifier.txt +++ b/Documentation/nvme-sndk-vs-error-reason-identifier.txt @@ -8,7 +8,7 @@ nvme-sndk-vs-error-reason-identifier - Retrieve sndk device's telemetry log erro SYNOPSIS -------- [verse] -'nvme sndk vs-error-reason-identifier' [--log-id=, -i ] [--file=, -o ] +'nvme sndk vs-error-reason-identifier' [--log-id=, -i ] [--file=, -O ] [] DESCRIPTION @@ -33,7 +33,7 @@ OPTIONS Use id 8 for the controller initiated log page. The default is 7/host generated --o :: +-O :: --output-file=:: Output file; defaults to "_error_reason_identifier_host__