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