1 /* $NetBSD: lvmcmdline.c,v 1.2 2011/01/05 14:57:28 haad Exp $ */
2
3 /*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2009 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 Lesser General Public License v.2.1.
12 *
13 * You should have received a copy of the GNU Lesser 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 #include "label.h"
21 #include "lvm-version.h"
22
23 #include "stub.h"
24 #include "lvm2cmd.h"
25 #include "last-path-component.h"
26
27 #include <signal.h>
28 #include <syslog.h>
29 #include <libgen.h>
30 #include <sys/stat.h>
31 #include <time.h>
32 #include <sys/resource.h>
33
34 #ifdef HAVE_GETOPTLONG
35 # include <getopt.h>
36 # define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
37 # define OPTIND_INIT 0
38 #else
39 struct option {
40 };
41 extern int optind;
42 extern char *optarg;
43 # define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))
44 # define OPTIND_INIT 1
45 #endif
46
47 /*
48 * Table of valid switches
49 */
50 static struct arg _the_args[ARG_COUNT + 1] = {
51 #define arg(a, b, c, d, e) {b, "", "--" c, d, e, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), SIGN_NONE, PERCENT_NONE, NULL},
52 #include "args.h"
53 #undef arg
54 };
55
56 static struct cmdline_context _cmdline;
57
58 /* Command line args */
59 /* FIXME: Move static _the_args into cmd? */
arg_count(const struct cmd_context * cmd __attribute ((unused)),int a)60 unsigned arg_count(const struct cmd_context *cmd __attribute((unused)), int a)
61 {
62 return _the_args[a].count;
63 }
64
arg_is_set(const struct cmd_context * cmd,int a)65 unsigned arg_is_set(const struct cmd_context *cmd, int a)
66 {
67 return arg_count(cmd, a) ? 1 : 0;
68 }
69
arg_value(struct cmd_context * cmd __attribute ((unused)),int a)70 const char *arg_value(struct cmd_context *cmd __attribute((unused)), int a)
71 {
72 return _the_args[a].value;
73 }
74
arg_str_value(struct cmd_context * cmd,int a,const char * def)75 const char *arg_str_value(struct cmd_context *cmd, int a, const char *def)
76 {
77 return arg_count(cmd, a) ? _the_args[a].value : def;
78 }
79
arg_int_value(struct cmd_context * cmd,int a,const int32_t def)80 int32_t arg_int_value(struct cmd_context *cmd, int a, const int32_t def)
81 {
82 return arg_count(cmd, a) ? _the_args[a].i_value : def;
83 }
84
arg_uint_value(struct cmd_context * cmd,int a,const uint32_t def)85 uint32_t arg_uint_value(struct cmd_context *cmd, int a, const uint32_t def)
86 {
87 return arg_count(cmd, a) ? _the_args[a].ui_value : def;
88 }
89
arg_int64_value(struct cmd_context * cmd,int a,const int64_t def)90 int64_t arg_int64_value(struct cmd_context *cmd, int a, const int64_t def)
91 {
92 return arg_count(cmd, a) ? _the_args[a].i64_value : def;
93 }
94
arg_uint64_value(struct cmd_context * cmd,int a,const uint64_t def)95 uint64_t arg_uint64_value(struct cmd_context *cmd, int a, const uint64_t def)
96 {
97 return arg_count(cmd, a) ? _the_args[a].ui64_value : def;
98 }
99
arg_ptr_value(struct cmd_context * cmd,int a,const void * def)100 const void *arg_ptr_value(struct cmd_context *cmd, int a, const void *def)
101 {
102 return arg_count(cmd, a) ? _the_args[a].ptr : def;
103 }
104
arg_sign_value(struct cmd_context * cmd,int a,const sign_t def)105 sign_t arg_sign_value(struct cmd_context *cmd, int a, const sign_t def)
106 {
107 return arg_count(cmd, a) ? _the_args[a].sign : def;
108 }
109
arg_percent_value(struct cmd_context * cmd,int a,const percent_t def)110 percent_t arg_percent_value(struct cmd_context *cmd, int a, const percent_t def)
111 {
112 return arg_count(cmd, a) ? _the_args[a].percent : def;
113 }
114
arg_count_increment(struct cmd_context * cmd __attribute ((unused)),int a)115 int arg_count_increment(struct cmd_context *cmd __attribute((unused)), int a)
116 {
117 return _the_args[a].count++;
118 }
119
yes_no_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a)120 int yes_no_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
121 {
122 a->sign = SIGN_NONE;
123 a->percent = PERCENT_NONE;
124
125 if (!strcmp(a->value, "y")) {
126 a->i_value = 1;
127 a->ui_value = 1;
128 }
129
130 else if (!strcmp(a->value, "n")) {
131 a->i_value = 0;
132 a->ui_value = 0;
133 }
134
135 else
136 return 0;
137
138 return 1;
139 }
140
yes_no_excl_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a)141 int yes_no_excl_arg(struct cmd_context *cmd __attribute((unused)),
142 struct arg *a)
143 {
144 a->sign = SIGN_NONE;
145 a->percent = PERCENT_NONE;
146
147 if (!strcmp(a->value, "e") || !strcmp(a->value, "ey") ||
148 !strcmp(a->value, "ye")) {
149 a->i_value = CHANGE_AE;
150 a->ui_value = CHANGE_AE;
151 }
152
153 else if (!strcmp(a->value, "y")) {
154 a->i_value = CHANGE_AY;
155 a->ui_value = CHANGE_AY;
156 }
157
158 else if (!strcmp(a->value, "n") || !strcmp(a->value, "en") ||
159 !strcmp(a->value, "ne")) {
160 a->i_value = CHANGE_AN;
161 a->ui_value = CHANGE_AN;
162 }
163
164 else if (!strcmp(a->value, "ln") || !strcmp(a->value, "nl")) {
165 a->i_value = CHANGE_ALN;
166 a->ui_value = CHANGE_ALN;
167 }
168
169 else if (!strcmp(a->value, "ly") || !strcmp(a->value, "yl")) {
170 a->i_value = CHANGE_ALY;
171 a->ui_value = CHANGE_ALY;
172 }
173
174 else
175 return 0;
176
177 return 1;
178 }
179
metadatatype_arg(struct cmd_context * cmd,struct arg * a)180 int metadatatype_arg(struct cmd_context *cmd, struct arg *a)
181 {
182 struct format_type *fmt;
183 char *format;
184
185 format = a->value;
186
187 dm_list_iterate_items(fmt, &cmd->formats) {
188 if (!strcasecmp(fmt->name, format) ||
189 !strcasecmp(fmt->name + 3, format) ||
190 (fmt->alias && !strcasecmp(fmt->alias, format))) {
191 a->ptr = fmt;
192 return 1;
193 }
194 }
195
196 return 0;
197 }
198
_get_int_arg(struct arg * a,char ** ptr)199 static int _get_int_arg(struct arg *a, char **ptr)
200 {
201 char *val;
202 long v;
203
204 a->percent = PERCENT_NONE;
205
206 val = a->value;
207 switch (*val) {
208 case '+':
209 a->sign = SIGN_PLUS;
210 val++;
211 break;
212 case '-':
213 a->sign = SIGN_MINUS;
214 val++;
215 break;
216 default:
217 a->sign = SIGN_NONE;
218 }
219
220 if (!isdigit(*val))
221 return 0;
222
223 v = strtol(val, ptr, 10);
224
225 if (*ptr == val)
226 return 0;
227
228 a->i_value = (int32_t) v;
229 a->ui_value = (uint32_t) v;
230 a->i64_value = (int64_t) v;
231 a->ui64_value = (uint64_t) v;
232
233 return 1;
234 }
235
236 /* Size stored in sectors */
_size_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a,int factor)237 static int _size_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a, int factor)
238 {
239 char *ptr;
240 int i;
241 static const char *suffixes = "kmgtpebs";
242 char *val;
243 double v;
244 uint64_t v_tmp, adjustment;
245
246 a->percent = PERCENT_NONE;
247
248 val = a->value;
249 switch (*val) {
250 case '+':
251 a->sign = SIGN_PLUS;
252 val++;
253 break;
254 case '-':
255 a->sign = SIGN_MINUS;
256 val++;
257 break;
258 default:
259 a->sign = SIGN_NONE;
260 }
261
262 if (!isdigit(*val))
263 return 0;
264
265 v = strtod(val, &ptr);
266
267 if (ptr == val)
268 return 0;
269
270 if (*ptr) {
271 for (i = strlen(suffixes) - 1; i >= 0; i--)
272 if (suffixes[i] == tolower((int) *ptr))
273 break;
274
275 if (i < 0) {
276 return 0;
277 } else if (i == 7) {
278 /* sectors */
279 v = v;
280 } else if (i == 6) {
281 /* bytes */
282 v_tmp = (uint64_t) v;
283 adjustment = v_tmp % 512;
284 if (adjustment) {
285 v_tmp += (512 - adjustment);
286 log_error("Size is not a multiple of 512. "
287 "Try using %"PRIu64" or %"PRIu64".",
288 v_tmp - 512, v_tmp);
289 return 0;
290 }
291 v /= 512;
292 } else {
293 /* all other units: kmgtpe */
294 while (i-- > 0)
295 v *= 1024;
296 v *= 2;
297 }
298 } else
299 v *= factor;
300
301 a->i_value = (int32_t) v;
302 a->ui_value = (uint32_t) v;
303 a->i64_value = (int64_t) v;
304 a->ui64_value = (uint64_t) v;
305
306 return 1;
307 }
308
size_kb_arg(struct cmd_context * cmd,struct arg * a)309 int size_kb_arg(struct cmd_context *cmd, struct arg *a)
310 {
311 return _size_arg(cmd, a, 2);
312 }
313
size_mb_arg(struct cmd_context * cmd,struct arg * a)314 int size_mb_arg(struct cmd_context *cmd, struct arg *a)
315 {
316 return _size_arg(cmd, a, 2048);
317 }
318
int_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a)319 int int_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
320 {
321 char *ptr;
322
323 if (!_get_int_arg(a, &ptr) || (*ptr) || (a->sign == SIGN_MINUS))
324 return 0;
325
326 return 1;
327 }
328
int_arg_with_sign(struct cmd_context * cmd __attribute ((unused)),struct arg * a)329 int int_arg_with_sign(struct cmd_context *cmd __attribute((unused)), struct arg *a)
330 {
331 char *ptr;
332
333 if (!_get_int_arg(a, &ptr) || (*ptr))
334 return 0;
335
336 return 1;
337 }
338
int_arg_with_sign_and_percent(struct cmd_context * cmd __attribute ((unused)),struct arg * a)339 int int_arg_with_sign_and_percent(struct cmd_context *cmd __attribute((unused)),
340 struct arg *a)
341 {
342 char *ptr;
343
344 if (!_get_int_arg(a, &ptr))
345 return 0;
346
347 if (!*ptr)
348 return 1;
349
350 if (*ptr++ != '%')
351 return 0;
352
353 if (!strcasecmp(ptr, "V") || !strcasecmp(ptr, "VG"))
354 a->percent = PERCENT_VG;
355 else if (!strcasecmp(ptr, "L") || !strcasecmp(ptr, "LV"))
356 a->percent = PERCENT_LV;
357 else if (!strcasecmp(ptr, "P") || !strcasecmp(ptr, "PV") ||
358 !strcasecmp(ptr, "PVS"))
359 a->percent = PERCENT_PVS;
360 else if (!strcasecmp(ptr, "F") || !strcasecmp(ptr, "FR") ||
361 !strcasecmp(ptr, "FREE"))
362 a->percent = PERCENT_FREE;
363 else
364 return 0;
365
366 return 1;
367 }
368
minor_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a)369 int minor_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
370 {
371 char *ptr;
372
373 if (!_get_int_arg(a, &ptr) || (*ptr) || (a->sign == SIGN_MINUS))
374 return 0;
375
376 if (a->i_value > 255) {
377 log_error("Minor number outside range 0-255");
378 return 0;
379 }
380
381 return 1;
382 }
383
major_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a)384 int major_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
385 {
386 char *ptr;
387
388 if (!_get_int_arg(a, &ptr) || (*ptr) || (a->sign == SIGN_MINUS))
389 return 0;
390
391 if (a->i_value > 255) {
392 log_error("Major number outside range 0-255");
393 return 0;
394 }
395
396 /* FIXME Also Check against /proc/devices */
397
398 return 1;
399 }
400
string_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a __attribute ((unused)))401 int string_arg(struct cmd_context *cmd __attribute((unused)),
402 struct arg *a __attribute((unused)))
403 {
404 return 1;
405 }
406
tag_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a)407 int tag_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
408 {
409 char *pos = a->value;
410
411 if (*pos == '@')
412 pos++;
413
414 if (!validate_name(pos))
415 return 0;
416
417 a->value = pos;
418
419 return 1;
420 }
421
permission_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a)422 int permission_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
423 {
424 a->sign = SIGN_NONE;
425
426 if ((!strcmp(a->value, "rw")) || (!strcmp(a->value, "wr")))
427 a->ui_value = LVM_READ | LVM_WRITE;
428
429 else if (!strcmp(a->value, "r"))
430 a->ui_value = LVM_READ;
431
432 else
433 return 0;
434
435 return 1;
436 }
437
alloc_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a)438 int alloc_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
439 {
440 alloc_policy_t alloc;
441
442 a->sign = SIGN_NONE;
443
444 alloc = get_alloc_from_string(a->value);
445 if (alloc == ALLOC_INVALID)
446 return 0;
447
448 a->ui_value = (uint32_t) alloc;
449
450 return 1;
451 }
452
segtype_arg(struct cmd_context * cmd,struct arg * a)453 int segtype_arg(struct cmd_context *cmd, struct arg *a)
454 {
455 if (!(a->ptr = (void *) get_segtype_from_string(cmd, a->value)))
456 return 0;
457
458 return 1;
459 }
460
461 /*
462 * Positive integer, zero or "auto".
463 */
readahead_arg(struct cmd_context * cmd __attribute ((unused)),struct arg * a)464 int readahead_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
465 {
466 if (!strcasecmp(a->value, "auto")) {
467 a->ui_value = DM_READ_AHEAD_AUTO;
468 return 1;
469 }
470
471 if (!strcasecmp(a->value, "none")) {
472 a->ui_value = DM_READ_AHEAD_NONE;
473 return 1;
474 }
475
476 if (!_size_arg(cmd, a, 1))
477 return 0;
478
479 if (a->sign == SIGN_MINUS)
480 return 0;
481
482 return 1;
483 }
484
__alloc(int size)485 static void __alloc(int size)
486 {
487 if (!(_cmdline.commands = dm_realloc(_cmdline.commands, sizeof(*_cmdline.commands) * size))) {
488 log_fatal("Couldn't allocate memory.");
489 exit(ECMD_FAILED);
490 }
491
492 _cmdline.commands_size = size;
493 }
494
_alloc_command(void)495 static void _alloc_command(void)
496 {
497 if (!_cmdline.commands_size)
498 __alloc(32);
499
500 if (_cmdline.commands_size <= _cmdline.num_commands)
501 __alloc(2 * _cmdline.commands_size);
502 }
503
_create_new_command(const char * name,command_fn command,unsigned flags,const char * desc,const char * usagestr,int nargs,int * args)504 static void _create_new_command(const char *name, command_fn command,
505 unsigned flags,
506 const char *desc, const char *usagestr,
507 int nargs, int *args)
508 {
509 struct command *nc;
510
511 _alloc_command();
512
513 nc = _cmdline.commands + _cmdline.num_commands++;
514
515 nc->name = name;
516 nc->desc = desc;
517 nc->usage = usagestr;
518 nc->fn = command;
519 nc->flags = flags;
520 nc->num_args = nargs;
521 nc->valid_args = args;
522 }
523
_register_command(const char * name,command_fn fn,const char * desc,unsigned flags,const char * usagestr,...)524 static void _register_command(const char *name, command_fn fn, const char *desc,
525 unsigned flags, const char *usagestr, ...)
526 {
527 int nargs = 0, i;
528 int *args;
529 va_list ap;
530
531 /* count how many arguments we have */
532 va_start(ap, usagestr);
533 while (va_arg(ap, int) >= 0)
534 nargs++;
535 va_end(ap);
536
537 /* allocate space for them */
538 if (!(args = dm_malloc(sizeof(*args) * nargs))) {
539 log_fatal("Out of memory.");
540 exit(ECMD_FAILED);
541 }
542
543 /* fill them in */
544 va_start(ap, usagestr);
545 for (i = 0; i < nargs; i++)
546 args[i] = va_arg(ap, int);
547 va_end(ap);
548
549 /* enter the command in the register */
550 _create_new_command(name, fn, flags, desc, usagestr, nargs, args);
551 }
552
lvm_register_commands(void)553 void lvm_register_commands(void)
554 {
555 #define xx(a, b, c, d...) _register_command(# a, a, b, c, ## d, \
556 driverloaded_ARG, \
557 debug_ARG, help_ARG, help2_ARG, \
558 version_ARG, verbose_ARG, \
559 quiet_ARG, config_ARG, -1);
560 #include "commands.h"
561 #undef xx
562 }
563
_find_command(const char * name)564 static struct command *_find_command(const char *name)
565 {
566 int i;
567 const char *base;
568
569 base = last_path_component(name);
570
571 for (i = 0; i < _cmdline.num_commands; i++) {
572 if (!strcmp(base, _cmdline.commands[i].name))
573 break;
574 }
575
576 if (i >= _cmdline.num_commands)
577 return 0;
578
579 return _cmdline.commands + i;
580 }
581
_short_usage(const char * name)582 static void _short_usage(const char *name)
583 {
584 log_error("Run `%s --help' for more information.", name);
585 }
586
_usage(const char * name)587 static int _usage(const char *name)
588 {
589 struct command *com = _find_command(name);
590
591 if (!com) {
592 log_print("%s: no such command.", name);
593 return 0;
594 }
595
596 log_print("%s: %s\n\n%s", com->name, com->desc, com->usage);
597 return 1;
598 }
599
600 /*
601 * Sets up the short and long argument. If there
602 * is no short argument then the index of the
603 * argument in the the_args array is set as the
604 * long opt value. Yuck. Of course this means we
605 * can't have more than 'a' long arguments.
606 */
_add_getopt_arg(int arg,char ** ptr,struct option ** o)607 static void _add_getopt_arg(int arg, char **ptr, struct option **o)
608 {
609 struct arg *a = _cmdline.the_args + arg;
610
611 if (a->short_arg) {
612 *(*ptr)++ = a->short_arg;
613
614 if (a->fn)
615 *(*ptr)++ = ':';
616 }
617 #ifdef HAVE_GETOPTLONG
618 if (*(a->long_arg + 2)) {
619 (*o)->name = a->long_arg + 2;
620 (*o)->has_arg = a->fn ? 1 : 0;
621 (*o)->flag = NULL;
622 if (a->short_arg)
623 (*o)->val = a->short_arg;
624 else
625 (*o)->val = arg;
626 (*o)++;
627 }
628 #endif
629 }
630
_find_arg(struct command * com,int opt)631 static struct arg *_find_arg(struct command *com, int opt)
632 {
633 struct arg *a;
634 int i, arg;
635
636 for (i = 0; i < com->num_args; i++) {
637 arg = com->valid_args[i];
638 a = _cmdline.the_args + arg;
639
640 /*
641 * opt should equal either the
642 * short arg, or the index into
643 * the_args.
644 */
645 if ((a->short_arg && (opt == a->short_arg)) ||
646 (!a->short_arg && (opt == arg)))
647 return a;
648 }
649
650 return 0;
651 }
652
_process_command_line(struct cmd_context * cmd,int * argc,char *** argv)653 static int _process_command_line(struct cmd_context *cmd, int *argc,
654 char ***argv)
655 {
656 int i, opt;
657 char str[((ARG_COUNT + 1) * 2) + 1], *ptr = str;
658 struct option opts[ARG_COUNT + 1], *o = opts;
659 struct arg *a;
660
661 for (i = 0; i < ARG_COUNT; i++) {
662 a = _cmdline.the_args + i;
663
664 /* zero the count and arg */
665 a->count = 0;
666 a->value = 0;
667 a->i_value = 0;
668 a->ui_value = 0;
669 a->i64_value = 0;
670 a->ui64_value = 0;
671 }
672
673 /* fill in the short and long opts */
674 for (i = 0; i < cmd->command->num_args; i++)
675 _add_getopt_arg(cmd->command->valid_args[i], &ptr, &o);
676
677 *ptr = '\0';
678 memset(o, 0, sizeof(*o));
679
680 /* initialise getopt_long & scan for command line switches */
681 optarg = 0;
682 optind = OPTIND_INIT;
683 while ((opt = GETOPTLONG_FN(*argc, *argv, str, opts, NULL)) >= 0) {
684
685 if (opt == '?')
686 return 0;
687
688 a = _find_arg(cmd->command, opt);
689
690 if (!a) {
691 log_fatal("Unrecognised option.");
692 return 0;
693 }
694
695 if (a->count && !(a->flags & ARG_REPEATABLE)) {
696 log_error("Option%s%c%s%s may not be repeated",
697 a->short_arg ? " -" : "",
698 a->short_arg ? : ' ',
699 (a->short_arg && a->long_arg) ?
700 "/" : "", a->long_arg ? : "");
701 return 0;
702 }
703
704 if (a->fn) {
705 if (!optarg) {
706 log_error("Option requires argument.");
707 return 0;
708 }
709
710 a->value = optarg;
711
712 if (!a->fn(cmd, a)) {
713 log_error("Invalid argument %s", optarg);
714 return 0;
715 }
716 }
717
718 a->count++;
719 }
720
721 *argc -= optind;
722 *argv += optind;
723 return 1;
724 }
725
_merge_synonym(struct cmd_context * cmd,int oldarg,int newarg)726 static int _merge_synonym(struct cmd_context *cmd, int oldarg, int newarg)
727 {
728 const struct arg *old;
729 struct arg *new;
730
731 if (arg_count(cmd, oldarg) && arg_count(cmd, newarg)) {
732 log_error("%s and %s are synonyms. Please only supply one.",
733 _cmdline.the_args[oldarg].long_arg, _cmdline.the_args[newarg].long_arg);
734 return 0;
735 }
736
737 if (!arg_count(cmd, oldarg))
738 return 1;
739
740 old = _cmdline.the_args + oldarg;
741 new = _cmdline.the_args + newarg;
742
743 new->count = old->count;
744 new->value = old->value;
745 new->i_value = old->i_value;
746 new->ui_value = old->ui_value;
747 new->i64_value = old->i64_value;
748 new->ui64_value = old->ui64_value;
749 new->sign = old->sign;
750
751 return 1;
752 }
753
version(struct cmd_context * cmd __attribute ((unused)),int argc __attribute ((unused)),char ** argv __attribute ((unused)))754 int version(struct cmd_context *cmd __attribute((unused)),
755 int argc __attribute((unused)),
756 char **argv __attribute((unused)))
757 {
758 char vsn[80];
759
760 log_print("LVM version: %s", LVM_VERSION);
761 if (library_version(vsn, sizeof(vsn)))
762 log_print("Library version: %s", vsn);
763 if (driver_version(vsn, sizeof(vsn)))
764 log_print("Driver version: %s", vsn);
765
766 return ECMD_PROCESSED;
767 }
768
_get_settings(struct cmd_context * cmd)769 static int _get_settings(struct cmd_context *cmd)
770 {
771 cmd->current_settings = cmd->default_settings;
772
773 if (arg_count(cmd, debug_ARG))
774 cmd->current_settings.debug = _LOG_FATAL +
775 (arg_count(cmd, debug_ARG) - 1);
776
777 if (arg_count(cmd, verbose_ARG))
778 cmd->current_settings.verbose = arg_count(cmd, verbose_ARG);
779
780 if (arg_count(cmd, quiet_ARG)) {
781 cmd->current_settings.debug = 0;
782 cmd->current_settings.verbose = 0;
783 }
784
785 if (arg_count(cmd, test_ARG))
786 cmd->current_settings.test = arg_count(cmd, test_ARG);
787
788 if (arg_count(cmd, driverloaded_ARG)) {
789 cmd->current_settings.activation =
790 arg_int_value(cmd, driverloaded_ARG,
791 cmd->default_settings.activation);
792 }
793
794 cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive);
795 cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup);
796 cmd->current_settings.cache_vgmetadata = cmd->command->flags & CACHE_VGMETADATA ? 1 : 0;
797 cmd->partial_activation = 0;
798
799 if (arg_count(cmd, partial_ARG)) {
800 cmd->partial_activation = 1;
801 log_print("Partial mode. Incomplete volume groups will "
802 "be activated read-only.");
803 }
804
805 if (arg_count(cmd, ignorelockingfailure_ARG))
806 init_ignorelockingfailure(1);
807 else
808 init_ignorelockingfailure(0);
809
810 if (arg_count(cmd, nosuffix_ARG))
811 cmd->current_settings.suffix = 0;
812
813 if (arg_count(cmd, units_ARG))
814 if (!(cmd->current_settings.unit_factor =
815 units_to_bytes(arg_str_value(cmd, units_ARG, ""),
816 &cmd->current_settings.unit_type))) {
817 log_error("Invalid units specification");
818 return EINVALID_CMD_LINE;
819 }
820
821 if (arg_count(cmd, trustcache_ARG)) {
822 if (arg_count(cmd, all_ARG)) {
823 log_error("--trustcache is incompatible with --all");
824 return EINVALID_CMD_LINE;
825 }
826 init_trust_cache(1);
827 log_warn("WARNING: Cache file of PVs will be trusted. "
828 "New devices holding PVs may get ignored.");
829 } else
830 init_trust_cache(0);
831
832 if (arg_count(cmd, noudevsync_ARG))
833 cmd->current_settings.udev_sync = 0;
834
835 /* Handle synonyms */
836 if (!_merge_synonym(cmd, resizable_ARG, resizeable_ARG) ||
837 !_merge_synonym(cmd, allocation_ARG, allocatable_ARG) ||
838 !_merge_synonym(cmd, allocation_ARG, resizeable_ARG) ||
839 !_merge_synonym(cmd, virtualoriginsize_ARG, virtualsize_ARG) ||
840 !_merge_synonym(cmd, metadatacopies_ARG, pvmetadatacopies_ARG))
841 return EINVALID_CMD_LINE;
842
843 /* Zero indicates success */
844 return 0;
845 }
846
_process_common_commands(struct cmd_context * cmd)847 static int _process_common_commands(struct cmd_context *cmd)
848 {
849 if (arg_count(cmd, help_ARG) || arg_count(cmd, help2_ARG)) {
850 _usage(cmd->command->name);
851 return ECMD_PROCESSED;
852 }
853
854 if (arg_count(cmd, version_ARG)) {
855 return version(cmd, 0, (char **) NULL);
856 }
857
858 /* Zero indicates it's OK to continue processing this command */
859 return 0;
860 }
861
_display_help(void)862 static void _display_help(void)
863 {
864 int i;
865
866 log_error("Available lvm commands:");
867 log_error("Use 'lvm help <command>' for more information");
868 log_error(" ");
869
870 for (i = 0; i < _cmdline.num_commands; i++) {
871 struct command *com = _cmdline.commands + i;
872
873 log_error("%-16.16s%s", com->name, com->desc);
874 }
875 }
876
help(struct cmd_context * cmd __attribute ((unused)),int argc,char ** argv)877 int help(struct cmd_context *cmd __attribute((unused)), int argc, char **argv)
878 {
879 int ret = ECMD_PROCESSED;
880
881 if (!argc)
882 _display_help();
883 else {
884 int i;
885 for (i = 0; i < argc; i++)
886 if (!_usage(argv[i]))
887 ret = EINVALID_CMD_LINE;
888 }
889
890 return ret;
891 }
892
_apply_settings(struct cmd_context * cmd)893 static void _apply_settings(struct cmd_context *cmd)
894 {
895 init_debug(cmd->current_settings.debug);
896 init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL);
897 init_test(cmd->current_settings.test);
898 init_full_scan_done(0);
899 init_mirror_in_sync(0);
900
901 init_msg_prefix(cmd->default_settings.msg_prefix);
902 init_cmd_name(cmd->default_settings.cmd_name);
903
904 archive_enable(cmd, cmd->current_settings.archive);
905 backup_enable(cmd, cmd->current_settings.backup);
906
907 set_activation(cmd->current_settings.activation);
908
909 cmd->fmt = arg_ptr_value(cmd, metadatatype_ARG,
910 cmd->current_settings.fmt);
911 cmd->handles_missing_pvs = 0;
912 }
913
_copy_command_line(struct cmd_context * cmd,int argc,char ** argv)914 static const char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv)
915 {
916 int i, space;
917
918 /*
919 * Build up the complete command line, used as a
920 * description for backups.
921 */
922 if (!dm_pool_begin_object(cmd->mem, 128))
923 goto_bad;
924
925 for (i = 0; i < argc; i++) {
926 space = strchr(argv[i], ' ') ? 1 : 0;
927
928 if (space && !dm_pool_grow_object(cmd->mem, "'", 1))
929 goto_bad;
930
931 if (!dm_pool_grow_object(cmd->mem, argv[i], strlen(argv[i])))
932 goto_bad;
933
934 if (space && !dm_pool_grow_object(cmd->mem, "'", 1))
935 goto_bad;
936
937 if (i < (argc - 1))
938 if (!dm_pool_grow_object(cmd->mem, " ", 1))
939 goto_bad;
940 }
941
942 /*
943 * Terminate.
944 */
945 if (!dm_pool_grow_object(cmd->mem, "\0", 1))
946 goto_bad;
947
948 return dm_pool_end_object(cmd->mem);
949
950 bad:
951 log_error("Couldn't copy command line.");
952 dm_pool_abandon_object(cmd->mem);
953 return NULL;
954 }
955
lvm_run_command(struct cmd_context * cmd,int argc,char ** argv)956 int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
957 {
958 int ret = 0;
959 int locking_type;
960
961 init_error_message_produced(0);
962
963 /* each command should start out with sigint flag cleared */
964 sigint_clear();
965
966 if (!(cmd->cmd_line = _copy_command_line(cmd, argc, argv))) {
967 stack;
968 return ECMD_FAILED;
969 }
970
971 log_debug("Parsing: %s", cmd->cmd_line);
972
973 if (!(cmd->command = _find_command(argv[0])))
974 return ENO_SUCH_CMD;
975
976 if (!_process_command_line(cmd, &argc, &argv)) {
977 log_error("Error during parsing of command line.");
978 return EINVALID_CMD_LINE;
979 }
980
981 set_cmd_name(cmd->command->name);
982
983 if (arg_count(cmd, config_ARG))
984 if ((ret = override_config_tree_from_string(cmd,
985 arg_str_value(cmd, config_ARG, "")))) {
986 ret = EINVALID_CMD_LINE;
987 goto_out;
988 }
989
990 if (arg_count(cmd, config_ARG) || !cmd->config_valid || config_files_changed(cmd)) {
991 /* Reinitialise various settings inc. logging, filters */
992 if (!refresh_toolcontext(cmd)) {
993 log_error("Updated config file invalid. Aborting.");
994 return ECMD_FAILED;
995 }
996 }
997
998 if ((ret = _get_settings(cmd)))
999 goto_out;
1000 _apply_settings(cmd);
1001
1002 log_debug("Processing: %s", cmd->cmd_line);
1003
1004 #ifdef O_DIRECT_SUPPORT
1005 log_debug("O_DIRECT will be used");
1006 #endif
1007
1008 if ((ret = _process_common_commands(cmd)))
1009 goto_out;
1010
1011 if (arg_count(cmd, nolocking_ARG))
1012 locking_type = 0;
1013 else
1014 locking_type = -1;
1015
1016 if (!init_locking(locking_type, cmd)) {
1017 log_error("Locking type %d initialisation failed.",
1018 locking_type);
1019 ret = ECMD_FAILED;
1020 goto out;
1021 }
1022
1023 ret = cmd->command->fn(cmd, argc, argv);
1024
1025 fin_locking();
1026
1027 out:
1028 if (test_mode()) {
1029 log_verbose("Test mode: Wiping internal cache");
1030 lvmcache_destroy(cmd, 1);
1031 }
1032
1033 if (cmd->cft_override) {
1034 destroy_config_tree(cmd->cft_override);
1035 cmd->cft_override = NULL;
1036 /* Move this? */
1037 if (!refresh_toolcontext(cmd))
1038 stack;
1039 }
1040
1041 /* FIXME Move this? */
1042 cmd->current_settings = cmd->default_settings;
1043 _apply_settings(cmd);
1044
1045 if (ret == EINVALID_CMD_LINE && !_cmdline.interactive)
1046 _short_usage(cmd->command->name);
1047
1048 log_debug("Completed: %s", cmd->cmd_line);
1049
1050 /*
1051 * free off any memory the command used.
1052 */
1053 dm_pool_empty(cmd->mem);
1054
1055 reset_lvm_errno(1);
1056
1057 return ret;
1058 }
1059
lvm_split(char * str,int * argc,char ** argv,int max)1060 int lvm_split(char *str, int *argc, char **argv, int max)
1061 {
1062 char *b = str, *e;
1063 *argc = 0;
1064
1065 while (*b) {
1066 while (*b && isspace(*b))
1067 b++;
1068
1069 if ((!*b) || (*b == '#'))
1070 break;
1071
1072 e = b;
1073 while (*e && !isspace(*e))
1074 e++;
1075
1076 argv[(*argc)++] = b;
1077 if (!*e)
1078 break;
1079 *e++ = '\0';
1080 b = e;
1081 if (*argc == max)
1082 break;
1083 }
1084
1085 return *argc;
1086 }
1087
_get_cmdline(pid_t pid)1088 static const char *_get_cmdline(pid_t pid)
1089 {
1090 static char _proc_cmdline[32];
1091 char buf[256];
1092 int fd;
1093
1094 snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/%u/cmdline", pid);
1095 if ((fd = open(buf, O_RDONLY)) > 0) {
1096 read(fd, _proc_cmdline, sizeof(_proc_cmdline) - 1);
1097 _proc_cmdline[sizeof(_proc_cmdline) - 1] = '\0';
1098 close(fd);
1099 } else
1100 _proc_cmdline[0] = '\0';
1101
1102 return _proc_cmdline;
1103 }
1104
_get_filename(int fd)1105 static const char *_get_filename(int fd)
1106 {
1107 static char filename[PATH_MAX];
1108 char buf[32]; /* Assumes short DEFAULT_PROC_DIR */
1109 int size;
1110
1111 snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/self/fd/%u", fd);
1112
1113 if ((size = readlink(buf, filename, sizeof(filename) - 1)) == -1)
1114 filename[0] = '\0';
1115 else
1116 filename[size] = '\0';
1117
1118 return filename;
1119 }
1120
_close_descriptor(int fd,unsigned suppress_warnings,const char * command,pid_t ppid,const char * parent_cmdline)1121 static void _close_descriptor(int fd, unsigned suppress_warnings,
1122 const char *command, pid_t ppid,
1123 const char *parent_cmdline)
1124 {
1125 int r;
1126 const char *filename;
1127
1128 /* Ignore bad file descriptors */
1129 if (fcntl(fd, F_GETFD) == -1 && errno == EBADF)
1130 return;
1131
1132 if (!suppress_warnings)
1133 filename = _get_filename(fd);
1134
1135 r = close(fd);
1136 if (suppress_warnings)
1137 return;
1138
1139 if (!r)
1140 fprintf(stderr, "File descriptor %d (%s) leaked on "
1141 "%s invocation.", fd, filename, command);
1142 else if (errno == EBADF)
1143 return;
1144 else
1145 fprintf(stderr, "Close failed on stray file descriptor "
1146 "%d (%s): %s", fd, filename, strerror(errno));
1147
1148 fprintf(stderr, " Parent PID %" PRIpid_t ": %s\n", ppid, parent_cmdline);
1149 }
1150
_close_stray_fds(const char * command)1151 static void _close_stray_fds(const char *command)
1152 {
1153 struct rlimit rlim;
1154 int fd;
1155 unsigned suppress_warnings = 0;
1156 pid_t ppid = getppid();
1157 const char *parent_cmdline = _get_cmdline(ppid);
1158
1159 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
1160 fprintf(stderr, "getrlimit(RLIMIT_NOFILE) failed: %s\n",
1161 strerror(errno));
1162 return;
1163 }
1164
1165 if (getenv("LVM_SUPPRESS_FD_WARNINGS"))
1166 suppress_warnings = 1;
1167
1168 for (fd = 3; fd < rlim.rlim_cur; fd++)
1169 _close_descriptor(fd, suppress_warnings, command, ppid,
1170 parent_cmdline);
1171 }
1172
init_lvm(void)1173 struct cmd_context *init_lvm(void)
1174 {
1175 struct cmd_context *cmd;
1176
1177 _cmdline.the_args = &_the_args[0];
1178
1179 if (!(cmd = create_toolcontext(0, NULL)))
1180 return_NULL;
1181
1182 if (stored_errno()) {
1183 destroy_toolcontext(cmd);
1184 return_NULL;
1185 }
1186
1187 return cmd;
1188 }
1189
_fin_commands(void)1190 static void _fin_commands(void)
1191 {
1192 int i;
1193
1194 for (i = 0; i < _cmdline.num_commands; i++)
1195 dm_free(_cmdline.commands[i].valid_args);
1196
1197 dm_free(_cmdline.commands);
1198 }
1199
lvm_fin(struct cmd_context * cmd)1200 void lvm_fin(struct cmd_context *cmd)
1201 {
1202 _fin_commands();
1203 destroy_toolcontext(cmd);
1204 }
1205
_run_script(struct cmd_context * cmd,int argc,char ** argv)1206 static int _run_script(struct cmd_context *cmd, int argc, char **argv)
1207 {
1208 FILE *script;
1209
1210 char buffer[CMD_LEN];
1211 int ret = 0;
1212 int magic_number = 0;
1213 char *script_file = argv[0];
1214
1215 if ((script = fopen(script_file, "r")) == NULL)
1216 return ENO_SUCH_CMD;
1217
1218 while (fgets(buffer, sizeof(buffer), script) != NULL) {
1219 if (!magic_number) {
1220 if (buffer[0] == '#' && buffer[1] == '!')
1221 magic_number = 1;
1222 else {
1223 ret = ENO_SUCH_CMD;
1224 break;
1225 }
1226 }
1227 if ((strlen(buffer) == sizeof(buffer) - 1)
1228 && (buffer[sizeof(buffer) - 1] - 2 != '\n')) {
1229 buffer[50] = '\0';
1230 log_error("Line too long (max 255) beginning: %s",
1231 buffer);
1232 ret = EINVALID_CMD_LINE;
1233 break;
1234 }
1235 if (lvm_split(buffer, &argc, argv, MAX_ARGS) == MAX_ARGS) {
1236 buffer[50] = '\0';
1237 log_error("Too many arguments: %s", buffer);
1238 ret = EINVALID_CMD_LINE;
1239 break;
1240 }
1241 if (!argc)
1242 continue;
1243 if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit"))
1244 break;
1245 ret = lvm_run_command(cmd, argc, argv);
1246 if (ret != ECMD_PROCESSED) {
1247 if (!error_message_produced()) {
1248 log_debug("Internal error: Failed command did not use log_error");
1249 log_error("Command failed with status code %d.", ret);
1250 }
1251 break;
1252 }
1253 }
1254
1255 if (fclose(script))
1256 log_sys_error("fclose", script_file);
1257
1258 return ret;
1259 }
1260
1261 /*
1262 * Determine whether we should fall back and exec the equivalent LVM1 tool
1263 */
_lvm1_fallback(struct cmd_context * cmd)1264 static int _lvm1_fallback(struct cmd_context *cmd)
1265 {
1266 char vsn[80];
1267 int dm_present;
1268
1269 if (!find_config_tree_int(cmd, "global/fallback_to_lvm1",
1270 DEFAULT_FALLBACK_TO_LVM1) ||
1271 strncmp(cmd->kernel_vsn, "2.4.", 4))
1272 return 0;
1273
1274 log_suppress(1);
1275 dm_present = driver_version(vsn, sizeof(vsn));
1276 log_suppress(0);
1277
1278 if (dm_present || !lvm1_present(cmd))
1279 return 0;
1280
1281 return 1;
1282 }
1283
_exec_lvm1_command(char ** argv)1284 static void _exec_lvm1_command(char **argv)
1285 {
1286 char path[PATH_MAX];
1287
1288 if (dm_snprintf(path, sizeof(path), "%s.lvm1", argv[0]) < 0) {
1289 log_error("Failed to create LVM1 tool pathname");
1290 return;
1291 }
1292
1293 execvp(path, argv);
1294 log_sys_error("execvp", path);
1295 }
1296
_nonroot_warning(void)1297 static void _nonroot_warning(void)
1298 {
1299 #ifdef __NetBSD__
1300 gid_t groups_list[NGROUPS_MAX];
1301 int i, group_num, is_operator = 0;
1302
1303 /* Operator group in NetBSD should be able to see lvm status. */
1304 if (getuid() || geteuid()) {
1305 group_num = getgroups(NGROUPS_MAX, groups_list);
1306
1307 for (i = 0; i < group_num; i++) {
1308 if (groups_list[i] == DM_DEVICE_GID) {
1309 is_operator = 1;
1310 init_operator(is_operator);
1311 break;
1312 }
1313 }
1314
1315 if (is_operator)
1316 log_warn("WARNING: Using LVM as operator you have only read access.");
1317 else
1318 log_warn("WARNING: Running as a non-root user and without "
1319 "operator group. Functionality may be unavailable.");
1320 }
1321 #else
1322 if (getuid() || geteuid())
1323 log_warn("WARNING: Running as a non-root user. Functionality may be unavailable.");
1324 #endif
1325 }
1326
lvm2_main(int argc,char ** argv)1327 int lvm2_main(int argc, char **argv)
1328 {
1329 const char *base;
1330 int ret, alias = 0;
1331 struct cmd_context *cmd;
1332
1333 base = last_path_component(argv[0]);
1334 if (strcmp(base, "lvm") && strcmp(base, "lvm.static") &&
1335 strcmp(base, "initrd-lvm"))
1336 alias = 1;
1337
1338 _close_stray_fds(base);
1339
1340 if (is_static() && strcmp(base, "lvm.static") &&
1341 path_exists(LVM_SHARED_PATH) &&
1342 !getenv("LVM_DID_EXEC")) {
1343 setenv("LVM_DID_EXEC", base, 1);
1344 execvp(LVM_SHARED_PATH, argv);
1345 unsetenv("LVM_DID_EXEC");
1346 }
1347
1348 if (!(cmd = init_lvm()))
1349 return -1;
1350
1351 cmd->argv = argv;
1352 lvm_register_commands();
1353
1354 if (_lvm1_fallback(cmd)) {
1355 /* Attempt to run equivalent LVM1 tool instead */
1356 if (!alias) {
1357 argv++;
1358 argc--;
1359 alias = 0;
1360 }
1361 if (!argc) {
1362 log_error("Falling back to LVM1 tools, but no "
1363 "command specified.");
1364 return ECMD_FAILED;
1365 }
1366 _exec_lvm1_command(argv);
1367 return ECMD_FAILED;
1368 }
1369 #ifdef READLINE_SUPPORT
1370 if (!alias && argc == 1) {
1371 _nonroot_warning();
1372 ret = lvm_shell(cmd, &_cmdline);
1373 goto out;
1374 }
1375 #endif
1376
1377 if (!alias) {
1378 if (argc < 2) {
1379 log_fatal("Please supply an LVM command.");
1380 _display_help();
1381 ret = EINVALID_CMD_LINE;
1382 goto out;
1383 }
1384
1385 argc--;
1386 argv++;
1387 }
1388
1389 _nonroot_warning();
1390 ret = lvm_run_command(cmd, argc, argv);
1391 if ((ret == ENO_SUCH_CMD) && (!alias))
1392 ret = _run_script(cmd, argc, argv);
1393 if (ret == ENO_SUCH_CMD)
1394 log_error("No such command. Try 'help'.");
1395
1396 if ((ret != ECMD_PROCESSED) && !error_message_produced()) {
1397 log_debug("Internal error: Failed command did not use log_error");
1398 log_error("Command failed with status code %d.", ret);
1399 }
1400
1401 out:
1402 lvm_fin(cmd);
1403 if (ret == ECMD_PROCESSED)
1404 ret = 0;
1405 return ret;
1406 }
1407