Tizen 2.1 base
[external/device-mapper.git] / tools / lvm.c
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 int main(int argc, char **argv)
20 {
21         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 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         if (!state) {
42                 i = 0;
43                 len = strlen(text);
44         }
45
46         while (i < _cmdline->num_commands)
47                 if (!strncmp(text, _cmdline->commands[i++].name, len))
48                         return strdup(_cmdline->commands[i - 1].name);
49
50         return NULL;
51 }
52
53 /* List matching arguments */
54 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         if (!state) {
62                 char *s = rl_line_buffer;
63                 int j = 0;
64
65                 match_no = 0;
66                 com = NULL;
67                 len = strlen(text);
68
69                 /* Find start of first word in line buffer */
70                 while (isspace(*s))
71                         s++;
72
73                 /* Look for word in list of commands */
74                 for (j = 0; j < _cmdline->num_commands; j++) {
75                         const char *p;
76                         char *q = s;
77
78                         p = _cmdline->commands[j].name;
79                         while (*p == *q) {
80                                 p++;
81                                 q++;
82                         }
83                         if ((!*p) && *q == ' ') {
84                                 com = _cmdline->commands + j;
85                                 break;
86                         }
87                 }
88         }
89
90         if (!com)
91                 return NULL;
92
93         /* Short form arguments */
94         if (len < 3) {
95                 while (match_no < com->num_args) {
96                         char s[3];
97                         char c;
98                         if (!(c = (_cmdline->arg_props +
99                                    com->valid_args[match_no++])->short_arg))
100                                 continue;
101
102                         sprintf(s, "-%c", c);
103                         if (!strncmp(text, s, len))
104                                 return strdup(s);
105                 }
106         }
107
108         /* Long form arguments */
109         if (match_no < com->num_args)
110                 match_no = com->num_args;
111
112         while (match_no - com->num_args < com->num_args) {
113                 const char *l;
114                 l = (_cmdline->arg_props +
115                      com->valid_args[match_no++ - com->num_args])->long_arg;
116                 if (*(l + 2) && !strncmp(text, l, len))
117                         return strdup(l);
118         }
119
120         return NULL;
121 }
122
123 /* Custom completion function */
124 static char **_completion(const char *text, int start_pos,
125                           int end_pos __attribute__((unused)))
126 {
127         char **match_list = NULL;
128         int p = 0;
129
130         while (isspace((int) *(rl_line_buffer + p)))
131                 p++;
132
133         /* First word should be one of our commands */
134         if (start_pos == p)
135                 match_list = rl_completion_matches(text, _list_cmds);
136
137         else if (*text == '-')
138                 match_list = rl_completion_matches(text, _list_args);
139         /* else other args */
140
141         /* No further completion */
142         rl_attempted_completion_over = 1;
143         return match_list;
144 }
145
146 static int _hist_file(char *buffer, size_t size)
147 {
148         char *e = getenv("HOME");
149
150         if (dm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) {
151                 log_error("$HOME/.lvm_history: path too long");
152                 return 0;
153         }
154
155         return 1;
156 }
157
158 static void _read_history(struct cmd_context *cmd)
159 {
160         char hist_file[PATH_MAX];
161
162         if (!_hist_file(hist_file, sizeof(hist_file)))
163                 return;
164
165         if (read_history(hist_file))
166                 log_very_verbose("Couldn't read history from %s.", hist_file);
167
168         stifle_history(find_config_tree_int(cmd, "shell/history_size",
169                                        DEFAULT_MAX_HISTORY));
170
171 }
172
173 static void _write_history(void)
174 {
175         char hist_file[PATH_MAX];
176
177         if (!_hist_file(hist_file, sizeof(hist_file)))
178                 return;
179
180         if (write_history(hist_file))
181                 log_very_verbose("Couldn't write history to %s.", hist_file);
182 }
183
184 int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
185 {
186         int argc, ret;
187         char *input = NULL, *args[MAX_ARGS], **argv;
188
189         rl_readline_name = "lvm";
190         rl_attempted_completion_function = (CPPFunction *) _completion;
191
192         _read_history(cmd);
193
194         _cmdline = cmdline;
195
196         _cmdline->interactive = 1;
197         while (1) {
198                 free(input);
199                 input = readline("lvm> ");
200
201                 /* EOF */
202                 if (!input) {
203                         printf("\n");
204                         break;
205                 }
206
207                 /* empty line */
208                 if (!*input)
209                         continue;
210
211                 add_history(input);
212
213                 argv = args;
214
215                 if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
216                         log_error("Too many arguments, sorry.");
217                         continue;
218                 }
219
220                 if (!argc)
221                         continue;
222
223                 if (!strcmp(argv[0], "lvm")) {
224                         argv++;
225                         argc--;
226                 }
227
228                 if (!argc)
229                         continue;
230
231                 if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
232                         remove_history(history_length - 1);
233                         log_error("Exiting.");
234                         break;
235                 }
236
237                 ret = lvm_run_command(cmd, argc, argv);
238                 if (ret == ENO_SUCH_CMD)
239                         log_error("No such command '%s'.  Try 'help'.",
240                                   argv[0]);
241
242                 if ((ret != ECMD_PROCESSED) && !error_message_produced()) {
243                         log_debug(INTERNAL_ERROR "Failed command did not use log_error");
244                         log_error("Command failed with status code %d.", ret);
245                 }
246                 _write_history();
247         }
248
249         free(input);
250         return 0;
251 }
252
253 #endif  /* READLINE_SUPPORT */