-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
+/*
* Copyright (C) 2001 Cluster File Systems, Inc.
*
+ * Copyright (c) 2014, 2017, Intel Corporation.
+ *
* This file is part of Lustre, http://www.sf.net/projects/lustre/
*
* Lustre is free software; you can redistribute it and/or
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
+
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
+#include <assert.h>
#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <malloc.h>
+#ifdef HAVE_LIBREADLINE
+# include <readline/history.h>
+# include <readline/readline.h>
+#endif /* HAVE_LIBREADLINE */
#include <string.h>
-#include <stddef.h>
#include <unistd.h>
-#include <sys/param.h>
-#include <assert.h>
-#include <libcfs/libcfsutil.h>
+#include <libcfs/util/parser.h>
+#include <linux/lustre/lustre_ver.h>
static command_t * top_level; /* Top level of commands, initialized by
* InitParser */
static char *skiptowhitespace(char *s);
static command_t *find_cmd(char *name, command_t cmds[], char **next);
static int process(char *s, char **next, command_t *lookup, command_t **result,
- char **prev);
-static void print_commands(char *str, command_t *table);
+ char **prev);
static char * skipwhitespace(char * s)
{
static int line2args(char *line, char **argv, int maxargs)
{
- char *arg;
- int i = 0;
+ char *arg;
+ int i = 0;
- arg = strtok(line, " \t");
- if ( arg ) {
- argv[i] = arg;
- i++;
- } else
- return 0;
+ arg = strtok(line, " \t");
+ if (arg == NULL || maxargs < 1)
+ return 0;
- while( (arg = strtok(NULL, " \t")) && (i <= maxargs)) {
- argv[i] = arg;
- i++;
- }
- return i;
+ argv[i++] = arg;
+ while ((arg = strtok(NULL, " \t")) != NULL && i < maxargs)
+ argv[i++] = arg;
+ return i;
}
/* find a command -- return it if unique otherwise print alternatives */
int Parser_execarg(int argc, char **argv, command_t cmds[])
{
- command_t *cmd;
-
- cmd = Parser_findargcmd(argv[0], cmds);
- if ( cmd ) {
- int rc = (cmd->pc_func)(argc, argv);
- if (rc == CMD_HELP)
- fprintf(stderr, "%s\n", cmd->pc_help);
- return rc;
- } else {
+ command_t *cmd;
+
+ cmd = Parser_findargcmd(argv[0], cmds);
+ if (cmd != NULL && cmd->pc_func != NULL) {
+ int rc = (cmd->pc_func)(argc, argv);
+ if (rc == CMD_HELP)
+ fprintf(stderr, "%s\n", cmd->pc_help);
+ return rc;
+ } else {
printf("Try interactive use without arguments or use one of:\n");
- for (cmd = cmds; cmd->pc_name; cmd++)
- printf("\"%s\"\n", cmd->pc_name);
- printf("as argument.\n");
- }
- return -1;
+ for (cmd = cmds; cmd->pc_name; cmd++)
+ printf("\"%s\"\n", cmd->pc_name);
+ printf("as argument.\n");
+ }
+ return -1;
}
/* returns the command_t * (NULL if not found) corresponding to a
this with strtok*/
name = skipwhitespace(name);
*next = skiptowhitespace(name);
- len = *next - name;
+ len = (int)(*next - name);
if (len == 0)
return NULL;
}
got_it:
- /* found a unique command: component or full? */
- if ( (*result)->pc_func ) {
- return CMD_COMPLETE;
- } else {
- if ( *next == '\0' ) {
- return CMD_INCOMPLETE;
- } else {
- return process(*next, next, (*result)->pc_sub_cmd,
- result, prev);
- }
- }
+ /* found a unique command: component or full? */
+ if ((*result)->pc_func != NULL) {
+ return CMD_COMPLETE;
+ } else {
+ if (**next == '\0') {
+ return CMD_INCOMPLETE;
+ } else {
+ return process(*next, next, (*result)->pc_sub_cmd,
+ result, prev);
+ }
+ }
}
#ifdef HAVE_LIBREADLINE
}
/* probably called by readline */
-static char **command_completion(char * text, int start, int end)
+static char **command_completion(const char *text, int start, int end)
{
command_t * table;
char * pos;
if (*(pos - 1) == ' ') match_tbl = table->pc_sub_cmd;
}
- return completion_matches(text, command_generator);
+ return rl_completion_matches(text, command_generator);
}
#endif
/* take a string and execute the function or print help */
int execute_line(char * line)
{
- command_t *cmd, *ambig;
- char *prev;
- char *next, *tmp;
- char *argv[MAXARGS];
- int i;
- int rc = 0;
-
- switch (process(line, &next, top_level, &cmd, &prev)) {
- case CMD_AMBIG:
- fprintf(stderr, "Ambiguous command \'%s\'\nOptions: ", line);
- while( (ambig = find_cmd(prev, cmd, &tmp)) ) {
- fprintf(stderr, "%s ", ambig->pc_name);
- cmd = ambig + 1;
- }
- fprintf(stderr, "\n");
- break;
- case CMD_NONE:
- fprintf(stderr, "No such command, type help\n");
- break;
- case CMD_INCOMPLETE:
- fprintf(stderr,
- "'%s' incomplete command. Use '%s x' where x is one of:\n",
- line, line);
- fprintf(stderr, "\t");
- for (i = 0; cmd->pc_sub_cmd[i].pc_name; i++) {
- fprintf(stderr, "%s ", cmd->pc_sub_cmd[i].pc_name);
- }
- fprintf(stderr, "\n");
- break;
- case CMD_COMPLETE:
- i = line2args(line, argv, MAXARGS);
- rc = (cmd->pc_func)(i, argv);
-
- if (rc == CMD_HELP)
- fprintf(stderr, "%s\n", cmd->pc_help);
-
- break;
- }
-
- return rc;
+ command_t *cmd, *ambig;
+ char *prev;
+ char *next, *tmp;
+ char *argv[MAXARGS];
+ int i;
+ int rc = 0;
+
+ switch (process(line, &next, top_level, &cmd, &prev)) {
+ case CMD_AMBIG:
+ fprintf(stderr, "Ambiguous command \'%s\'\nOptions: ", line);
+ while ((ambig = find_cmd(prev, cmd, &tmp))) {
+ fprintf(stderr, "%s ", ambig->pc_name);
+ cmd = ambig + 1;
+ }
+ fprintf(stderr, "\n");
+ break;
+ case CMD_NONE:
+ fprintf(stderr, "No such command, type help\n");
+ break;
+ case CMD_INCOMPLETE:
+ fprintf(stderr, "'%s' incomplete command. Use '%s x' where "
+ "x is one of:\n", line, line);
+ fprintf(stderr, "\t");
+ for (i = 0; cmd->pc_sub_cmd[i].pc_name; i++)
+ fprintf(stderr, "%s ", cmd->pc_sub_cmd[i].pc_name);
+ fprintf(stderr, "\n");
+ break;
+ case CMD_COMPLETE:
+ optind = 0;
+ i = line2args(line, argv, MAXARGS);
+ rc = (cmd->pc_func)(i, argv);
+
+ if (rc == CMD_HELP)
+ fprintf(stderr, "%s\n", cmd->pc_help);
+
+ break;
+ }
+
+ return rc;
}
-int
-noop_fn ()
-{
- return (0);
-}
+#ifdef HAVE_LIBREADLINE
+static void noop_int_fn(int unused) { }
+static void noop_void_fn(void) { }
+#endif
/* just in case you're ever in an airplane and discover you
- forgot to install readline-dev. :) */
-int init_input()
+ * forgot to install readline-dev. :) */
+static int init_input(void)
{
- int interactive = isatty (fileno (stdin));
+ int interactive = isatty(fileno(stdin));
#ifdef HAVE_LIBREADLINE
- using_history();
- stifle_history(HISTORY);
+ using_history();
+ stifle_history(HISTORY);
- if (!interactive)
- {
- rl_prep_term_function = (rl_vintfunc_t *)noop_fn;
- rl_deprep_term_function = (rl_voidfunc_t *)noop_fn;
- }
+ if (!interactive) {
+ rl_prep_term_function = noop_int_fn;
+ rl_deprep_term_function = noop_void_fn;
+ }
- rl_attempted_completion_function = (CPPFunction *)command_completion;
- rl_completion_entry_function = (void *)command_generator;
+ rl_attempted_completion_function = command_completion;
+ rl_completion_entry_function = command_generator;
#endif
- return interactive;
+ return interactive;
}
#ifndef HAVE_LIBREADLINE
if ((c = fgetc(stdin)) != EOF) {
if (c == '\n')
goto out;
- *ptr++ = c;
+ *ptr++ = (char)c;
if (ptr - line >= size - 1) {
char *tmp;
void Parser_qhelp(int argc, char *argv[]) {
- printf("Available commands are:\n");
+ printf("usage: %s [COMMAND] [OPTIONS]... [ARGS]\n",
+ program_invocation_short_name);
+ printf("Without any parameters, interactive mode is invoked\n");
- print_commands(NULL, top_level);
- printf("For more help type: help command-name\n");
+ printf("Try '%s help <COMMAND>' or '%s --list-commands' for more information\n",
+ program_invocation_short_name, program_invocation_short_name);
}
int Parser_help(int argc, char **argv)
return 0;
}
- line[0]='\0';
- for ( i = 1 ; i < argc ; i++ ) {
- strcat(line, argv[i]);
- }
+ /* Joining command line arguments without space is not critical here
+ * because of this string is used for search a help topic and assume
+ * that only one argument will be (the name of topic). For example:
+ * lst > help ping run
+ * pingrun: Unknown command. */
+ line[0] = '\0';
+ for (i = 1; i < argc; i++) {
+ if (strlen(argv[i]) >= sizeof(line) - strlen(line))
+ return -E2BIG;
+ /* The function strlcat() cannot be used here because of
+ * this function is used in LNet utils that is not linked
+ * with libcfs.a. */
+ strncat(line, argv[i], sizeof(line) - strlen(line));
+ }
switch ( process(line, &next, top_level, &result, &prev) ) {
case CMD_COMPLETE:
/*************************************************************************
* COMMANDS *
*************************************************************************/
-static void print_commands(char * str, command_t * table) {
- command_t * cmds;
- char buf[80];
-
- for (cmds = table; cmds->pc_name; cmds++) {
- if (cmds->pc_func) {
- if (str) printf("\t%s %s\n", str, cmds->pc_name);
- else printf("\t%s\n", cmds->pc_name);
- }
- if (cmds->pc_sub_cmd) {
- if (str) {
- sprintf(buf, "%s %s", str, cmds->pc_name);
- print_commands(buf, cmds->pc_sub_cmd);
- } else {
- print_commands(cmds->pc_name, cmds->pc_sub_cmd);
- }
- }
- }
+
+/**
+ * Parser_list_commands() - Output a list of the supported commands.
+ * @cmdlist: Array of structures describing the commands.
+ * @buffer: String buffer used to temporarily store the output text.
+ * @buf_size: Length of the string buffer.
+ * @parent_cmd: When called recursively, contains the name of the parent cmd.
+ * @col_start: Column where printing should begin.
+ * @col_num: The number of commands printed in a single row.
+ *
+ * The commands and subcommands supported by the utility are printed, arranged
+ * into several columns for readability. If a command supports subcommands, the
+ * function is called recursively, and the name of the parent command is
+ * supplied so that it can be prepended to the names of the subcommands.
+ *
+ * Return: The number of items that were printed.
+ */
+int Parser_list_commands(const command_t *cmdlist, char *buffer,
+ size_t buf_size, const char *parent_cmd,
+ int col_start, int col_num)
+{
+ int col = col_start;
+ int char_max;
+ int len;
+ int count = 0;
+ int rc;
+
+ if (col_start >= col_num)
+ return 0;
+
+ char_max = (buf_size - 1) / col_num; /* Reserve 1 char for NUL */
+
+ for (; cmdlist->pc_name != NULL; cmdlist++) {
+ if (cmdlist->pc_func == NULL && cmdlist->pc_sub_cmd == NULL)
+ break;
+ count++;
+ if (parent_cmd != NULL)
+ len = snprintf(&buffer[col * char_max],
+ char_max + 1, "%s %s", parent_cmd,
+ cmdlist->pc_name);
+ else
+ len = snprintf(&buffer[col * char_max],
+ char_max + 1, "%s", cmdlist->pc_name);
+
+ /* Add trailing spaces to pad the entry to the column size */
+ if (len < char_max) {
+ snprintf(&buffer[col * char_max] + len,
+ char_max - len + 1, "%*s", char_max - len,
+ " ");
+ } else {
+ buffer[(col + 1) * char_max - 1] = ' ';
+ }
+
+ col++;
+ if (col >= col_num) {
+ fprintf(stdout, "%s\n", buffer);
+ col = 0;
+ buffer[0] = '\0';
+ }
+
+ if (cmdlist->pc_sub_cmd != NULL) {
+ rc = Parser_list_commands(cmdlist->pc_sub_cmd, buffer,
+ buf_size, cmdlist->pc_name,
+ col, col_num);
+ col = (col + rc) % col_num;
+ count += rc;
+ }
+ }
+ if (parent_cmd == NULL && col != 0)
+ fprintf(stdout, "%s\n", buffer);
+ return count;
}
char *Parser_getstr(const char *prompt, const char *deft, char *res,
line = readline(theprompt);
free(theprompt);
- if ( line == NULL || *line == '\0' ) {
- strncpy(res, deft, len);
- } else {
- strncpy(res, line, len);
- }
-
- if ( line ) {
- free(line);
- return res;
- } else {
- return NULL;
- }
+ /* The function strlcpy() cannot be used here because of
+ * this function is used in LNet utils that is not linked
+ * with libcfs.a. */
+ if (line == NULL || *line == '\0')
+ strncpy(res, deft, len);
+ else
+ strncpy(res, line, len);
+ res[len - 1] = '\0';
+
+ if (line != NULL) {
+ free(line);
+ return res;
+ }
+ return NULL;
}
/* get integer from prompt, loop forever to get it */
done = 1;
return 0;
}
+
+int Parser_version(int argc, char **argv)
+{
+ fprintf(stdout, "%s %s\n", program_invocation_short_name,
+ LUSTRE_VERSION_STRING);
+ return 0;
+}