// SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include "plugin.h" #include "util/argconfig.h" #include static int version_cmd(struct plugin *plugin) { struct program *prog = plugin->parent; if (plugin->name) { printf("%s %s version %s (git %s)\n", prog->name, plugin->name, plugin->version, GIT_VERSION); } else { printf("%s version %s (git %s)\n", prog->name, prog->version, GIT_VERSION); } printf("libnvme version %s (git %s)\n", nvme_get_version(NVME_VERSION_PROJECT), nvme_get_version(NVME_VERSION_GIT)); return 0; } static int help(int argc, char **argv, struct plugin *plugin) { char man[0x100]; struct program *prog = plugin->parent; char *str = argv[1]; int i; if (argc == 1) { general_help(plugin); return 0; } for (i = 0; plugin->commands[i]; i++) { struct command *cmd = plugin->commands[i]; if (strcmp(str, cmd->name)) if (!cmd->alias || (cmd->alias && strcmp(str, cmd->alias))) continue; if (plugin->name) sprintf(man, "%s-%s-%s", prog->name, plugin->name, cmd->name); else sprintf(man, "%s-%s", prog->name, cmd->name); if (execlp("man", "man", man, (char *)NULL)) perror(argv[1]); } return 0; } static void usage_cmd(struct plugin *plugin) { struct program *prog = plugin->parent; if (plugin->name) printf("usage: %s %s %s\n", prog->name, plugin->name, prog->usage); else printf("usage: %s %s\n", prog->name, prog->usage); } void general_help(struct plugin *plugin) { struct program *prog = plugin->parent; struct plugin *extension; unsigned int i = 0; unsigned int padding = 15; unsigned int curr_length = 0; printf("%s-%s\n", prog->name, prog->version); usage_cmd(plugin); printf("\n"); print_word_wrapped(prog->desc, 0, 0, stdout); printf("\n"); if (plugin->desc) { printf("\n"); print_word_wrapped(plugin->desc, 0, 0, stdout); printf("\n"); } printf("\nThe following are all implemented sub-commands:\n"); /* * iterate through all commands to get maximum length * Still need to handle the case of ultra long strings, help messages, etc */ for (; plugin->commands[i]; i++) { curr_length = 2 + strlen(plugin->commands[i]->name); if (padding < curr_length) padding = curr_length; } i = 0; for (; plugin->commands[i]; i++) printf(" %-*s %s\n", padding, plugin->commands[i]->name, plugin->commands[i]->help); printf(" %-*s %s\n", padding, "version", "Shows the program version"); printf(" %-*s %s\n", padding, "help", "Display this help"); printf("\n"); if (plugin->name) printf("See '%s %s help ' for more information on a specific command\n", prog->name, plugin->name); else printf("See '%s help ' for more information on a specific command\n", prog->name); /* * The first plugin is the built-in. If we're not showing help for the * built-in, don't show the program's other extensions */ if (plugin->name) return; extension = prog->extensions->next; if (!extension) return; printf("\nThe following are all installed plugin extensions:\n"); while (extension) { printf(" %-*s %s\n", 15, extension->name, extension->desc); extension = extension->next; } printf("\nSee '%s help' for more information on a plugin\n", prog->name); } 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; struct command **cmd = plugin->commands; struct command *cr = NULL; bool cr_valid = false; if (!argc) { general_help(plugin); return 0; } if (!plugin->name) sprintf(use, "%s %s [OPTIONS]", prog->name, str); else sprintf(use, "%s %s %s [OPTIONS]", prog->name, plugin->name, str); argconfig_append_usage(use); /* translate --help and --version into commands */ while (*str == '-') str++; if (!strcmp(str, "help")) return help(argc, argv, plugin); if (!strcmp(str, "version")) return version_cmd(plugin); while (*cmd) { if (!strcmp(str, (*cmd)->name) || ((*cmd)->alias && !strcmp(str, (*cmd)->alias))) return (*cmd)->fn(argc, argv, *cmd, plugin); if (!strncmp(str, (*cmd)->name, strlen(str))) { if (cr) { cr_valid = false; } else { cr = *cmd; cr_valid = true; } } cmd++; } if (cr && cr_valid) { sprintf(use, "%s %s [OPTIONS]", prog->name, cr->name); argconfig_append_usage(use); return cr->fn(argc, argv, cr, plugin); } /* Check extensions only if this is running the built-in plugin */ if (plugin->name) { printf("ERROR: Invalid sub-command '%s' for plugin %s\n", str, plugin->name); return -ENOTTY; } extension = plugin->next; while (extension) { if (!strcmp(str, extension->name)) return handle_plugin(argc - 1, &argv[1], extension); extension = extension->next; } /* * If the command is executed with the extension name and * command together ("plugin-command"), run the plug in */ extension = plugin->next; while (extension) { if (!strncmp(str, extension->name, strlen(extension->name))) { argv[0] += strlen(extension->name); while (*argv[0] == '-') argv[0]++; return handle_plugin(argc, &argv[0], extension); } extension = extension->next; } printf("ERROR: Invalid sub-command '%s'\n", str); return -ENOTTY; }