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