218 lines
5.3 KiB
C
218 lines
5.3 KiB
C
// 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;
|
|
}
|