diff options
Diffstat (limited to 'tools/lvm.c')
-rw-r--r-- | tools/lvm.c | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/tools/lvm.c b/tools/lvm.c index 2e9dab7e..b0256d7a 100644 --- a/tools/lvm.c +++ b/tools/lvm.c @@ -13,9 +13,233 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "tools.h" #include "lvm2cmdline.h" int main(int argc, char **argv) { return lvm2_main(argc, argv, 0); } + +#ifdef READLINE_SUPPORT + +# include <readline/readline.h> +# include <readline/history.h> +# ifndef HAVE_RL_COMPLETION_MATCHES +# define rl_completion_matches(a, b) completion_matches((char *)a, b) +# endif + +static struct cmdline_context *_cmdline; + +/* List matching commands */ +static char *_list_cmds(const char *text, int state) +{ + static int i = 0; + static size_t len = 0; + + /* Initialise if this is a new completion attempt */ + if (!state) { + i = 0; + len = strlen(text); + } + + while (i < _cmdline->num_commands) + if (!strncmp(text, _cmdline->commands[i++].name, len)) + return strdup(_cmdline->commands[i - 1].name); + + return NULL; +} + +/* List matching arguments */ +static char *_list_args(const char *text, int state) +{ + static int match_no = 0; + static size_t len = 0; + static struct command *com; + + /* Initialise if this is a new completion attempt */ + if (!state) { + char *s = rl_line_buffer; + int j = 0; + + match_no = 0; + com = NULL; + len = strlen(text); + + /* Find start of first word in line buffer */ + while (isspace(*s)) + s++; + + /* Look for word in list of commands */ + for (j = 0; j < _cmdline->num_commands; j++) { + const char *p; + char *q = s; + + p = _cmdline->commands[j].name; + while (*p == *q) { + p++; + q++; + } + if ((!*p) && *q == ' ') { + com = _cmdline->commands + j; + break; + } + } + + if (!com) + return NULL; + } + + /* Short form arguments */ + if (len < 3) { + while (match_no < com->num_args) { + char s[3]; + char c; + if (!(c = (_cmdline->the_args + + com->valid_args[match_no++])->short_arg)) + continue; + + sprintf(s, "-%c", c); + if (!strncmp(text, s, len)) + return strdup(s); + } + } + + /* Long form arguments */ + if (match_no < com->num_args) + match_no = com->num_args; + + while (match_no - com->num_args < com->num_args) { + const char *l; + l = (_cmdline->the_args + + com->valid_args[match_no++ - com->num_args])->long_arg; + if (*(l + 2) && !strncmp(text, l, len)) + return strdup(l); + } + + return NULL; +} + +/* Custom completion function */ +static char **_completion(const char *text, int start_pos, int end_pos) +{ + char **match_list = NULL; + int p = 0; + + while (isspace((int) *(rl_line_buffer + p))) + p++; + + /* First word should be one of our commands */ + if (start_pos == p) + match_list = rl_completion_matches(text, _list_cmds); + + else if (*text == '-') + match_list = rl_completion_matches(text, _list_args); + /* else other args */ + + /* No further completion */ + rl_attempted_completion_over = 1; + return match_list; +} + +static int _hist_file(char *buffer, size_t size) +{ + char *e = getenv("HOME"); + + if (dm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) { + log_error("$HOME/.lvm_history: path too long"); + return 0; + } + + return 1; +} + +static void _read_history(struct cmd_context *cmd) +{ + char hist_file[PATH_MAX]; + + if (!_hist_file(hist_file, sizeof(hist_file))) + return; + + if (read_history(hist_file)) + log_very_verbose("Couldn't read history from %s.", hist_file); + + stifle_history(find_config_tree_int(cmd, "shell/history_size", + DEFAULT_MAX_HISTORY)); + +} + +static void _write_history(void) +{ + char hist_file[PATH_MAX]; + + if (!_hist_file(hist_file, sizeof(hist_file))) + return; + + if (write_history(hist_file)) + log_very_verbose("Couldn't write history to %s.", hist_file); +} + +int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline) +{ + int argc, ret; + char *input = NULL, *args[MAX_ARGS], **argv; + + rl_readline_name = "lvm"; + rl_attempted_completion_function = (CPPFunction *) _completion; + + _read_history(cmd); + + _cmdline = cmdline; + + _cmdline->interactive = 1; + while (1) { + free(input); + input = readline("lvm> "); + + /* EOF */ + if (!input) { + printf("\n"); + break; + } + + /* empty line */ + if (!*input) + continue; + + add_history(input); + + argv = args; + + if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) { + log_error("Too many arguments, sorry."); + continue; + } + + if (!strcmp(argv[0], "lvm")) { + argv++; + argc--; + } + + if (!argc) + continue; + + if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) { + remove_history(history_length - 1); + log_error("Exiting."); + break; + } + + ret = lvm_run_command(cmd, argc, argv); + if (ret == ENO_SUCH_CMD) + log_error("No such command '%s'. Try 'help'.", + argv[0]); + + _write_history(); + } + + free(input); + return 0; +} + +#endif /* READLINE_SUPPORT */ |