| File: | .build-ci/../src/plugin.c |
| Warning: | line 509, column 13 Potential leak of memory pointed to by 'sub_argv' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | |||
| 2 | #include <errno(*__errno_location ()).h> | |||
| 3 | #include <stdio.h> | |||
| 4 | #include <stdlib.h> | |||
| 5 | #include <string.h> | |||
| 6 | #include <unistd.h> | |||
| 7 | ||||
| 8 | #include <libnvme.h> | |||
| 9 | ||||
| 10 | #include <shared/wrap-util.h> | |||
| 11 | ||||
| 12 | #include "argconfig.h" | |||
| 13 | #include "args.h" | |||
| 14 | #include "cleanup.h" | |||
| 15 | #include "plugin.h" | |||
| 16 | ||||
| 17 | static int version_cmd(struct plugin *plugin) | |||
| 18 | { | |||
| 19 | struct program *prog = plugin->parent; | |||
| 20 | ||||
| 21 | if (plugin->name) { | |||
| 22 | printf("%s %s version %s (git %s)\n", | |||
| 23 | prog->name, plugin->name, plugin->version, GIT_VERSION"v3.1-24-ge924f82"); | |||
| 24 | } else { | |||
| 25 | printf("%s version %s (git %s)\n", | |||
| 26 | prog->name, prog->version, GIT_VERSION"v3.1-24-ge924f82"); | |||
| 27 | } | |||
| 28 | printf("libnvme version %s (git %s)\n", | |||
| 29 | libnvme_get_version(LIBNVME_VERSION_PROJECT), | |||
| 30 | libnvme_get_version(LIBNVME_VERSION_GIT)); | |||
| 31 | return 0; | |||
| 32 | } | |||
| 33 | ||||
| 34 | static int help(int argc, char **argv, struct plugin *plugin) | |||
| 35 | { | |||
| 36 | char man[0x100]; | |||
| 37 | struct program *prog = plugin->parent; | |||
| 38 | char *str; | |||
| 39 | int i; | |||
| 40 | ||||
| 41 | if (argc == 1) { | |||
| 42 | general_help(plugin, NULL((void*)0)); | |||
| 43 | return 0; | |||
| 44 | } | |||
| 45 | ||||
| 46 | str = argv[1]; | |||
| 47 | for (i = 0; plugin->commands[i]; i++) { | |||
| 48 | struct command *command = plugin->commands[i]; | |||
| 49 | ||||
| 50 | if (strcmp(str, command->name)) | |||
| 51 | if (!command->alias || | |||
| 52 | (command->alias && strcmp(str, command->alias))) | |||
| 53 | continue; | |||
| 54 | ||||
| 55 | if (plugin->name) | |||
| 56 | snprintf(man, sizeof(man), "%s-%s-%s", prog->name, | |||
| 57 | plugin->name, command->name); | |||
| 58 | else | |||
| 59 | snprintf(man, sizeof(man), "%s-%s", prog->name, command->name); | |||
| 60 | if (execlp("man", "man", man, (char *)NULL((void*)0))) | |||
| 61 | perror(argv[1]); | |||
| 62 | } | |||
| 63 | ||||
| 64 | general_help(plugin, str); | |||
| 65 | ||||
| 66 | return 0; | |||
| 67 | } | |||
| 68 | ||||
| 69 | enum ext_filter { | |||
| 70 | EXT_GROUP, /* extension->group matches the given title */ | |||
| 71 | EXT_CORE_ONLY, /* core, not shown next to a built-in group */ | |||
| 72 | EXT_VENDOR, /* vendor (non-core) */ | |||
| 73 | }; | |||
| 74 | ||||
| 75 | static bool_Bool extension_matches(struct plugin *extension, enum ext_filter filter, | |||
| 76 | const char *group_title) | |||
| 77 | { | |||
| 78 | switch (filter) { | |||
| 79 | case EXT_GROUP: | |||
| 80 | return extension->group && !strcmp(extension->group, group_title); | |||
| 81 | case EXT_CORE_ONLY: | |||
| 82 | return extension->core && !extension->group; | |||
| 83 | case EXT_VENDOR: | |||
| 84 | return !extension->core; | |||
| 85 | } | |||
| 86 | return false0; | |||
| 87 | } | |||
| 88 | ||||
| 89 | static int plugin_name_cmp(const void *a, const void *b) | |||
| 90 | { | |||
| 91 | struct plugin *const *pa = a; | |||
| 92 | struct plugin *const *pb = b; | |||
| 93 | ||||
| 94 | return strcmp((*pa)->name, (*pb)->name); | |||
| 95 | } | |||
| 96 | ||||
| 97 | /* | |||
| 98 | * Collect extensions matching filter into a name-sorted, NULL-terminated | |||
| 99 | * array so the plugin listings in general_help() print alphabetically | |||
| 100 | * regardless of registration order. Caller must free() the result. | |||
| 101 | */ | |||
| 102 | static struct plugin **sorted_extensions(struct plugin *extensions, enum ext_filter filter, | |||
| 103 | const char *group_title) | |||
| 104 | { | |||
| 105 | struct plugin *extension; | |||
| 106 | struct plugin **list; | |||
| 107 | size_t count = 0, i = 0; | |||
| 108 | ||||
| 109 | for (extension = extensions; extension; extension = extension->next) | |||
| 110 | if (extension_matches(extension, filter, group_title)) | |||
| 111 | count++; | |||
| 112 | ||||
| 113 | list = malloc((count + 1) * sizeof(*list)); | |||
| 114 | if (!list) | |||
| 115 | return NULL((void*)0); | |||
| 116 | ||||
| 117 | for (extension = extensions; extension; extension = extension->next) | |||
| 118 | if (extension_matches(extension, filter, group_title)) | |||
| 119 | list[i++] = extension; | |||
| 120 | list[i] = NULL((void*)0); | |||
| 121 | ||||
| 122 | qsort(list, count, sizeof(*list), plugin_name_cmp); | |||
| 123 | ||||
| 124 | return list; | |||
| 125 | } | |||
| 126 | ||||
| 127 | static void usage_cmd(struct plugin *plugin) | |||
| 128 | { | |||
| 129 | struct program *prog = plugin->parent; | |||
| 130 | ||||
| 131 | if (plugin->name) | |||
| 132 | printf("usage: %s %s %s\n", prog->name, plugin->name, prog->usage); | |||
| 133 | else | |||
| 134 | printf("usage: %s %s\n", prog->name, prog->usage); | |||
| 135 | } | |||
| 136 | ||||
| 137 | static void build_command_usage(char *use, size_t size, struct program *prog, | |||
| 138 | struct plugin *plugin, struct command *cmd) | |||
| 139 | { | |||
| 140 | const char *device = cmd->no_device ? "" : " <device>"; | |||
| 141 | ||||
| 142 | if (!plugin->name) | |||
| 143 | snprintf(use, size, "%s %s%s [OPTIONS]", prog->name, cmd->name, device); | |||
| 144 | else | |||
| 145 | snprintf(use, size, "%s %s %s%s [OPTIONS]", prog->name, plugin->name, | |||
| 146 | cmd->name, device); | |||
| 147 | } | |||
| 148 | ||||
| 149 | void plugin_add_group(struct plugin *plugin, const char *title, | |||
| 150 | struct command **commands) | |||
| 151 | { | |||
| 152 | struct command_group *group, **tail; | |||
| 153 | struct command **merged; | |||
| 154 | size_t old_count = 0, new_count = 0; | |||
| 155 | ||||
| 156 | group = malloc(sizeof(*group)); | |||
| 157 | if (!group) | |||
| 158 | return; | |||
| 159 | group->title = title; | |||
| 160 | group->commands = commands; | |||
| 161 | group->next = NULL((void*)0); | |||
| 162 | ||||
| 163 | for (tail = &plugin->groups; *tail; tail = &(*tail)->next) | |||
| 164 | ; | |||
| 165 | *tail = group; | |||
| 166 | ||||
| 167 | if (plugin->commands) | |||
| 168 | while (plugin->commands[old_count]) | |||
| 169 | old_count++; | |||
| 170 | while (commands[new_count]) | |||
| 171 | new_count++; | |||
| 172 | ||||
| 173 | merged = realloc(plugin->commands, (old_count + new_count + 1) * sizeof(*merged)); | |||
| 174 | if (!merged) | |||
| 175 | return; | |||
| 176 | ||||
| 177 | memcpy(&merged[old_count], commands, (new_count + 1) * sizeof(*merged)); | |||
| 178 | plugin->commands = merged; | |||
| 179 | } | |||
| 180 | ||||
| 181 | static void print_device_desc(void) | |||
| 182 | { | |||
| 183 | printf("'<device>' is one of:\n"); | |||
| 184 | printf(" - an NVMe controller device (ex: /dev/nvme0)\n"); | |||
| 185 | printf(" - an NVMe namespace device (ex: /dev/nvme0n1)\n"); | |||
| 186 | #ifdef CONFIG_MI | |||
| 187 | printf(" - a mctp address (ex: mctp:<net>,<eid>[:ctrl-id])\n"); | |||
| 188 | #endif | |||
| 189 | } | |||
| 190 | ||||
| 191 | void general_help(struct plugin *plugin, char *str) | |||
| 192 | { | |||
| 193 | struct program *prog = plugin->parent; | |||
| 194 | struct plugin *extension; | |||
| 195 | unsigned int i = 0; | |||
| 196 | unsigned int padding = 15; | |||
| 197 | unsigned int curr_length = 0; | |||
| 198 | bool_Bool have_deprecated = false0; | |||
| 199 | bool_Bool needs_device = false0; | |||
| 200 | ||||
| 201 | for (i = 0; plugin->commands[i]; i++) { | |||
| 202 | if (!plugin->commands[i]->no_device) { | |||
| 203 | needs_device = true1; | |||
| 204 | break; | |||
| 205 | } | |||
| 206 | } | |||
| 207 | ||||
| 208 | printf("%s-%s\n", prog->name, prog->version); | |||
| 209 | ||||
| 210 | usage_cmd(plugin); | |||
| 211 | ||||
| 212 | if (prog->desc) { | |||
| 213 | printf("\n"); | |||
| 214 | shr_print_word_wrapped(prog->desc, 0, 0, stdoutstdout); | |||
| 215 | printf("\n"); | |||
| 216 | } | |||
| 217 | ||||
| 218 | if (needs_device) { | |||
| 219 | printf("\n"); | |||
| 220 | print_device_desc(); | |||
| 221 | } | |||
| 222 | ||||
| 223 | if (plugin->desc) { | |||
| 224 | printf("\n"); | |||
| 225 | shr_print_word_wrapped(plugin->desc, 0, 0, stdoutstdout); | |||
| 226 | printf("\n"); | |||
| 227 | } | |||
| 228 | ||||
| 229 | printf("\nThe following are all implemented sub-commands:\n"); | |||
| 230 | if (str) | |||
| 231 | printf("Note: Only sub-commands including %s\n", str); | |||
| 232 | ||||
| 233 | /* | |||
| 234 | * iterate through all commands to get maximum length | |||
| 235 | * Still need to handle the case of ultra long strings, help messages, etc | |||
| 236 | */ | |||
| 237 | for (i = 0; plugin->commands[i]; i++) { | |||
| 238 | curr_length = 2 + strlen(plugin->commands[i]->name); | |||
| 239 | if (padding < curr_length) | |||
| 240 | padding = curr_length; | |||
| 241 | if (plugin->commands[i]->deprecated) | |||
| 242 | have_deprecated = true1; | |||
| 243 | } | |||
| 244 | ||||
| 245 | if (plugin->groups) { | |||
| 246 | struct command_group *group; | |||
| 247 | ||||
| 248 | for (group = plugin->groups; group; group = group->next) { | |||
| 249 | bool_Bool header_printed = false0; | |||
| 250 | ||||
| 251 | for (i = 0; group->commands[i]; i++) { | |||
| 252 | struct command *command = group->commands[i]; | |||
| 253 | ||||
| 254 | if (command->deprecated) | |||
| 255 | continue; | |||
| 256 | if (str && !strstr(command->name, str)_Generic (0 ? (command->name) : (void *) 1, const void *: ( const char *) (strstr (command->name, str)), default: strstr (command->name, str))) | |||
| 257 | continue; | |||
| 258 | if (!header_printed && group->title) { | |||
| 259 | printf("\n\033[1m%s:\033[0m\n", group->title); | |||
| 260 | header_printed = true1; | |||
| 261 | } | |||
| 262 | printf(" %-*s %s\n", padding, command->name, command->help); | |||
| 263 | } | |||
| 264 | ||||
| 265 | /* | |||
| 266 | * Core plugins tagged with .group are shown next to the | |||
| 267 | * built-in group they relate to instead of the flat | |||
| 268 | * "core NVMe/NVMeoF plugins" list further down. | |||
| 269 | */ | |||
| 270 | if (!plugin->name && group->title) { | |||
| 271 | __cleanup_free__attribute__((cleanup(shr_freep))) struct plugin **sorted = | |||
| 272 | sorted_extensions(prog->extensions->next, EXT_GROUP, | |||
| 273 | group->title); | |||
| 274 | size_t j; | |||
| 275 | ||||
| 276 | for (j = 0; sorted && sorted[j]; j++) { | |||
| 277 | extension = sorted[j]; | |||
| 278 | ||||
| 279 | if (str && !strstr(extension->name, str)_Generic (0 ? (extension->name) : (void *) 1, const void * : (const char *) (strstr (extension->name, str)), default: strstr (extension->name, str))) | |||
| 280 | continue; | |||
| 281 | if (!header_printed) { | |||
| 282 | printf("\n\033[1m%s:\033[0m\n", group->title); | |||
| 283 | header_printed = true1; | |||
| 284 | } | |||
| 285 | printf(" %-*s %s\n", padding, extension->name, | |||
| 286 | extension->desc); | |||
| 287 | } | |||
| 288 | } | |||
| 289 | } | |||
| 290 | } else { | |||
| 291 | /* Not yet migrated to plugin_add_group(): flat listing. */ | |||
| 292 | for (i = 0; plugin->commands[i]; i++) { | |||
| 293 | if (plugin->commands[i]->deprecated) | |||
| 294 | continue; | |||
| 295 | if (!str || strstr(plugin->commands[i]->name, str)_Generic (0 ? (plugin->commands[i]->name) : (void *) 1, const void *: (const char *) (strstr (plugin->commands[i] ->name, str)), default: strstr (plugin->commands[i]-> name, str))) | |||
| 296 | printf(" %-*s %s\n", padding, plugin->commands[i]->name, | |||
| 297 | plugin->commands[i]->help); | |||
| 298 | } | |||
| 299 | } | |||
| 300 | ||||
| 301 | printf("\n"); | |||
| 302 | if (!str || strstr("version", str)_Generic (0 ? ("version") : (void *) 1, const void *: (const char *) (strstr ("version", str)), default: strstr ("version", str ))) | |||
| 303 | printf(" %-*s %s\n", padding, "version", "Shows the program version"); | |||
| 304 | if (!str || strstr("help", str)_Generic (0 ? ("help") : (void *) 1, const void *: (const char *) (strstr ("help", str)), default: strstr ("help", str))) | |||
| 305 | printf(" %-*s %s\n", padding, "help", "Display this help"); | |||
| 306 | printf("\n"); | |||
| 307 | ||||
| 308 | if (plugin->name) | |||
| 309 | printf("See '%s %s help <command>' for more information on a specific command\n", | |||
| 310 | prog->name, plugin->name); | |||
| 311 | else | |||
| 312 | printf("See '%s help <command>' for more information on a specific command\n", | |||
| 313 | prog->name); | |||
| 314 | ||||
| 315 | /* | |||
| 316 | * The first plugin is the built-in. If we're not showing help for the | |||
| 317 | * built-in, don't show the program's other extensions | |||
| 318 | */ | |||
| 319 | if (!plugin->name) { | |||
| 320 | bool_Bool have_core = false0, have_vendor = false0; | |||
| 321 | ||||
| 322 | extension = prog->extensions->next; | |||
| 323 | while (extension) { | |||
| 324 | if (extension->core && !extension->group) | |||
| 325 | have_core = true1; | |||
| 326 | else if (!extension->core) | |||
| 327 | have_vendor = true1; | |||
| 328 | extension = extension->next; | |||
| 329 | } | |||
| 330 | ||||
| 331 | if (have_core) { | |||
| 332 | __cleanup_free__attribute__((cleanup(shr_freep))) struct plugin **sorted = | |||
| 333 | sorted_extensions(prog->extensions->next, EXT_CORE_ONLY, NULL((void*)0)); | |||
| 334 | size_t j; | |||
| 335 | ||||
| 336 | printf("\nThe following are core NVMe/NVMeoF plugins:\n"); | |||
| 337 | if (str) | |||
| 338 | printf("Note: Only extensions including %s\n", str); | |||
| 339 | ||||
| 340 | for (j = 0; sorted && sorted[j]; j++) { | |||
| 341 | if (!str || strstr(sorted[j]->name, str)_Generic (0 ? (sorted[j]->name) : (void *) 1, const void * : (const char *) (strstr (sorted[j]->name, str)), default: strstr (sorted[j]->name, str))) | |||
| 342 | printf(" %-*s %s\n", 15, sorted[j]->name, sorted[j]->desc); | |||
| 343 | } | |||
| 344 | } | |||
| 345 | ||||
| 346 | if (have_vendor) { | |||
| 347 | __cleanup_free__attribute__((cleanup(shr_freep))) struct plugin **sorted = | |||
| 348 | sorted_extensions(prog->extensions->next, EXT_VENDOR, NULL((void*)0)); | |||
| 349 | size_t j; | |||
| 350 | ||||
| 351 | printf("\nThe following are vendor specific plugins:\n"); | |||
| 352 | if (str) | |||
| 353 | printf("Note: Only extensions including %s\n", str); | |||
| 354 | ||||
| 355 | for (j = 0; sorted && sorted[j]; j++) { | |||
| 356 | if (!str || strstr(sorted[j]->name, str)_Generic (0 ? (sorted[j]->name) : (void *) 1, const void * : (const char *) (strstr (sorted[j]->name, str)), default: strstr (sorted[j]->name, str))) | |||
| 357 | printf(" %-*s %s\n", 15, sorted[j]->name, sorted[j]->desc); | |||
| 358 | } | |||
| 359 | } | |||
| 360 | ||||
| 361 | if (have_core || have_vendor) | |||
| 362 | printf("\nSee '%s <plugin> help' for more information on a plugin\n", | |||
| 363 | prog->name); | |||
| 364 | } | |||
| 365 | ||||
| 366 | if (have_deprecated) { | |||
| 367 | printf("\nThe following sub-commands are deprecated and will be removed in the next major version:\n"); | |||
| 368 | if (str) | |||
| 369 | printf("Note: Only sub-commands including %s\n", str); | |||
| 370 | ||||
| 371 | i = 0; | |||
| 372 | for (; plugin->commands[i]; i++) { | |||
| 373 | if (!plugin->commands[i]->deprecated) | |||
| 374 | continue; | |||
| 375 | if (!str || strstr(plugin->commands[i]->name, str)_Generic (0 ? (plugin->commands[i]->name) : (void *) 1, const void *: (const char *) (strstr (plugin->commands[i] ->name, str)), default: strstr (plugin->commands[i]-> name, str))) | |||
| 376 | printf(" %-*s %s\n", padding, plugin->commands[i]->name, | |||
| 377 | plugin->commands[i]->help); | |||
| 378 | } | |||
| 379 | } | |||
| 380 | } | |||
| 381 | ||||
| 382 | int handle_plugin(int argc, char **argv, struct plugin *plugin) | |||
| 383 | { | |||
| 384 | char use[0x100]; | |||
| 385 | struct plugin *extension; | |||
| 386 | struct program *prog = plugin->parent; | |||
| 387 | struct command **cmd = plugin->commands; | |||
| 388 | struct command *cr = NULL((void*)0); | |||
| 389 | bool_Bool opt_help = false0, opt_version = false0; | |||
| 390 | bool_Bool cr_valid = false0; | |||
| 391 | char *str; | |||
| 392 | int err; | |||
| 393 | ||||
| 394 | if (!argc) { | |||
| ||||
| 395 | general_help(plugin, NULL((void*)0)); | |||
| 396 | return 0; | |||
| 397 | } | |||
| 398 | ||||
| 399 | /* | |||
| 400 | * look for global options before the sub command parser and | |||
| 401 | * pre-fill the global nvme_args variable. | |||
| 402 | */ | |||
| 403 | NVME_ARGS(global_opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; struct argconfig_commandline_options global_opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options" , 0, ((void*)0)}, {"help", 'h', ((void*)0), CFG_FLAG, &opt_help , 0, "show help text", 0, }, {"version", 'V', ((void*)0), CFG_FLAG , &opt_version, 0, "show version", 0, }, {"", 0, ((void*) 0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0, ( (void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args .verbose, 0, "Increase output verbosity", 0, }, {"quiet", 0, ( (void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1 , "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void *)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 404 | OPT_FLAG("help", 'h', &opt_help, "show help text"),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; struct argconfig_commandline_options global_opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options" , 0, ((void*)0)}, {"help", 'h', ((void*)0), CFG_FLAG, &opt_help , 0, "show help text", 0, }, {"version", 'V', ((void*)0), CFG_FLAG , &opt_version, 0, "show version", 0, }, {"", 0, ((void*) 0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0, ( (void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args .verbose, 0, "Increase output verbosity", 0, }, {"quiet", 0, ( (void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1 , "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void *)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } } | |||
| 405 | OPT_FLAG("version", 'V', &opt_version, "show version"))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY) ; struct argconfig_commandline_options global_opts[] = { {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options" , 0, ((void*)0)}, {"help", 'h', ((void*)0), CFG_FLAG, &opt_help , 0, "show help text", 0, }, {"version", 'V', ((void*)0), CFG_FLAG , &opt_version, 0, "show version", 0, }, {"", 0, ((void*) 0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Global options", 0, ( (void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT, &nvme_args .verbose, 0, "Increase output verbosity", 0, }, {"quiet", 0, ( (void*)0), CFG_FLAG, &nvme_args.quiet, 0, "suppress informational output" , 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args .output_format, 1, "Output format: normal|json|binary", 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout, 1 , "timeout value, in milliseconds", 0, }, {"dry-run", 0, ((void *)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing" , 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args .no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing" , 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0 , "disable 64-bit IOCTL support probing", 0, }, {"output-format-version" , 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1 , "output format version: 1|2", 0, }, {"human-readable", 'H', ((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0), 0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING , &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);" , 0, }, { ((void*)0) } }; | |||
| 406 | err = argconfig_parse_global(argc, argv, global_opts); | |||
| 407 | if (err) { | |||
| 408 | general_help(plugin, NULL((void*)0)); | |||
| 409 | return err; | |||
| 410 | } | |||
| 411 | ||||
| 412 | argc -= optind; | |||
| 413 | argv += optind; | |||
| 414 | ||||
| 415 | if (opt_help) { | |||
| 416 | __cleanup_free__attribute__((cleanup(shr_freep))) char **help_argv = NULL((void*)0); | |||
| 417 | __cleanup_free__attribute__((cleanup(shr_freep))) char *help_name = NULL((void*)0); | |||
| 418 | ||||
| 419 | if (argc <= 0) { | |||
| 420 | general_help(plugin, NULL((void*)0)); | |||
| 421 | return 0; | |||
| 422 | } | |||
| 423 | ||||
| 424 | help_argv = malloc((argc + 1) * sizeof(*help_argv)); | |||
| 425 | if (!help_argv) | |||
| 426 | return -ENOMEM12; | |||
| 427 | ||||
| 428 | help_name = strdup("help"); | |||
| 429 | if (!help_name) | |||
| 430 | return -ENOMEM12; | |||
| 431 | ||||
| 432 | help_argv[0] = help_name; | |||
| 433 | memcpy(&help_argv[1], argv, argc * sizeof(*argv)); | |||
| 434 | return help(argc + 1, help_argv, plugin); | |||
| 435 | } | |||
| 436 | ||||
| 437 | if (opt_version) | |||
| 438 | return version_cmd(plugin); | |||
| 439 | ||||
| 440 | if (!argc) { | |||
| 441 | general_help(plugin, NULL((void*)0)); | |||
| 442 | return 0; | |||
| 443 | } | |||
| 444 | ||||
| 445 | str = argv[0]; | |||
| 446 | ||||
| 447 | if (!strcmp(str, "help")) | |||
| 448 | return help(argc, argv, plugin); | |||
| 449 | if (!strcmp(str, "version")) | |||
| 450 | return version_cmd(plugin); | |||
| 451 | ||||
| 452 | while (*cmd) { | |||
| 453 | if (!strcmp(str, (*cmd)->name) || | |||
| 454 | ((*cmd)->alias && !strcmp(str, (*cmd)->alias))) { | |||
| 455 | build_command_usage(use, sizeof(use), prog, plugin, *cmd); | |||
| 456 | argconfig_append_usage(use); | |||
| 457 | return (*cmd)->fn(argc, argv, *cmd, plugin); | |||
| 458 | } | |||
| 459 | if (!strncmp(str, (*cmd)->name, strlen(str))) { | |||
| 460 | if (cr) { | |||
| 461 | cr_valid = false0; | |||
| 462 | } else { | |||
| 463 | cr = *cmd; | |||
| 464 | cr_valid = true1; | |||
| 465 | } | |||
| 466 | } | |||
| 467 | cmd++; | |||
| 468 | } | |||
| 469 | ||||
| 470 | if (cr
| |||
| 471 | build_command_usage(use, sizeof(use), prog, plugin, cr); | |||
| 472 | argconfig_append_usage(use); | |||
| 473 | return cr->fn(argc, argv, cr, plugin); | |||
| 474 | } | |||
| 475 | ||||
| 476 | /* Check extensions only if this is running the built-in plugin */ | |||
| 477 | if (plugin->name) { | |||
| 478 | fprintf(stderrstderr, "ERROR: Invalid sub-command '%s' for plugin %s\n", str, plugin->name); | |||
| 479 | return -ENOTTY25; | |||
| 480 | } | |||
| 481 | ||||
| 482 | extension = plugin->next; | |||
| 483 | while (extension) { | |||
| 484 | if (!strcmp(str, extension->name)) | |||
| 485 | return handle_plugin(argc, argv, extension); | |||
| 486 | extension = extension->next; | |||
| 487 | } | |||
| 488 | ||||
| 489 | /* | |||
| 490 | * If the command is executed with the extension name and | |||
| 491 | * command together ("plugin-command"), run the plug in | |||
| 492 | */ | |||
| 493 | extension = plugin->next; | |||
| 494 | while (extension) { | |||
| 495 | if (!strncmp(str, extension->name, strlen(extension->name))) { | |||
| 496 | __cleanup_free__attribute__((cleanup(shr_freep))) char **sub_argv = NULL((void*)0); | |||
| 497 | __cleanup_free__attribute__((cleanup(shr_freep))) char *name_copy = NULL((void*)0); | |||
| 498 | ||||
| 499 | sub_argv = malloc((argc + 1) * sizeof(*sub_argv)); | |||
| 500 | if (!sub_argv) | |||
| 501 | return -ENOMEM12; | |||
| 502 | ||||
| 503 | argv[0] += strlen(extension->name); | |||
| 504 | while (*argv[0] == '-') | |||
| 505 | argv[0]++; | |||
| 506 | ||||
| 507 | name_copy = strdup(extension->name); | |||
| 508 | if (!name_copy) | |||
| 509 | return -ENOMEM12; | |||
| ||||
| 510 | ||||
| 511 | sub_argv[0] = name_copy; | |||
| 512 | memcpy(&sub_argv[1], argv, argc * sizeof(*argv)); | |||
| 513 | ||||
| 514 | return handle_plugin(argc + 1, sub_argv, extension); | |||
| 515 | } | |||
| 516 | extension = extension->next; | |||
| 517 | } | |||
| 518 | fprintf(stderrstderr, "ERROR: Invalid sub-command '%s'\n", str); | |||
| 519 | return -ENOTTY25; | |||
| 520 | } |