]> sourceware.org Git - lvm2.git/blame - tools/lvm.c
dev-type: detect mixed dos partition with gpt's PMBR
[lvm2.git] / tools / lvm.c
CommitLineData
269930c0 1/*
67cdbd7e 2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
be684599 3 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
269930c0 4 *
6606c3ae
AK
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,
fcbef05a 13 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
269930c0
AK
14 */
15
f359c9b8 16#include "tools.h"
dfe3eb12 17
7fa2d1a0 18#include "lvm2cmdline.h"
5a52dca9
AK
19
20int main(int argc, char **argv)
21{
bf0d5580 22 /* coverity[os_cmd_sink] intentionally passing argv */
02961979 23 return lvm2_main(argc, argv);
5a52dca9 24}
f359c9b8 25
168e2ffb
BG
26#if defined(READLINE_SUPPORT) || defined(EDITLINE_SUPPORT)
27
28# ifdef READLINE_SUPPORT
29# include <readline/readline.h>
30# include <readline/history.h>
31# ifndef HAVE_RL_COMPLETION_MATCHES
32# define rl_completion_matches(a, b) completion_matches((char *)a, b)
33# define rl_completion_func_t CPPFunction
34# endif
35# elif defined(EDITLINE_SUPPORT)
36# include <editline/readline.h>
f359c9b8
AK
37# endif
38
39static struct cmdline_context *_cmdline;
40
41/* List matching commands */
42static char *_list_cmds(const char *text, int state)
43{
44 static int i = 0;
45 static size_t len = 0;
46
47 /* Initialise if this is a new completion attempt */
48 if (!state) {
49 i = 0;
50 len = strlen(text);
51 }
52
82617852
ZK
53 for (;i < _cmdline->num_command_names;++i)
54 if (!strncmp(text, _cmdline->command_names[i].name, len))
73298635
ZK
55 /* increase position for next iteration */
56 return strdup(_cmdline->command_names[i++].name);
f359c9b8
AK
57
58 return NULL;
59}
60
61/* List matching arguments */
62static char *_list_args(const char *text, int state)
63{
64 static int match_no = 0;
65 static size_t len = 0;
82617852
ZK
66 static const struct command_name *cname;
67 static const struct command_name_args *cna;
f359c9b8
AK
68
69 /* Initialise if this is a new completion attempt */
70 if (!state) {
71 char *s = rl_line_buffer;
a6292f2a 72 int j;
f359c9b8
AK
73
74 match_no = 0;
1e2420bc 75 cname = NULL;
abe1b49b 76 cna = NULL;
f359c9b8
AK
77 len = strlen(text);
78
79 /* Find start of first word in line buffer */
80 while (isspace(*s))
81 s++;
82
1e2420bc
DT
83 /* Look for word in list of command names */
84 for (j = 0; j < _cmdline->num_command_names; j++) {
f359c9b8
AK
85 const char *p;
86 char *q = s;
87
1e2420bc 88 p = _cmdline->command_names[j].name;
f359c9b8
AK
89 while (*p == *q) {
90 p++;
91 q++;
92 }
93 if ((!*p) && *q == ' ') {
1e2420bc 94 cname = _cmdline->command_names + j;
abe1b49b 95 cna = _cmdline->command_names_args + j;
f359c9b8
AK
96 break;
97 }
98 }
f359c9b8
AK
99 }
100
1e2420bc 101 if (!cname)
30b36dc0
ZK
102 return NULL;
103
f359c9b8 104 /* Short form arguments */
9495a3d8 105 if (len < 3) {
73298635 106 while (match_no < cna->num_args) {
9495a3d8 107 char s[3];
73298635
ZK
108 /* increase position for next iteration */
109 char c = _cmdline->opt_names[cna->valid_args[match_no++]].short_opt;
82617852
ZK
110 if (c) {
111 sprintf(s, "-%c", c);
112 if (!strncmp(text, s, len))
113 return strdup(s);
114 }
9495a3d8 115 }
f359c9b8
AK
116 }
117
118 /* Long form arguments */
abe1b49b
ZK
119 if (match_no < cna->num_args)
120 match_no = cna->num_args;
f359c9b8 121
73298635
ZK
122 while ((match_no - cna->num_args) < cna->num_args) {
123 /* increase position for next iteration */
124 const char *l = _cmdline->opt_names[cna->valid_args[match_no++ - cna->num_args]].long_opt;
f359c9b8
AK
125 if (*(l + 2) && !strncmp(text, l, len))
126 return strdup(l);
127 }
128
129 return NULL;
130}
131
132/* Custom completion function */
4e9083db 133static char **_completion(const char *text, int start_pos,
08f1ddea 134 int end_pos __attribute__((unused)))
f359c9b8
AK
135{
136 char **match_list = NULL;
137 int p = 0;
138
139 while (isspace((int) *(rl_line_buffer + p)))
140 p++;
141
142 /* First word should be one of our commands */
143 if (start_pos == p)
144 match_list = rl_completion_matches(text, _list_cmds);
145
146 else if (*text == '-')
147 match_list = rl_completion_matches(text, _list_args);
148 /* else other args */
149
150 /* No further completion */
151 rl_attempted_completion_over = 1;
152 return match_list;
153}
154
155static int _hist_file(char *buffer, size_t size)
156{
157 char *e = getenv("HOME");
158
493af2bb 159 if (dm_snprintf(buffer, size, "%s%s.lvm_history", e ? :"", e ? "/" : "") < 0) {
f359c9b8
AK
160 log_error("$HOME/.lvm_history: path too long");
161 return 0;
162 }
163
164 return 1;
165}
166
167static void _read_history(struct cmd_context *cmd)
168{
169 char hist_file[PATH_MAX];
170
171 if (!_hist_file(hist_file, sizeof(hist_file)))
172 return;
173
174 if (read_history(hist_file))
175 log_very_verbose("Couldn't read history from %s.", hist_file);
176
50bf2c0d 177 stifle_history(find_config_tree_int(cmd, shell_history_size_CFG, NULL));
f359c9b8
AK
178}
179
180static void _write_history(void)
181{
182 char hist_file[PATH_MAX];
183
184 if (!_hist_file(hist_file, sizeof(hist_file)))
185 return;
186
187 if (write_history(hist_file))
188 log_very_verbose("Couldn't write history to %s.", hist_file);
189}
190
ef699347
PR
191static int _log_shell_command_status(struct cmd_context *cmd, int ret_code)
192{
193 log_report_t log_state;
194
1fde4bf4 195 if (!cmd->cmd_report.log_rh)
ef699347
PR
196 return 1;
197
198 log_state = log_get_report_state();
199
1fde4bf4 200 return report_cmdlog(cmd->cmd_report.log_rh, REPORT_OBJECT_CMDLOG_NAME,
ef699347
PR
201 log_get_report_context_name(log_state.context),
202 log_get_report_object_type_name(log_state.object_type),
203 log_state.object_name, log_state.object_id,
204 log_state.object_group, log_state.object_group_id,
205 ret_code == ECMD_PROCESSED ? REPORT_OBJECT_CMDLOG_SUCCESS
206 : REPORT_OBJECT_CMDLOG_FAILURE,
207 stored_errno(), ret_code);
208}
209
f21afdde
PR
210static void _discard_log_report_content(struct cmd_context *cmd)
211{
212 if (cmd->cmd_report.log_rh)
213 dm_report_destroy_rows(cmd->cmd_report.log_rh);
214}
215
f359c9b8
AK
216int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
217{
ef699347 218 log_report_t saved_log_report_state = log_get_report_state();
7111d487 219 char *orig_command_log_selection = NULL;
9a0f0c70 220 int is_lastlog_cmd = 0, argc, ret, i;
f359c9b8
AK
221 char *input = NULL, *args[MAX_ARGS], **argv;
222
223 rl_readline_name = "lvm";
216c57ee 224 rl_attempted_completion_function = (rl_completion_func_t *) _completion;
f359c9b8
AK
225
226 _read_history(cmd);
f359c9b8
AK
227 _cmdline = cmdline;
228
c33c0545 229 cmd->is_interactive = 1;
f21afdde
PR
230
231 if (!report_format_init(cmd))
232 return_ECMD_FAILED;
233
7111d487 234 orig_command_log_selection = dm_pool_strdup(cmd->libmem, find_config_tree_str(cmd, log_command_log_selection_CFG, NULL));
ef699347 235 log_set_report_context(LOG_REPORT_CONTEXT_SHELL);
508782a9 236 log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_PRE_CMD);
ef699347 237
f359c9b8 238 while (1) {
2fa99164
PR
239 /*
240 * Note: If we need to output the log report before we get to the dm_report_group_output_and_pop_all
241 * at the end of this loop, like hitting a failure situation before we execute the command itself,
39b7d1ba 242 * don't forget to directly call dm_report_group_output_and_pop_all, otherwise no log message will
2fa99164
PR
243 * appear on output (for output formats other than 'basic').
244 *
245 * Obviously, you can't output the 'log report' if the error is in initializing or setting
246 * the report itself. In this case, we can only return an error code, but no message.
247 */
248
5ac00811 249 report_reset_cmdlog_seqnum();
7111d487
PR
250 if (cmd->cmd_report.log_rh) {
251 /*
252 * If previous command was lastlog, reset log report selection to
253 * its original value as set by log/command_log_selection config setting.
254 */
255 if (is_lastlog_cmd &&
256 !dm_report_set_selection(cmd->cmd_report.log_rh, orig_command_log_selection))
257 log_error("Failed to reset log report selection.");
258 }
259
508782a9 260 log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_PRE_CMD);
f21afdde 261 log_set_report(cmd->cmd_report.log_rh);
ef699347 262 log_set_report_object_name_and_id(NULL, NULL);
f21afdde 263
f359c9b8
AK
264 free(input);
265 input = readline("lvm> ");
266
267 /* EOF */
268 if (!input) {
f21afdde 269 _discard_log_report_content(cmd);
438e0050 270 /* readline sends prompt to stdout */
f359c9b8
AK
271 printf("\n");
272 break;
273 }
274
275 /* empty line */
f21afdde
PR
276 if (!*input) {
277 _discard_log_report_content(cmd);
f359c9b8 278 continue;
f21afdde 279 }
f359c9b8 280
508782a9
PR
281 log_set_report_object_name_and_id(input, NULL);
282
f359c9b8
AK
283 add_history(input);
284
9a0f0c70
DT
285 for (i = 0; i < MAX_ARGS; i++)
286 args[i] = NULL;
287
f359c9b8
AK
288 argv = args;
289
290 if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
f21afdde 291 _discard_log_report_content(cmd);
f359c9b8 292 log_error("Too many arguments, sorry.");
508782a9 293 goto report_log;
f359c9b8
AK
294 }
295
f21afdde
PR
296 if (!argc) {
297 _discard_log_report_content(cmd);
89dd7d52 298 continue;
f21afdde 299 }
89dd7d52 300
f359c9b8
AK
301 if (!strcmp(argv[0], "lvm")) {
302 argv++;
303 argc--;
304 }
305
f21afdde
PR
306 if (!argc) {
307 _discard_log_report_content(cmd);
f359c9b8 308 continue;
f21afdde 309 }
f359c9b8 310
508782a9 311 log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_CMD);
ef699347
PR
312 log_set_report_object_name_and_id(argv[0], NULL);
313
f21afdde
PR
314 is_lastlog_cmd = !strcmp(argv[0], "lastlog");
315
316 if (!is_lastlog_cmd)
317 _discard_log_report_content(cmd);
318
f359c9b8 319 if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
f21afdde 320 _discard_log_report_content(cmd);
f359c9b8
AK
321 remove_history(history_length - 1);
322 log_error("Exiting.");
323 break;
324 }
325
326 ret = lvm_run_command(cmd, argc, argv);
327 if (ret == ENO_SUCH_CMD)
328 log_error("No such command '%s'. Try 'help'.",
329 argv[0]);
330
ec40d928 331 if ((ret != ECMD_PROCESSED) && !error_message_produced()) {
550cae23 332 log_debug(INTERNAL_ERROR "Failed command did not use log_error");
ec40d928
AK
333 log_error("Command failed with status code %d.", ret);
334 }
f359c9b8 335 _write_history();
ef699347
PR
336
337 if (!is_lastlog_cmd)
338 _log_shell_command_status(cmd, ret);
508782a9 339report_log:
f21afdde
PR
340 log_set_report(NULL);
341 dm_report_group_output_and_pop_all(cmd->cmd_report.report_group);
342
343 if (cmd->cmd_report.log_rh &&
344 !(dm_report_group_push(cmd->cmd_report.report_group,
345 cmd->cmd_report.log_rh,
346 (void *) cmd->cmd_report.log_name))) {
347 log_set_report(NULL);
348 log_error("Failed to add log report.");
349 break;
350 }
f359c9b8 351 }
ef699347
PR
352
353 log_restore_report_state(saved_log_report_state);
c33c0545 354 cmd->is_interactive = 0;
f359c9b8
AK
355
356 free(input);
f21afdde
PR
357
358 if (cmd->cmd_report.report_group) {
c3e0ef1a
ZK
359 if (!dm_report_group_destroy(cmd->cmd_report.report_group))
360 stack;
f21afdde
PR
361 cmd->cmd_report.report_group = NULL;
362 }
363
364 if (cmd->cmd_report.log_rh) {
365 dm_report_free(cmd->cmd_report.log_rh);
366 cmd->cmd_report.report_group = NULL;
367 }
368
f359c9b8
AK
369 return 0;
370}
371
168e2ffb 372#endif /* READLINE_SUPPORT || EDITLINE_SUPPORT */
This page took 0.284445 seconds and 6 git commands to generate.