diff options
Diffstat (limited to 'plugin.c')
-rw-r--r-- | plugin.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/plugin.c b/plugin.c new file mode 100644 index 0000000..a5cb4f9 --- /dev/null +++ b/plugin.c @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "plugin.h" +#include "util/argconfig.h" + +#include <libnvme.h> + +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 <command>' for more information on a specific command\n", + prog->name, plugin->name); + else + printf("See '%s help <command>' 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 <plugin> 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 <device> [OPTIONS]", prog->name, str); + else + sprintf(use, "%s %s %s <device> [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 <device> [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; +} |