1*86d7f5d3SJohn Marino /* $NetBSD: lvm.c,v 1.1.1.2 2009/02/18 11:17:44 haad Exp $ */
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino /*
4*86d7f5d3SJohn Marino * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5*86d7f5d3SJohn Marino * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6*86d7f5d3SJohn Marino *
7*86d7f5d3SJohn Marino * This file is part of LVM2.
8*86d7f5d3SJohn Marino *
9*86d7f5d3SJohn Marino * This copyrighted material is made available to anyone wishing to use,
10*86d7f5d3SJohn Marino * modify, copy, or redistribute it subject to the terms and conditions
11*86d7f5d3SJohn Marino * of the GNU General Public License v.2.
12*86d7f5d3SJohn Marino *
13*86d7f5d3SJohn Marino * You should have received a copy of the GNU General Public License
14*86d7f5d3SJohn Marino * along with this program; if not, write to the Free Software Foundation,
15*86d7f5d3SJohn Marino * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16*86d7f5d3SJohn Marino */
17*86d7f5d3SJohn Marino
18*86d7f5d3SJohn Marino #include "tools.h"
19*86d7f5d3SJohn Marino #include "lvm2cmdline.h"
20*86d7f5d3SJohn Marino
main(int argc,char ** argv)21*86d7f5d3SJohn Marino int main(int argc, char **argv)
22*86d7f5d3SJohn Marino {
23*86d7f5d3SJohn Marino return lvm2_main(argc, argv);
24*86d7f5d3SJohn Marino }
25*86d7f5d3SJohn Marino
26*86d7f5d3SJohn Marino #ifdef READLINE_SUPPORT
27*86d7f5d3SJohn Marino
28*86d7f5d3SJohn Marino # include <readline/readline.h>
29*86d7f5d3SJohn Marino # include <readline/history.h>
30*86d7f5d3SJohn Marino # ifndef HAVE_RL_COMPLETION_MATCHES
31*86d7f5d3SJohn Marino # define rl_completion_matches(a, b) completion_matches((char *)a, b)
32*86d7f5d3SJohn Marino # endif
33*86d7f5d3SJohn Marino
34*86d7f5d3SJohn Marino static struct cmdline_context *_cmdline;
35*86d7f5d3SJohn Marino
36*86d7f5d3SJohn Marino /* List matching commands */
_list_cmds(const char * text,int state)37*86d7f5d3SJohn Marino static char *_list_cmds(const char *text, int state)
38*86d7f5d3SJohn Marino {
39*86d7f5d3SJohn Marino static int i = 0;
40*86d7f5d3SJohn Marino static size_t len = 0;
41*86d7f5d3SJohn Marino
42*86d7f5d3SJohn Marino /* Initialise if this is a new completion attempt */
43*86d7f5d3SJohn Marino if (!state) {
44*86d7f5d3SJohn Marino i = 0;
45*86d7f5d3SJohn Marino len = strlen(text);
46*86d7f5d3SJohn Marino }
47*86d7f5d3SJohn Marino
48*86d7f5d3SJohn Marino while (i < _cmdline->num_commands)
49*86d7f5d3SJohn Marino if (!strncmp(text, _cmdline->commands[i++].name, len))
50*86d7f5d3SJohn Marino return strdup(_cmdline->commands[i - 1].name);
51*86d7f5d3SJohn Marino
52*86d7f5d3SJohn Marino return NULL;
53*86d7f5d3SJohn Marino }
54*86d7f5d3SJohn Marino
55*86d7f5d3SJohn Marino /* List matching arguments */
_list_args(const char * text,int state)56*86d7f5d3SJohn Marino static char *_list_args(const char *text, int state)
57*86d7f5d3SJohn Marino {
58*86d7f5d3SJohn Marino static int match_no = 0;
59*86d7f5d3SJohn Marino static size_t len = 0;
60*86d7f5d3SJohn Marino static struct command *com;
61*86d7f5d3SJohn Marino
62*86d7f5d3SJohn Marino /* Initialise if this is a new completion attempt */
63*86d7f5d3SJohn Marino if (!state) {
64*86d7f5d3SJohn Marino char *s = rl_line_buffer;
65*86d7f5d3SJohn Marino int j = 0;
66*86d7f5d3SJohn Marino
67*86d7f5d3SJohn Marino match_no = 0;
68*86d7f5d3SJohn Marino com = NULL;
69*86d7f5d3SJohn Marino len = strlen(text);
70*86d7f5d3SJohn Marino
71*86d7f5d3SJohn Marino /* Find start of first word in line buffer */
72*86d7f5d3SJohn Marino while (isspace(*s))
73*86d7f5d3SJohn Marino s++;
74*86d7f5d3SJohn Marino
75*86d7f5d3SJohn Marino /* Look for word in list of commands */
76*86d7f5d3SJohn Marino for (j = 0; j < _cmdline->num_commands; j++) {
77*86d7f5d3SJohn Marino const char *p;
78*86d7f5d3SJohn Marino char *q = s;
79*86d7f5d3SJohn Marino
80*86d7f5d3SJohn Marino p = _cmdline->commands[j].name;
81*86d7f5d3SJohn Marino while (*p == *q) {
82*86d7f5d3SJohn Marino p++;
83*86d7f5d3SJohn Marino q++;
84*86d7f5d3SJohn Marino }
85*86d7f5d3SJohn Marino if ((!*p) && *q == ' ') {
86*86d7f5d3SJohn Marino com = _cmdline->commands + j;
87*86d7f5d3SJohn Marino break;
88*86d7f5d3SJohn Marino }
89*86d7f5d3SJohn Marino }
90*86d7f5d3SJohn Marino
91*86d7f5d3SJohn Marino if (!com)
92*86d7f5d3SJohn Marino return NULL;
93*86d7f5d3SJohn Marino }
94*86d7f5d3SJohn Marino
95*86d7f5d3SJohn Marino /* Short form arguments */
96*86d7f5d3SJohn Marino if (len < 3) {
97*86d7f5d3SJohn Marino while (match_no < com->num_args) {
98*86d7f5d3SJohn Marino char s[3];
99*86d7f5d3SJohn Marino char c;
100*86d7f5d3SJohn Marino if (!(c = (_cmdline->the_args +
101*86d7f5d3SJohn Marino com->valid_args[match_no++])->short_arg))
102*86d7f5d3SJohn Marino continue;
103*86d7f5d3SJohn Marino
104*86d7f5d3SJohn Marino sprintf(s, "-%c", c);
105*86d7f5d3SJohn Marino if (!strncmp(text, s, len))
106*86d7f5d3SJohn Marino return strdup(s);
107*86d7f5d3SJohn Marino }
108*86d7f5d3SJohn Marino }
109*86d7f5d3SJohn Marino
110*86d7f5d3SJohn Marino /* Long form arguments */
111*86d7f5d3SJohn Marino if (match_no < com->num_args)
112*86d7f5d3SJohn Marino match_no = com->num_args;
113*86d7f5d3SJohn Marino
114*86d7f5d3SJohn Marino while (match_no - com->num_args < com->num_args) {
115*86d7f5d3SJohn Marino const char *l;
116*86d7f5d3SJohn Marino l = (_cmdline->the_args +
117*86d7f5d3SJohn Marino com->valid_args[match_no++ - com->num_args])->long_arg;
118*86d7f5d3SJohn Marino if (*(l + 2) && !strncmp(text, l, len))
119*86d7f5d3SJohn Marino return strdup(l);
120*86d7f5d3SJohn Marino }
121*86d7f5d3SJohn Marino
122*86d7f5d3SJohn Marino return NULL;
123*86d7f5d3SJohn Marino }
124*86d7f5d3SJohn Marino
125*86d7f5d3SJohn Marino /* Custom completion function */
_completion(const char * text,int start_pos,int end_pos __attribute ((unused)))126*86d7f5d3SJohn Marino static char **_completion(const char *text, int start_pos,
127*86d7f5d3SJohn Marino int end_pos __attribute((unused)))
128*86d7f5d3SJohn Marino {
129*86d7f5d3SJohn Marino char **match_list = NULL;
130*86d7f5d3SJohn Marino int p = 0;
131*86d7f5d3SJohn Marino
132*86d7f5d3SJohn Marino while (isspace((int) *(rl_line_buffer + p)))
133*86d7f5d3SJohn Marino p++;
134*86d7f5d3SJohn Marino
135*86d7f5d3SJohn Marino /* First word should be one of our commands */
136*86d7f5d3SJohn Marino if (start_pos == p)
137*86d7f5d3SJohn Marino match_list = rl_completion_matches(text, _list_cmds);
138*86d7f5d3SJohn Marino
139*86d7f5d3SJohn Marino else if (*text == '-')
140*86d7f5d3SJohn Marino match_list = rl_completion_matches(text, _list_args);
141*86d7f5d3SJohn Marino /* else other args */
142*86d7f5d3SJohn Marino
143*86d7f5d3SJohn Marino /* No further completion */
144*86d7f5d3SJohn Marino rl_attempted_completion_over = 1;
145*86d7f5d3SJohn Marino return match_list;
146*86d7f5d3SJohn Marino }
147*86d7f5d3SJohn Marino
_hist_file(char * buffer,size_t size)148*86d7f5d3SJohn Marino static int _hist_file(char *buffer, size_t size)
149*86d7f5d3SJohn Marino {
150*86d7f5d3SJohn Marino char *e = getenv("HOME");
151*86d7f5d3SJohn Marino
152*86d7f5d3SJohn Marino if (dm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) {
153*86d7f5d3SJohn Marino log_error("$HOME/.lvm_history: path too long");
154*86d7f5d3SJohn Marino return 0;
155*86d7f5d3SJohn Marino }
156*86d7f5d3SJohn Marino
157*86d7f5d3SJohn Marino return 1;
158*86d7f5d3SJohn Marino }
159*86d7f5d3SJohn Marino
_read_history(struct cmd_context * cmd)160*86d7f5d3SJohn Marino static void _read_history(struct cmd_context *cmd)
161*86d7f5d3SJohn Marino {
162*86d7f5d3SJohn Marino char hist_file[PATH_MAX];
163*86d7f5d3SJohn Marino
164*86d7f5d3SJohn Marino if (!_hist_file(hist_file, sizeof(hist_file)))
165*86d7f5d3SJohn Marino return;
166*86d7f5d3SJohn Marino
167*86d7f5d3SJohn Marino if (read_history(hist_file))
168*86d7f5d3SJohn Marino log_very_verbose("Couldn't read history from %s.", hist_file);
169*86d7f5d3SJohn Marino
170*86d7f5d3SJohn Marino stifle_history(find_config_tree_int(cmd, "shell/history_size",
171*86d7f5d3SJohn Marino DEFAULT_MAX_HISTORY));
172*86d7f5d3SJohn Marino
173*86d7f5d3SJohn Marino }
174*86d7f5d3SJohn Marino
_write_history(void)175*86d7f5d3SJohn Marino static void _write_history(void)
176*86d7f5d3SJohn Marino {
177*86d7f5d3SJohn Marino char hist_file[PATH_MAX];
178*86d7f5d3SJohn Marino
179*86d7f5d3SJohn Marino if (!_hist_file(hist_file, sizeof(hist_file)))
180*86d7f5d3SJohn Marino return;
181*86d7f5d3SJohn Marino
182*86d7f5d3SJohn Marino if (write_history(hist_file))
183*86d7f5d3SJohn Marino log_very_verbose("Couldn't write history to %s.", hist_file);
184*86d7f5d3SJohn Marino }
185*86d7f5d3SJohn Marino
lvm_shell(struct cmd_context * cmd,struct cmdline_context * cmdline)186*86d7f5d3SJohn Marino int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
187*86d7f5d3SJohn Marino {
188*86d7f5d3SJohn Marino int argc, ret;
189*86d7f5d3SJohn Marino char *input = NULL, *args[MAX_ARGS], **argv;
190*86d7f5d3SJohn Marino
191*86d7f5d3SJohn Marino rl_readline_name = "lvm";
192*86d7f5d3SJohn Marino rl_attempted_completion_function = (CPPFunction *) _completion;
193*86d7f5d3SJohn Marino
194*86d7f5d3SJohn Marino _read_history(cmd);
195*86d7f5d3SJohn Marino
196*86d7f5d3SJohn Marino _cmdline = cmdline;
197*86d7f5d3SJohn Marino
198*86d7f5d3SJohn Marino _cmdline->interactive = 1;
199*86d7f5d3SJohn Marino while (1) {
200*86d7f5d3SJohn Marino free(input);
201*86d7f5d3SJohn Marino input = readline("lvm> ");
202*86d7f5d3SJohn Marino
203*86d7f5d3SJohn Marino /* EOF */
204*86d7f5d3SJohn Marino if (!input) {
205*86d7f5d3SJohn Marino printf("\n");
206*86d7f5d3SJohn Marino break;
207*86d7f5d3SJohn Marino }
208*86d7f5d3SJohn Marino
209*86d7f5d3SJohn Marino /* empty line */
210*86d7f5d3SJohn Marino if (!*input)
211*86d7f5d3SJohn Marino continue;
212*86d7f5d3SJohn Marino
213*86d7f5d3SJohn Marino add_history(input);
214*86d7f5d3SJohn Marino
215*86d7f5d3SJohn Marino argv = args;
216*86d7f5d3SJohn Marino
217*86d7f5d3SJohn Marino if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
218*86d7f5d3SJohn Marino log_error("Too many arguments, sorry.");
219*86d7f5d3SJohn Marino continue;
220*86d7f5d3SJohn Marino }
221*86d7f5d3SJohn Marino
222*86d7f5d3SJohn Marino if (!strcmp(argv[0], "lvm")) {
223*86d7f5d3SJohn Marino argv++;
224*86d7f5d3SJohn Marino argc--;
225*86d7f5d3SJohn Marino }
226*86d7f5d3SJohn Marino
227*86d7f5d3SJohn Marino if (!argc)
228*86d7f5d3SJohn Marino continue;
229*86d7f5d3SJohn Marino
230*86d7f5d3SJohn Marino if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
231*86d7f5d3SJohn Marino remove_history(history_length - 1);
232*86d7f5d3SJohn Marino log_error("Exiting.");
233*86d7f5d3SJohn Marino break;
234*86d7f5d3SJohn Marino }
235*86d7f5d3SJohn Marino
236*86d7f5d3SJohn Marino ret = lvm_run_command(cmd, argc, argv);
237*86d7f5d3SJohn Marino if (ret == ENO_SUCH_CMD)
238*86d7f5d3SJohn Marino log_error("No such command '%s'. Try 'help'.",
239*86d7f5d3SJohn Marino argv[0]);
240*86d7f5d3SJohn Marino
241*86d7f5d3SJohn Marino if ((ret != ECMD_PROCESSED) && !error_message_produced()) {
242*86d7f5d3SJohn Marino log_debug("Internal error: Failed command did not use log_error");
243*86d7f5d3SJohn Marino log_error("Command failed with status code %d.", ret);
244*86d7f5d3SJohn Marino }
245*86d7f5d3SJohn Marino _write_history();
246*86d7f5d3SJohn Marino }
247*86d7f5d3SJohn Marino
248*86d7f5d3SJohn Marino free(input);
249*86d7f5d3SJohn Marino return 0;
250*86d7f5d3SJohn Marino }
251*86d7f5d3SJohn Marino
252*86d7f5d3SJohn Marino #endif /* READLINE_SUPPORT */
253