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