| File: | .build-ci/../plugin.c |
| Warning: | line 285, 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 <unistd.h> | |||
| 6 | ||||
| 7 | #include <libnvme.h> | |||
| 8 | ||||
| 9 | #include "nvme.h" | |||
| 10 | #include "plugin.h" | |||
| 11 | #include "util/argconfig.h" | |||
| 12 | #include "util/cleanup.h" | |||
| 13 | ||||
| 14 | static int version_cmd(struct plugin *plugin) | |||
| 15 | { | |||
| 16 | struct program *prog = plugin->parent; | |||
| 17 | ||||
| 18 | if (plugin->name) { | |||
| 19 | printf("%s %s version %s (git %s)\n", | |||
| 20 | prog->name, plugin->name, plugin->version, GIT_VERSION"3.0-a.5-312-g291cba4"); | |||
| 21 | } else { | |||
| 22 | printf("%s version %s (git %s)\n", | |||
| 23 | prog->name, prog->version, GIT_VERSION"3.0-a.5-312-g291cba4"); | |||
| 24 | } | |||
| 25 | printf("libnvme version %s (git %s)\n", | |||
| 26 | libnvme_get_version(LIBNVME_VERSION_PROJECT), | |||
| 27 | libnvme_get_version(LIBNVME_VERSION_GIT)); | |||
| 28 | return 0; | |||
| 29 | } | |||
| 30 | ||||
| 31 | static int help(int argc, char **argv, struct plugin *plugin) | |||
| 32 | { | |||
| 33 | char man[0x100]; | |||
| 34 | struct program *prog = plugin->parent; | |||
| 35 | char *str = argv[1]; | |||
| 36 | int i; | |||
| 37 | ||||
| 38 | if (argc == 1) { | |||
| 39 | general_help(plugin, NULL((void*)0)); | |||
| 40 | return 0; | |||
| 41 | } | |||
| 42 | ||||
| 43 | for (i = 0; plugin->commands[i]; i++) { | |||
| 44 | struct command *command = plugin->commands[i]; | |||
| 45 | ||||
| 46 | if (strcmp(str, command->name)) | |||
| 47 | if (!command->alias || | |||
| 48 | (command->alias && strcmp(str, command->alias))) | |||
| 49 | continue; | |||
| 50 | ||||
| 51 | if (plugin->name) | |||
| 52 | snprintf(man, sizeof(man), "%s-%s-%s", prog->name, | |||
| 53 | plugin->name, command->name); | |||
| 54 | else | |||
| 55 | snprintf(man, sizeof(man), "%s-%s", prog->name, command->name); | |||
| 56 | if (execlp("man", "man", man, (char *)NULL((void*)0))) | |||
| 57 | perror(argv[1]); | |||
| 58 | } | |||
| 59 | ||||
| 60 | general_help(plugin, str); | |||
| 61 | ||||
| 62 | return 0; | |||
| 63 | } | |||
| 64 | ||||
| 65 | static void usage_cmd(struct plugin *plugin) | |||
| 66 | { | |||
| 67 | struct program *prog = plugin->parent; | |||
| 68 | ||||
| 69 | if (plugin->name) | |||
| 70 | printf("usage: %s %s %s\n", prog->name, plugin->name, prog->usage); | |||
| 71 | else | |||
| 72 | printf("usage: %s %s\n", prog->name, prog->usage); | |||
| 73 | } | |||
| 74 | ||||
| 75 | void general_help(struct plugin *plugin, char *str) | |||
| 76 | { | |||
| 77 | struct program *prog = plugin->parent; | |||
| 78 | struct plugin *extension; | |||
| 79 | unsigned int i = 0; | |||
| 80 | unsigned int padding = 15; | |||
| 81 | unsigned int curr_length = 0; | |||
| 82 | ||||
| 83 | printf("%s-%s\n", prog->name, prog->version); | |||
| 84 | ||||
| 85 | usage_cmd(plugin); | |||
| 86 | ||||
| 87 | printf("\n"); | |||
| 88 | print_word_wrapped(prog->desc, 0, 0, stdoutstdout); | |||
| 89 | printf("\n"); | |||
| 90 | ||||
| 91 | if (plugin->desc) { | |||
| 92 | printf("\n"); | |||
| 93 | print_word_wrapped(plugin->desc, 0, 0, stdoutstdout); | |||
| 94 | printf("\n"); | |||
| 95 | } | |||
| 96 | ||||
| 97 | printf("\nThe following are all implemented sub-commands:\n"); | |||
| 98 | if (str) | |||
| 99 | printf("Note: Only sub-commands including %s\n", str); | |||
| 100 | ||||
| 101 | /* | |||
| 102 | * iterate through all commands to get maximum length | |||
| 103 | * Still need to handle the case of ultra long strings, help messages, etc | |||
| 104 | */ | |||
| 105 | for (; plugin->commands[i]; i++) { | |||
| 106 | curr_length = 2 + strlen(plugin->commands[i]->name); | |||
| 107 | if (padding < curr_length) | |||
| 108 | padding = curr_length; | |||
| 109 | } | |||
| 110 | ||||
| 111 | i = 0; | |||
| 112 | for (; plugin->commands[i]; i++) { | |||
| 113 | if (!str || strstr(plugin->commands[i]->name, str)) | |||
| 114 | printf(" %-*s %s\n", padding, plugin->commands[i]->name, | |||
| 115 | plugin->commands[i]->help); | |||
| 116 | } | |||
| 117 | ||||
| 118 | if (!str || strstr("version", str)) | |||
| 119 | printf(" %-*s %s\n", padding, "version", "Shows the program version"); | |||
| 120 | if (!str || strstr("help", str)) | |||
| 121 | printf(" %-*s %s\n", padding, "help", "Display this help"); | |||
| 122 | printf("\n"); | |||
| 123 | ||||
| 124 | if (plugin->name) | |||
| 125 | printf("See '%s %s help <command>' for more information on a specific command\n", | |||
| 126 | prog->name, plugin->name); | |||
| 127 | else | |||
| 128 | printf("See '%s help <command>' for more information on a specific command\n", | |||
| 129 | prog->name); | |||
| 130 | ||||
| 131 | /* | |||
| 132 | * The first plugin is the built-in. If we're not showing help for the | |||
| 133 | * built-in, don't show the program's other extensions | |||
| 134 | */ | |||
| 135 | if (plugin->name) | |||
| 136 | return; | |||
| 137 | ||||
| 138 | extension = prog->extensions->next; | |||
| 139 | if (!extension) | |||
| 140 | return; | |||
| 141 | ||||
| 142 | printf("\nThe following are all installed plugin extensions:\n"); | |||
| 143 | if (str) | |||
| 144 | printf("Note: Only extensions including %s\n", str); | |||
| 145 | ||||
| 146 | while (extension) { | |||
| 147 | if (!str || strstr(extension->name, str)) | |||
| 148 | printf(" %-*s %s\n", 15, extension->name, extension->desc); | |||
| 149 | extension = extension->next; | |||
| 150 | } | |||
| 151 | printf("\nSee '%s <plugin> help' for more information on a plugin\n", | |||
| 152 | prog->name); | |||
| 153 | } | |||
| 154 | ||||
| 155 | int handle_plugin(int argc, char **argv, struct plugin *plugin) | |||
| 156 | { | |||
| 157 | char use[0x100]; | |||
| 158 | struct plugin *extension; | |||
| 159 | struct program *prog = plugin->parent; | |||
| 160 | struct command **cmd = plugin->commands; | |||
| 161 | struct command *cr = NULL((void*)0); | |||
| 162 | bool_Bool opt_help = false0, opt_version = false0; | |||
| 163 | bool_Bool cr_valid = false0; | |||
| 164 | char *str; | |||
| 165 | int err; | |||
| 166 | ||||
| 167 | if (!argc) { | |||
| ||||
| 168 | general_help(plugin, NULL((void*)0)); | |||
| 169 | return 0; | |||
| 170 | } | |||
| 171 | ||||
| 172 | /* | |||
| 173 | * look for global options before the sub command parser and | |||
| 174 | * pre-fill the global nvme_args variable. | |||
| 175 | */ | |||
| 176 | NVME_ARGS(global_opts,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, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 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}, { ((void*)0) } } | |||
| 177 | OPT_FLAG("help", 'h', &opt_help, "show help text"),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, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 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}, { ((void*)0) } } | |||
| 178 | OPT_FLAG("version", 'V', &opt_version, "show version"))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, }, {"output-format" , 'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary|tabular" , 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}, { ((void*)0) } }; | |||
| 179 | err = argconfig_parse_global(argc, argv, global_opts); | |||
| 180 | if (err) { | |||
| 181 | general_help(plugin, NULL((void*)0)); | |||
| 182 | return err; | |||
| 183 | } | |||
| 184 | ||||
| 185 | argc -= optind; | |||
| 186 | argv += optind; | |||
| 187 | ||||
| 188 | if (opt_help) { | |||
| 189 | __cleanup_free__attribute__((cleanup(freep))) char **help_argv = NULL((void*)0); | |||
| 190 | __cleanup_free__attribute__((cleanup(freep))) char *help_name = NULL((void*)0); | |||
| 191 | ||||
| 192 | if (argc <= 0) { | |||
| 193 | general_help(plugin, NULL((void*)0)); | |||
| 194 | return 0; | |||
| 195 | } | |||
| 196 | ||||
| 197 | help_argv = malloc((argc + 1) * sizeof(*help_argv)); | |||
| 198 | if (!help_argv) | |||
| 199 | return -ENOMEM12; | |||
| 200 | ||||
| 201 | help_name = strdup("help"); | |||
| 202 | if (!help_name) | |||
| 203 | return -ENOMEM12; | |||
| 204 | ||||
| 205 | help_argv[0] = help_name; | |||
| 206 | memcpy(&help_argv[1], argv, argc * sizeof(*argv)); | |||
| 207 | return help(argc + 1, help_argv, plugin); | |||
| 208 | } | |||
| 209 | ||||
| 210 | if (opt_version) | |||
| 211 | return version_cmd(plugin); | |||
| 212 | ||||
| 213 | if (!argc) { | |||
| 214 | general_help(plugin, NULL((void*)0)); | |||
| 215 | return 0; | |||
| 216 | } | |||
| 217 | ||||
| 218 | str = argv[0]; | |||
| 219 | ||||
| 220 | if (!plugin->name) | |||
| 221 | snprintf(use, sizeof(use), "%s %s <device> [OPTIONS]", prog->name, str); | |||
| 222 | else | |||
| 223 | snprintf(use, sizeof(use), "%s %s %s <device> [OPTIONS]", prog->name, plugin->name, str); | |||
| 224 | argconfig_append_usage(use); | |||
| 225 | ||||
| 226 | if (!strcmp(str, "help")) | |||
| 227 | return help(argc, argv, plugin); | |||
| 228 | if (!strcmp(str, "version")) | |||
| 229 | return version_cmd(plugin); | |||
| 230 | ||||
| 231 | while (*cmd) { | |||
| 232 | if (!strcmp(str, (*cmd)->name) || | |||
| 233 | ((*cmd)->alias && !strcmp(str, (*cmd)->alias))) | |||
| 234 | return (*cmd)->fn(argc, argv, *cmd, plugin); | |||
| 235 | if (!strncmp(str, (*cmd)->name, strlen(str))) { | |||
| 236 | if (cr) { | |||
| 237 | cr_valid = false0; | |||
| 238 | } else { | |||
| 239 | cr = *cmd; | |||
| 240 | cr_valid = true1; | |||
| 241 | } | |||
| 242 | } | |||
| 243 | cmd++; | |||
| 244 | } | |||
| 245 | ||||
| 246 | if (cr
| |||
| 247 | snprintf(use, sizeof(use), "%s %s <device> [OPTIONS]", prog->name, cr->name); | |||
| 248 | argconfig_append_usage(use); | |||
| 249 | return cr->fn(argc, argv, cr, plugin); | |||
| 250 | } | |||
| 251 | ||||
| 252 | /* Check extensions only if this is running the built-in plugin */ | |||
| 253 | if (plugin->name
| |||
| 254 | printf("ERROR: Invalid sub-command '%s' for plugin %s\n", str, plugin->name); | |||
| 255 | return -ENOTTY25; | |||
| 256 | } | |||
| 257 | ||||
| 258 | extension = plugin->next; | |||
| 259 | while (extension) { | |||
| 260 | if (!strcmp(str, extension->name)) | |||
| 261 | return handle_plugin(argc, argv, extension); | |||
| 262 | extension = extension->next; | |||
| 263 | } | |||
| 264 | ||||
| 265 | /* | |||
| 266 | * If the command is executed with the extension name and | |||
| 267 | * command together ("plugin-command"), run the plug in | |||
| 268 | */ | |||
| 269 | extension = plugin->next; | |||
| 270 | while (extension) { | |||
| 271 | if (!strncmp(str, extension->name, strlen(extension->name))) { | |||
| 272 | __cleanup_free__attribute__((cleanup(freep))) char **sub_argv = NULL((void*)0); | |||
| 273 | __cleanup_free__attribute__((cleanup(freep))) char *name_copy = NULL((void*)0); | |||
| 274 | ||||
| 275 | sub_argv = malloc((argc + 1) * sizeof(*sub_argv)); | |||
| 276 | if (!sub_argv) | |||
| 277 | return -ENOMEM12; | |||
| 278 | ||||
| 279 | argv[0] += strlen(extension->name); | |||
| 280 | while (*argv[0] == '-') | |||
| 281 | argv[0]++; | |||
| 282 | ||||
| 283 | name_copy = strdup(extension->name); | |||
| 284 | if (!name_copy) | |||
| 285 | return -ENOMEM12; | |||
| ||||
| 286 | ||||
| 287 | sub_argv[0] = name_copy; | |||
| 288 | memcpy(&sub_argv[1], argv, argc * sizeof(*argv)); | |||
| 289 | ||||
| 290 | return handle_plugin(argc + 1, sub_argv, extension); | |||
| 291 | } | |||
| 292 | extension = extension->next; | |||
| 293 | } | |||
| 294 | printf("ERROR: Invalid sub-command '%s'\n", str); | |||
| 295 | return -ENOTTY25; | |||
| 296 | } |