]> sourceware.org Git - lvm2.git/blob - tools/dmsetup.c
thin: tighten discard string conversions
[lvm2.git] / tools / dmsetup.c
1 /*
2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
4 * Copyright (C) 2005-2007 NEC Corporation
5 *
6 * This file is part of the device-mapper userspace tools.
7 *
8 * It includes tree drawing code based on pstree: http://psmisc.sourceforge.net/
9 *
10 * This copyrighted material is made available to anyone wishing to use,
11 * modify, copy, or redistribute it subject to the terms and conditions
12 * of the GNU General Public License v.2.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #define _GNU_SOURCE
20 #define _FILE_OFFSET_BITS 64
21
22 #include "configure.h"
23
24 #include "dm-logging.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <dirent.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <libgen.h>
34 #include <sys/wait.h>
35 #include <unistd.h>
36 #include <sys/param.h>
37 #include <locale.h>
38 #include <langinfo.h>
39 #include <time.h>
40
41 #include <fcntl.h>
42 #include <sys/stat.h>
43
44 #ifdef UDEV_SYNC_SUPPORT
45 # include <sys/types.h>
46 # include <sys/ipc.h>
47 # include <sys/sem.h>
48 # include <libudev.h>
49 #endif
50
51 /* FIXME Unused so far */
52 #undef HAVE_SYS_STATVFS_H
53
54 #ifdef HAVE_SYS_STATVFS_H
55 # include <sys/statvfs.h>
56 #endif
57
58 #ifdef HAVE_SYS_IOCTL_H
59 # include <sys/ioctl.h>
60 #endif
61
62 #if HAVE_TERMIOS_H
63 # include <termios.h>
64 #endif
65
66 #ifdef HAVE_GETOPTLONG
67 # include <getopt.h>
68 # define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
69 # define OPTIND_INIT 0
70 #else
71 struct option {
72 };
73 extern int optind;
74 extern char *optarg;
75 # define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))
76 # define OPTIND_INIT 1
77 #endif
78
79 #ifndef TEMP_FAILURE_RETRY
80 # define TEMP_FAILURE_RETRY(expression) \
81 (__extension__ \
82 ({ long int __result; \
83 do __result = (long int) (expression); \
84 while (__result == -1L && errno == EINTR); \
85 __result; }))
86 #endif
87
88 #ifdef linux
89 # include "kdev_t.h"
90 #else
91 # define MAJOR(x) major((x))
92 # define MINOR(x) minor((x))
93 # define MKDEV(x,y) makedev((x),(y))
94 #endif
95
96 #define LINE_SIZE 4096
97 #define ARGS_MAX 256
98 #define LOOP_TABLE_SIZE (PATH_MAX + 255)
99
100 #define DEFAULT_DM_DEV_DIR "/dev/"
101
102 #define DM_DEV_DIR_ENV_VAR_NAME "DM_DEV_DIR"
103 #define DM_UDEV_COOKIE_ENV_VAR_NAME "DM_UDEV_COOKIE"
104
105 /* FIXME Should be imported */
106 #ifndef DM_MAX_TYPE_NAME
107 # define DM_MAX_TYPE_NAME 16
108 #endif
109
110 /* FIXME Should be elsewhere */
111 #define SECTOR_SHIFT 9L
112
113 #define err(msg, x...) fprintf(stderr, msg "\n", ##x)
114
115 /*
116 * We have only very simple switches ATM.
117 */
118 enum {
119 READ_ONLY = 0,
120 ADD_NODE_ON_CREATE_ARG,
121 ADD_NODE_ON_RESUME_ARG,
122 CHECKS_ARG,
123 COLS_ARG,
124 EXEC_ARG,
125 FORCE_ARG,
126 GID_ARG,
127 HELP_ARG,
128 INACTIVE_ARG,
129 MANGLENAME_ARG,
130 MAJOR_ARG,
131 MINOR_ARG,
132 MODE_ARG,
133 NAMEPREFIXES_ARG,
134 NOFLUSH_ARG,
135 NOHEADINGS_ARG,
136 NOLOCKFS_ARG,
137 NOOPENCOUNT_ARG,
138 NOTABLE_ARG,
139 UDEVCOOKIE_ARG,
140 NOUDEVRULES_ARG,
141 NOUDEVSYNC_ARG,
142 OPTIONS_ARG,
143 READAHEAD_ARG,
144 RETRY_ARG,
145 ROWS_ARG,
146 SEPARATOR_ARG,
147 SETUUID_ARG,
148 SHOWKEYS_ARG,
149 SORT_ARG,
150 TABLE_ARG,
151 TARGET_ARG,
152 TREE_ARG,
153 UID_ARG,
154 UNBUFFERED_ARG,
155 UNQUOTED_ARG,
156 UUID_ARG,
157 VERBOSE_ARG,
158 VERIFYUDEV_ARG,
159 VERSION_ARG,
160 YES_ARG,
161 NUM_SWITCHES
162 };
163
164 typedef enum {
165 DR_TASK = 1,
166 DR_INFO = 2,
167 DR_DEPS = 4,
168 DR_TREE = 8, /* Complete dependency tree required */
169 DR_NAME = 16
170 } report_type_t;
171
172 typedef enum {
173 DN_DEVNO, /* Major and minor number pair */
174 DN_BLK, /* Block device name (e.g. dm-0) */
175 DN_MAP /* Map name (for dm devices only, equal to DN_BLK otherwise) */
176 } dev_name_t;
177
178 static int _switches[NUM_SWITCHES];
179 static int _int_args[NUM_SWITCHES];
180 static char *_string_args[NUM_SWITCHES];
181 static int _num_devices;
182 static char *_uuid;
183 static char *_table;
184 static char *_target;
185 static char *_command;
186 static uint32_t _read_ahead_flags;
187 static uint32_t _udev_cookie;
188 static int _udev_only;
189 static struct dm_tree *_dtree;
190 static struct dm_report *_report;
191 static report_type_t _report_type;
192 static dev_name_t _dev_name_type;
193
194 /*
195 * Commands
196 */
197
198 struct command;
199 #define CMD_ARGS const struct command *cmd, int argc, char **argv, struct dm_names *names, int multiple_devices
200 typedef int (*command_fn) (CMD_ARGS);
201
202 struct command {
203 const char *name;
204 const char *help;
205 int min_args;
206 int max_args;
207 int repeatable_cmd; /* Repeat to process device list? */
208 command_fn fn;
209 };
210
211 static int _parse_line(struct dm_task *dmt, char *buffer, const char *file,
212 int line)
213 {
214 char ttype[LINE_SIZE], *ptr, *comment;
215 unsigned long long start, size;
216 int n;
217
218 /* trim trailing space */
219 for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr--)
220 if (!isspace((int) *ptr))
221 break;
222 ptr++;
223 *ptr = '\0';
224
225 /* trim leading space */
226 for (ptr = buffer; *ptr && isspace((int) *ptr); ptr++)
227 ;
228
229 if (!*ptr || *ptr == '#')
230 return 1;
231
232 if (sscanf(ptr, "%llu %llu %s %n",
233 &start, &size, ttype, &n) < 3) {
234 err("Invalid format on line %d of table %s", line, file);
235 return 0;
236 }
237
238 ptr += n;
239 if ((comment = strchr(ptr, (int) '#')))
240 *comment = '\0';
241
242 if (!dm_task_add_target(dmt, start, size, ttype, ptr))
243 return 0;
244
245 return 1;
246 }
247
248 static int _parse_file(struct dm_task *dmt, const char *file)
249 {
250 char *buffer = NULL;
251 size_t buffer_size = 0;
252 FILE *fp;
253 int r = 0, line = 0;
254
255 /* one-line table on cmdline */
256 if (_table)
257 return _parse_line(dmt, _table, "", ++line);
258
259 /* OK for empty stdin */
260 if (file) {
261 if (!(fp = fopen(file, "r"))) {
262 err("Couldn't open '%s' for reading", file);
263 return 0;
264 }
265 } else
266 fp = stdin;
267
268 #ifndef HAVE_GETLINE
269 buffer_size = LINE_SIZE;
270 if (!(buffer = dm_malloc(buffer_size))) {
271 err("Failed to malloc line buffer.");
272 return 0;
273 }
274
275 while (fgets(buffer, (int) buffer_size, fp))
276 #else
277 while (getline(&buffer, &buffer_size, fp) > 0)
278 #endif
279 if (!_parse_line(dmt, buffer, file ? : "on stdin", ++line))
280 goto out;
281
282 r = 1;
283
284 out:
285 memset(buffer, 0, buffer_size);
286 #ifndef HAVE_GETLINE
287 dm_free(buffer);
288 #else
289 free(buffer);
290 #endif
291 if (file && fclose(fp))
292 fprintf(stderr, "%s: fclose failed: %s", file, strerror(errno));
293
294 return r;
295 }
296
297 struct dm_split_name {
298 char *subsystem;
299 char *vg_name;
300 char *lv_name;
301 char *lv_layer;
302 };
303
304 struct dmsetup_report_obj {
305 struct dm_task *task;
306 struct dm_info *info;
307 struct dm_task *deps_task;
308 struct dm_tree_node *tree_node;
309 struct dm_split_name *split_name;
310 };
311
312 static struct dm_task *_get_deps_task(int major, int minor)
313 {
314 struct dm_task *dmt;
315 struct dm_info info;
316
317 if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
318 return NULL;
319
320 if (!dm_task_set_major(dmt, major) ||
321 !dm_task_set_minor(dmt, minor))
322 goto err;
323
324 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
325 goto err;
326
327 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
328 goto err;
329
330 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
331 goto err;
332
333 if (!dm_task_run(dmt))
334 goto err;
335
336 if (!dm_task_get_info(dmt, &info))
337 goto err;
338
339 if (!info.exists)
340 goto err;
341
342 return dmt;
343
344 err:
345 dm_task_destroy(dmt);
346 return NULL;
347 }
348
349 static char *_extract_uuid_prefix(const char *uuid, const int separator)
350 {
351 char *ptr = NULL;
352 char *uuid_prefix = NULL;
353 size_t len;
354
355 if (uuid)
356 ptr = strchr(uuid, separator);
357
358 len = ptr ? ptr - uuid : 0;
359 if (!(uuid_prefix = dm_malloc(len + 1))) {
360 log_error("Failed to allocate memory to extract uuid prefix.");
361 return NULL;
362 }
363
364 if (uuid)
365 memcpy(uuid_prefix, uuid, len);
366
367 uuid_prefix[len] = '\0';
368
369 return uuid_prefix;
370 }
371
372 static struct dm_split_name *_get_split_name(const char *uuid, const char *name,
373 int separator)
374 {
375 struct dm_split_name *split_name;
376
377 if (!(split_name = dm_malloc(sizeof(*split_name)))) {
378 log_error("Failed to allocate memory to split device name "
379 "into components.");
380 return NULL;
381 }
382
383 if (!(split_name->subsystem = _extract_uuid_prefix(uuid, separator)))
384 return_NULL;
385
386 split_name->vg_name = split_name->lv_name =
387 split_name->lv_layer = (char *) "";
388
389 if (!strcmp(split_name->subsystem, "LVM") &&
390 (!(split_name->vg_name = dm_strdup(name)) ||
391 !dm_split_lvm_name(NULL, NULL, &split_name->vg_name,
392 &split_name->lv_name, &split_name->lv_layer)))
393 log_error("Failed to allocate memory to split LVM name "
394 "into components.");
395
396 return split_name;
397 }
398
399 static void _destroy_split_name(struct dm_split_name *split_name)
400 {
401 /*
402 * lv_name and lv_layer are allocated within the same block
403 * of memory as vg_name so don't need to be freed separately.
404 */
405 if (!strcmp(split_name->subsystem, "LVM"))
406 dm_free(split_name->vg_name);
407
408 dm_free(split_name->subsystem);
409 dm_free(split_name);
410 }
411
412 static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
413 {
414 struct dmsetup_report_obj obj;
415 int r = 0;
416
417 if (!info->exists) {
418 fprintf(stderr, "Device does not exist.\n");
419 return 0;
420 }
421
422 obj.task = dmt;
423 obj.info = info;
424 obj.deps_task = NULL;
425 obj.split_name = NULL;
426
427 if (_report_type & DR_TREE)
428 if (!(obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor))) {
429 log_error("Cannot find node %d:%d.", info->major, info->minor);
430 goto out;
431 }
432
433 if (_report_type & DR_DEPS)
434 if (!(obj.deps_task = _get_deps_task(info->major, info->minor))) {
435 log_error("Cannot get deps for %d:%d.", info->major, info->minor);
436 goto out;
437 }
438
439 if (_report_type & DR_NAME)
440 if (!(obj.split_name = _get_split_name(dm_task_get_uuid(dmt),
441 dm_task_get_name(dmt), '-')))
442 goto_out;
443
444 if (!dm_report_object(_report, &obj))
445 goto_out;
446
447 r = 1;
448
449 out:
450 if (obj.deps_task)
451 dm_task_destroy(obj.deps_task);
452 if (obj.split_name)
453 _destroy_split_name(obj.split_name);
454 return r;
455 }
456
457 static void _display_info_long(struct dm_task *dmt, struct dm_info *info)
458 {
459 const char *uuid;
460 uint32_t read_ahead;
461
462 if (!info->exists) {
463 printf("Device does not exist.\n");
464 return;
465 }
466
467 printf("Name: %s\n", dm_task_get_name(dmt));
468
469 printf("State: %s%s\n",
470 info->suspended ? "SUSPENDED" : "ACTIVE",
471 info->read_only ? " (READ-ONLY)" : "");
472
473 /* FIXME Old value is being printed when it's being changed. */
474 if (dm_task_get_read_ahead(dmt, &read_ahead))
475 printf("Read Ahead: %" PRIu32 "\n", read_ahead);
476
477 if (!info->live_table && !info->inactive_table)
478 printf("Tables present: None\n");
479 else
480 printf("Tables present: %s%s%s\n",
481 info->live_table ? "LIVE" : "",
482 info->live_table && info->inactive_table ? " & " : "",
483 info->inactive_table ? "INACTIVE" : "");
484
485 if (info->open_count != -1)
486 printf("Open count: %d\n", info->open_count);
487
488 printf("Event number: %" PRIu32 "\n", info->event_nr);
489 printf("Major, minor: %d, %d\n", info->major, info->minor);
490
491 if (info->target_count != -1)
492 printf("Number of targets: %d\n", info->target_count);
493
494 if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
495 printf("UUID: %s\n", uuid);
496
497 printf("\n");
498 }
499
500 static int _display_info(struct dm_task *dmt)
501 {
502 struct dm_info info;
503
504 if (!dm_task_get_info(dmt, &info))
505 return 0;
506
507 if (!_switches[COLS_ARG])
508 _display_info_long(dmt, &info);
509 else
510 /* FIXME return code */
511 _display_info_cols(dmt, &info);
512
513 return info.exists ? 1 : 0;
514 }
515
516 static int _set_task_device(struct dm_task *dmt, const char *name, int optional)
517 {
518 if (name) {
519 if (!dm_task_set_name(dmt, name))
520 return 0;
521 } else if (_switches[UUID_ARG]) {
522 if (!dm_task_set_uuid(dmt, _uuid))
523 return 0;
524 } else if (_switches[MAJOR_ARG] && _switches[MINOR_ARG]) {
525 if (!dm_task_set_major(dmt, _int_args[MAJOR_ARG]) ||
526 !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
527 return 0;
528 } else if (!optional) {
529 fprintf(stderr, "No device specified.\n");
530 return 0;
531 }
532
533 return 1;
534 }
535
536 static int _set_task_add_node(struct dm_task *dmt)
537 {
538 if (!dm_task_set_add_node(dmt, DEFAULT_DM_ADD_NODE))
539 return 0;
540
541 if (_switches[ADD_NODE_ON_RESUME_ARG] &&
542 !dm_task_set_add_node(dmt, DM_ADD_NODE_ON_RESUME))
543 return 0;
544
545 if (_switches[ADD_NODE_ON_CREATE_ARG] &&
546 !dm_task_set_add_node(dmt, DM_ADD_NODE_ON_CREATE))
547 return 0;
548
549 return 1;
550 }
551
552 static int _load(CMD_ARGS)
553 {
554 int r = 0;
555 struct dm_task *dmt;
556 const char *file = NULL;
557 const char *name = NULL;
558
559 if (_switches[NOTABLE_ARG]) {
560 err("--notable only available when creating new device\n");
561 return 0;
562 }
563
564 if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
565 if (argc == 1) {
566 err("Please specify device.\n");
567 return 0;
568 }
569 name = argv[1];
570 argc--;
571 argv++;
572 } else if (argc > 2) {
573 err("Too many command line arguments.\n");
574 return 0;
575 }
576
577 if (argc == 2)
578 file = argv[1];
579
580 if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
581 return 0;
582
583 if (!_set_task_device(dmt, name, 0))
584 goto out;
585
586 if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file))
587 goto out;
588
589 if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
590 goto out;
591
592 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
593 goto out;
594
595 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
596 goto out;
597
598 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
599 goto out;
600
601 if (!dm_task_run(dmt))
602 goto out;
603
604 r = 1;
605
606 if (_switches[VERBOSE_ARG])
607 r = _display_info(dmt);
608
609 out:
610 dm_task_destroy(dmt);
611
612 return r;
613 }
614
615 static int _create(CMD_ARGS)
616 {
617 int r = 0;
618 struct dm_task *dmt;
619 const char *file = NULL;
620 uint32_t cookie = 0;
621 uint16_t udev_flags = 0;
622
623 if (argc == 3)
624 file = argv[2];
625
626 if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
627 return 0;
628
629 if (!dm_task_set_name(dmt, argv[1]))
630 goto out;
631
632 if (_switches[UUID_ARG] && !dm_task_set_uuid(dmt, _uuid))
633 goto out;
634
635 if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file))
636 goto out;
637
638 if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
639 goto out;
640
641 if (_switches[MAJOR_ARG] && !dm_task_set_major(dmt, _int_args[MAJOR_ARG]))
642 goto out;
643
644 if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
645 goto out;
646
647 if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _int_args[UID_ARG]))
648 goto out;
649
650 if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _int_args[GID_ARG]))
651 goto out;
652
653 if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _int_args[MODE_ARG]))
654 goto out;
655
656 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
657 goto out;
658
659 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
660 goto out;
661
662 if (_switches[READAHEAD_ARG] &&
663 !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG],
664 _read_ahead_flags))
665 goto out;
666
667 if (_switches[NOTABLE_ARG])
668 dm_udev_set_sync_support(0);
669
670 if (_switches[NOUDEVRULES_ARG])
671 udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
672 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
673
674 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
675 goto out;
676
677 if (!_set_task_add_node(dmt))
678 goto out;
679
680 if (_udev_cookie)
681 cookie = _udev_cookie;
682
683 if (_udev_only)
684 udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
685
686 if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
687 !dm_task_run(dmt))
688 goto out;
689
690 r = 1;
691
692 out:
693 if (!_udev_cookie)
694 (void) dm_udev_wait(cookie);
695
696 if (r && _switches[VERBOSE_ARG])
697 r = _display_info(dmt);
698
699 dm_task_destroy(dmt);
700
701 return r;
702 }
703
704 static int _do_rename(const char *name, const char *new_name, const char *new_uuid) {
705 int r = 0;
706 struct dm_task *dmt;
707 uint32_t cookie = 0;
708 uint16_t udev_flags = 0;
709
710 if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
711 return 0;
712
713 /* FIXME Kernel doesn't support uuid or device number here yet */
714 if (!_set_task_device(dmt, name, 0))
715 goto out;
716
717 if (new_uuid) {
718 if (!dm_task_set_newuuid(dmt, new_uuid))
719 goto out;
720 } else if (!dm_task_set_newname(dmt, new_name))
721 goto out;
722
723 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
724 goto out;
725
726 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
727 goto out;
728
729 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
730 goto out;
731
732 if (_switches[NOUDEVRULES_ARG])
733 udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
734 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
735
736 if (_udev_cookie)
737 cookie = _udev_cookie;
738
739 if (_udev_only)
740 udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
741
742 if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
743 !dm_task_run(dmt))
744 goto out;
745
746 r = 1;
747
748 out:
749 if (!_udev_cookie)
750 (void) dm_udev_wait(cookie);
751
752 dm_task_destroy(dmt);
753
754 return r;
755 }
756
757 static int _rename(CMD_ARGS)
758 {
759 const char *name = (argc == 3) ? argv[1] : NULL;
760
761 return _switches[SETUUID_ARG] ? _do_rename(name, NULL, argv[argc - 1]) :
762 _do_rename(name, argv[argc - 1], NULL);
763
764 }
765
766 static int _message(CMD_ARGS)
767 {
768 int r = 0, i;
769 size_t sz = 1;
770 struct dm_task *dmt;
771 char *str;
772
773 if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
774 return 0;
775
776 if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) {
777 if (!_set_task_device(dmt, NULL, 0))
778 goto out;
779 } else {
780 if (!_set_task_device(dmt, argv[1], 0))
781 goto out;
782 argc--;
783 argv++;
784 }
785
786 if (!dm_task_set_sector(dmt, (uint64_t) atoll(argv[1])))
787 goto out;
788
789 argc -= 2;
790 argv += 2;
791
792 if (argc <= 0)
793 err("No message supplied.\n");
794
795 for (i = 0; i < argc; i++)
796 sz += strlen(argv[i]) + 1;
797
798 if (!(str = dm_zalloc(sz))) {
799 err("message string allocation failed");
800 goto out;
801 }
802
803 for (i = 0; i < argc; i++) {
804 if (i)
805 strcat(str, " ");
806 strcat(str, argv[i]);
807 }
808
809 i = dm_task_set_message(dmt, str);
810
811 dm_free(str);
812
813 if (!i)
814 goto out;
815
816 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
817 goto out;
818
819 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
820 goto out;
821
822 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
823 goto out;
824
825 if (!dm_task_run(dmt))
826 goto out;
827
828 r = 1;
829
830 out:
831 dm_task_destroy(dmt);
832
833 return r;
834 }
835
836 static int _setgeometry(CMD_ARGS)
837 {
838 int r = 0;
839 struct dm_task *dmt;
840
841 if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY)))
842 return 0;
843
844 if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) {
845 if (!_set_task_device(dmt, NULL, 0))
846 goto out;
847 } else {
848 if (!_set_task_device(dmt, argv[1], 0))
849 goto out;
850 argc--;
851 argv++;
852 }
853
854 if (!dm_task_set_geometry(dmt, argv[1], argv[2], argv[3], argv[4]))
855 goto out;
856
857 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
858 goto out;
859
860 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
861 goto out;
862
863 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
864 goto out;
865
866 /* run the task */
867 if (!dm_task_run(dmt))
868 goto out;
869
870 r = 1;
871
872 out:
873 dm_task_destroy(dmt);
874
875 return r;
876 }
877
878 static int _splitname(CMD_ARGS)
879 {
880 struct dmsetup_report_obj obj;
881 int r = 1;
882
883 obj.task = NULL;
884 obj.info = NULL;
885 obj.deps_task = NULL;
886 obj.tree_node = NULL;
887 if (!(obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM",
888 argv[1], '\0')))
889 return_0;
890
891 r = dm_report_object(_report, &obj);
892 _destroy_split_name(obj.split_name);
893
894 return r;
895 }
896
897 static uint32_t _get_cookie_value(const char *str_value)
898 {
899 unsigned long int value;
900 char *p;
901
902 if (!(value = strtoul(str_value, &p, 0)) ||
903 *p ||
904 (value == ULONG_MAX && errno == ERANGE) ||
905 value > 0xFFFFFFFF) {
906 err("Incorrect cookie value");
907 return 0;
908 }
909 else
910 return (uint32_t) value;
911 }
912
913 static int _udevflags(CMD_ARGS)
914 {
915 uint32_t cookie;
916 uint16_t flags;
917 int i;
918 static const char *dm_flag_names[] = {"DISABLE_DM_RULES",
919 "DISABLE_SUBSYSTEM_RULES",
920 "DISABLE_DISK_RULES",
921 "DISABLE_OTHER_RULES",
922 "LOW_PRIORITY",
923 "DISABLE_LIBRARY_FALLBACK",
924 "PRIMARY_SOURCE",
925 0};
926
927 if (!(cookie = _get_cookie_value(argv[1])))
928 return 0;
929
930 flags = cookie >> DM_UDEV_FLAGS_SHIFT;
931
932 for (i = 0; i < DM_UDEV_FLAGS_SHIFT; i++)
933 if (1 << i & flags) {
934 if (i < DM_UDEV_FLAGS_SHIFT / 2 && dm_flag_names[i])
935 printf("DM_UDEV_%s_FLAG='1'\n", dm_flag_names[i]);
936 else if (i < DM_UDEV_FLAGS_SHIFT / 2)
937 /*
938 * This is just a fallback. Each new DM flag
939 * should have its symbolic name assigned.
940 */
941 printf("DM_UDEV_FLAG%d='1'\n", i);
942 else
943 /*
944 * We can't assign symbolic names to subsystem
945 * flags. Their semantics vary based on the
946 * subsystem that is currently used.
947 */
948 printf("DM_SUBSYSTEM_UDEV_FLAG%d='1'\n",
949 i - DM_UDEV_FLAGS_SHIFT / 2);
950 }
951
952 return 1;
953 }
954
955 static int _udevcomplete(CMD_ARGS)
956 {
957 uint32_t cookie;
958
959 if (!(cookie = _get_cookie_value(argv[1])))
960 return 0;
961
962 /*
963 * Strip flags from the cookie and use cookie magic instead.
964 * If the cookie has non-zero prefix and the base is zero then
965 * this one carries flags to control udev rules only and it is
966 * not meant to be for notification. Return with success in this
967 * situation.
968 */
969 if (!(cookie &= ~DM_UDEV_FLAGS_MASK))
970 return 1;
971
972 cookie |= DM_COOKIE_MAGIC << DM_UDEV_FLAGS_SHIFT;
973
974 return dm_udev_complete(cookie);
975 }
976
977 #ifndef UDEV_SYNC_SUPPORT
978 static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev-sync\" to enable.";
979
980 static int _udevcreatecookie(CMD_ARGS)
981 {
982 log_error(_cmd_not_supported);
983
984 return 0;
985 }
986
987 static int _udevreleasecookie(CMD_ARGS)
988 {
989 log_error(_cmd_not_supported);
990
991 return 0;
992 }
993
994 static int _udevcomplete_all(CMD_ARGS)
995 {
996 log_error(_cmd_not_supported);
997
998 return 0;
999 }
1000
1001 static int _udevcookies(CMD_ARGS)
1002 {
1003 log_error(_cmd_not_supported);
1004
1005 return 0;
1006 }
1007
1008 #else /* UDEV_SYNC_SUPPORT */
1009 static int _set_up_udev_support(const char *dev_dir)
1010 {
1011 int dirs_diff;
1012 const char *env;
1013 size_t len = strlen(dev_dir), udev_dir_len = strlen(DM_UDEV_DEV_DIR);
1014
1015 if (_switches[NOUDEVSYNC_ARG])
1016 dm_udev_set_sync_support(0);
1017
1018 if (!_udev_cookie) {
1019 env = getenv(DM_UDEV_COOKIE_ENV_VAR_NAME);
1020 if (env && *env && (_udev_cookie = _get_cookie_value(env)))
1021 log_debug("Using udev transaction 0x%08" PRIX32
1022 " defined by %s environment variable.",
1023 _udev_cookie,
1024 DM_UDEV_COOKIE_ENV_VAR_NAME);
1025 }
1026 else if (_switches[UDEVCOOKIE_ARG])
1027 log_debug("Using udev transaction 0x%08" PRIX32
1028 " defined by --udevcookie option.",
1029 _udev_cookie);
1030
1031 /*
1032 * Normally, there's always a fallback action by libdevmapper if udev
1033 * has not done its job correctly, e.g. the nodes were not created.
1034 * If using udev transactions by specifying existing cookie value,
1035 * we need to disable node creation by libdevmapper completely,
1036 * disabling any fallback actions, since any synchronisation happens
1037 * at the end of the transaction only. We need to do this to prevent
1038 * races between udev and libdevmapper but only in case udev "dev path"
1039 * is the same as "dev path" used by libdevmapper.
1040 */
1041
1042
1043 /*
1044 * DM_UDEV_DEV_DIR always has '/' at its end.
1045 * If the dev_dir does not have it, be sure
1046 * to make the right comparison without the '/' char!
1047 */
1048 if (dev_dir[len - 1] != '/')
1049 udev_dir_len--;
1050
1051 dirs_diff = udev_dir_len != len ||
1052 strncmp(DM_UDEV_DEV_DIR, dev_dir, len);
1053 _udev_only = !dirs_diff && (_udev_cookie || !_switches[VERIFYUDEV_ARG]);
1054
1055 if (dirs_diff) {
1056 log_debug("The path %s used for creating device nodes that is "
1057 "set via DM_DEV_DIR environment variable differs from "
1058 "the path %s that is used by udev. All warnings "
1059 "about udev not working correctly while processing "
1060 "particular nodes will be suppressed. These nodes "
1061 "and symlinks will be managed in each directory "
1062 "separately.", dev_dir, DM_UDEV_DEV_DIR);
1063 dm_udev_set_checking(0);
1064 }
1065
1066 return 1;
1067 }
1068
1069 static int _udevcreatecookie(CMD_ARGS)
1070 {
1071 uint32_t cookie;
1072
1073 if (!dm_udev_create_cookie(&cookie))
1074 return 0;
1075
1076 if (cookie)
1077 printf("0x%08" PRIX32 "\n", cookie);
1078
1079 return 1;
1080 }
1081
1082 static int _udevreleasecookie(CMD_ARGS)
1083 {
1084 if (argv[1] && !(_udev_cookie = _get_cookie_value(argv[1])))
1085 return 0;
1086
1087 if (!_udev_cookie) {
1088 log_error("No udev transaction cookie given.");
1089 return 0;
1090 }
1091
1092 return dm_udev_wait(_udev_cookie);
1093 }
1094
1095 __attribute__((format(printf, 1, 2)))
1096 static char _yes_no_prompt(const char *prompt, ...)
1097 {
1098 int c = 0, ret = 0;
1099 va_list ap;
1100
1101 do {
1102 if (c == '\n' || !c) {
1103 va_start(ap, prompt);
1104 vprintf(prompt, ap);
1105 va_end(ap);
1106 }
1107
1108 if ((c = getchar()) == EOF) {
1109 ret = 'n';
1110 break;
1111 }
1112
1113 c = tolower(c);
1114 if ((c == 'y') || (c == 'n'))
1115 ret = c;
1116 } while (!ret || c != '\n');
1117
1118 if (c != '\n')
1119 printf("\n");
1120
1121 return ret;
1122 }
1123
1124 static int _udevcomplete_all(CMD_ARGS)
1125 {
1126 int max_id, id, sid;
1127 struct seminfo sinfo;
1128 struct semid_ds sdata;
1129 int counter = 0;
1130 int skipped = 0;
1131 unsigned age = 0;
1132 time_t t;
1133
1134 if (argc == 2 && (sscanf(argv[1], "%i", &age) != 1)) {
1135 log_error("Failed to read age_in_minutes parameter.");
1136 return 0;
1137 }
1138
1139 if (!_switches[YES_ARG]) {
1140 log_warn("This operation will destroy all semaphores %s%.0d%swith keys "
1141 "that have a prefix %" PRIu16 " (0x%" PRIx16 ").",
1142 age ? "older than " : "", age, age ? " minutes " : "",
1143 DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
1144
1145 if (_yes_no_prompt("Do you really want to continue? [y/n]: ") == 'n') {
1146 log_print("Semaphores with keys prefixed by %" PRIu16
1147 " (0x%" PRIx16 ") NOT destroyed.",
1148 DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
1149 return 1;
1150 }
1151 }
1152
1153 if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) {
1154 log_sys_error("semctl", "SEM_INFO");
1155 return 0;
1156 }
1157
1158 for (id = 0; id <= max_id; id++) {
1159 if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0)
1160 continue;
1161
1162 if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) {
1163 t = time(NULL);
1164
1165 if (sdata.sem_ctime + age * 60 > t ||
1166 sdata.sem_otime + age * 60 > t) {
1167 skipped++;
1168 continue;
1169 }
1170 if (semctl(sid, 0, IPC_RMID, 0) < 0) {
1171 log_error("Could not cleanup notification semaphore "
1172 "with semid %d and cookie value "
1173 "%" PRIu32 " (0x%" PRIx32 ")", sid,
1174 sdata.sem_perm.__key, sdata.sem_perm.__key);
1175 continue;
1176 }
1177
1178 counter++;
1179 }
1180 }
1181
1182 log_print("%d semaphores with keys prefixed by "
1183 "%" PRIu16 " (0x%" PRIx16 ") destroyed. %d skipped.",
1184 counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC, skipped);
1185
1186 return 1;
1187 }
1188
1189 static int _udevcookies(CMD_ARGS)
1190 {
1191 int max_id, id, sid;
1192 struct seminfo sinfo;
1193 struct semid_ds sdata;
1194 int val;
1195 char otime_str[26], ctime_str[26];
1196 char *otimes, *ctimes;
1197
1198 if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) {
1199 log_sys_error("sem_ctl", "SEM_INFO");
1200 return 0;
1201 }
1202
1203 printf("Cookie Semid Value Last semop time Last change time\n");
1204
1205 for (id = 0; id <= max_id; id++) {
1206 if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0)
1207 continue;
1208
1209 if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) {
1210 if ((val = semctl(sid, 0, GETVAL)) < 0) {
1211 log_error("semid %d: sem_ctl failed for "
1212 "cookie 0x%" PRIx32 ": %s",
1213 sid, sdata.sem_perm.__key,
1214 strerror(errno));
1215 continue;
1216 }
1217
1218 if ((otimes = ctime_r((const time_t *) &sdata.sem_otime, (char *)&otime_str)))
1219 otime_str[strlen(otimes)-1] = '\0';
1220 if ((ctimes = ctime_r((const time_t *) &sdata.sem_ctime, (char *)&ctime_str)))
1221 ctime_str[strlen(ctimes)-1] = '\0';
1222
1223 printf("0x%-10x %-10d %-10d %s %s\n", sdata.sem_perm.__key,
1224 sid, val, otimes ? : "unknown",
1225 ctimes? : "unknown");
1226 }
1227 }
1228
1229 return 1;
1230 }
1231 #endif /* UDEV_SYNC_SUPPORT */
1232
1233 static int _version(CMD_ARGS)
1234 {
1235 char version[80];
1236
1237 if (dm_get_library_version(version, sizeof(version)))
1238 printf("Library version: %s\n", version);
1239
1240 if (!dm_driver_version(version, sizeof(version)))
1241 return 0;
1242
1243 printf("Driver version: %s\n", version);
1244
1245 return 1;
1246 }
1247
1248 static int _simple(int task, const char *name, uint32_t event_nr, int display)
1249 {
1250 uint32_t cookie = 0;
1251 uint16_t udev_flags = 0;
1252 int udev_wait_flag = task == DM_DEVICE_RESUME ||
1253 task == DM_DEVICE_REMOVE;
1254 int r = 0;
1255
1256 struct dm_task *dmt;
1257
1258 if (!(dmt = dm_task_create(task)))
1259 return 0;
1260
1261 if (!_set_task_device(dmt, name, 0))
1262 goto out;
1263
1264 if (event_nr && !dm_task_set_event_nr(dmt, event_nr))
1265 goto out;
1266
1267 if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt))
1268 goto out;
1269
1270 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1271 goto out;
1272
1273 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1274 goto out;
1275
1276 if (_switches[NOLOCKFS_ARG] && !dm_task_skip_lockfs(dmt))
1277 goto out;
1278
1279 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
1280 goto out;
1281
1282 /* FIXME: needs to coperate with udev */
1283 if (!_set_task_add_node(dmt))
1284 goto out;
1285
1286 if (_switches[READAHEAD_ARG] &&
1287 !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG],
1288 _read_ahead_flags))
1289 goto out;
1290
1291 if (_switches[NOUDEVRULES_ARG])
1292 udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
1293 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
1294
1295 if (_udev_cookie)
1296 cookie = _udev_cookie;
1297
1298 if (_udev_only)
1299 udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
1300
1301 if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags))
1302 goto out;
1303
1304 if (_switches[RETRY_ARG] && task == DM_DEVICE_REMOVE)
1305 dm_task_retry_remove(dmt);
1306
1307 r = dm_task_run(dmt);
1308
1309 out:
1310 if (!_udev_cookie && udev_wait_flag)
1311 (void) dm_udev_wait(cookie);
1312
1313 if (r && display && _switches[VERBOSE_ARG])
1314 r = _display_info(dmt);
1315
1316 dm_task_destroy(dmt);
1317
1318 return r;
1319 }
1320
1321 static int _suspend(CMD_ARGS)
1322 {
1323 return _simple(DM_DEVICE_SUSPEND, argc > 1 ? argv[1] : NULL, 0, 1);
1324 }
1325
1326 static int _resume(CMD_ARGS)
1327 {
1328 return _simple(DM_DEVICE_RESUME, argc > 1 ? argv[1] : NULL, 0, 1);
1329 }
1330
1331 static int _clear(CMD_ARGS)
1332 {
1333 return _simple(DM_DEVICE_CLEAR, argc > 1 ? argv[1] : NULL, 0, 1);
1334 }
1335
1336 static int _wait(CMD_ARGS)
1337 {
1338 const char *name = NULL;
1339
1340 if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
1341 if (argc == 1) {
1342 err("No device specified.");
1343 return 0;
1344 }
1345 name = argv[1];
1346 argc--, argv++;
1347 }
1348
1349 return _simple(DM_DEVICE_WAITEVENT, name,
1350 (argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1);
1351 }
1352
1353 static int _process_all(const struct command *cmd, int argc, char **argv, int silent,
1354 int (*fn) (CMD_ARGS))
1355 {
1356 int r = 1;
1357 struct dm_names *names;
1358 unsigned next = 0;
1359
1360 struct dm_task *dmt;
1361
1362 if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
1363 return 0;
1364
1365 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
1366 goto out;
1367
1368 if (!dm_task_run(dmt)) {
1369 r = 0;
1370 goto out;
1371 }
1372
1373 if (!(names = dm_task_get_names(dmt))) {
1374 r = 0;
1375 goto out;
1376 }
1377
1378 if (!names->dev) {
1379 if (!silent)
1380 printf("No devices found\n");
1381 goto out;
1382 }
1383
1384 do {
1385 names = (struct dm_names *)((char *) names + next);
1386 if (!fn(cmd, argc, argv, names, 1))
1387 r = 0;
1388 next = names->next;
1389 } while (next);
1390
1391 out:
1392 dm_task_destroy(dmt);
1393 return r;
1394 }
1395
1396 static uint64_t _get_device_size(const char *name)
1397 {
1398 uint64_t start, length, size = UINT64_C(0);
1399 struct dm_info info;
1400 char *target_type, *params;
1401 struct dm_task *dmt;
1402 void *next = NULL;
1403
1404 if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
1405 return 0;
1406
1407 if (!_set_task_device(dmt, name, 0))
1408 goto out;
1409
1410 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1411 goto out;
1412
1413 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1414 goto out;
1415
1416 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
1417 goto out;
1418
1419 if (!dm_task_run(dmt))
1420 goto out;
1421
1422 if (!dm_task_get_info(dmt, &info) || !info.exists)
1423 goto out;
1424
1425 do {
1426 next = dm_get_next_target(dmt, next, &start, &length,
1427 &target_type, &params);
1428 size += length;
1429 } while (next);
1430
1431 out:
1432 dm_task_destroy(dmt);
1433 return size;
1434 }
1435
1436 static int _error_device(CMD_ARGS)
1437 {
1438 struct dm_task *dmt;
1439 const char *name;
1440 uint64_t size;
1441 int r = 0;
1442
1443 name = names ? names->name : argv[1];
1444
1445 size = _get_device_size(name);
1446
1447 if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
1448 return 0;
1449
1450 if (!_set_task_device(dmt, name, 0))
1451 goto error;
1452
1453 if (!dm_task_add_target(dmt, UINT64_C(0), size, "error", ""))
1454 goto error;
1455
1456 if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
1457 goto error;
1458
1459 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1460 goto error;
1461
1462 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1463 goto error;
1464
1465 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
1466 goto error;
1467
1468 if (!dm_task_run(dmt))
1469 goto error;
1470
1471 if (!_simple(DM_DEVICE_RESUME, name, 0, 0)) {
1472 _simple(DM_DEVICE_CLEAR, name, 0, 0);
1473 goto error;
1474 }
1475
1476 r = 1;
1477
1478 error:
1479 dm_task_destroy(dmt);
1480 return r;
1481 }
1482
1483 static int _remove(CMD_ARGS)
1484 {
1485 if (_switches[FORCE_ARG] && argc > 1)
1486 (void) _error_device(cmd, argc, argv, NULL, 0);
1487
1488 return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0);
1489 }
1490
1491 static int _count_devices(CMD_ARGS)
1492 {
1493 _num_devices++;
1494
1495 return 1;
1496 }
1497
1498 static int _remove_all(CMD_ARGS)
1499 {
1500 int r;
1501
1502 /* Remove all closed devices */
1503 r = _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL);
1504
1505 if (!_switches[FORCE_ARG])
1506 return r;
1507
1508 _num_devices = 0;
1509 r |= _process_all(cmd, argc, argv, 1, _count_devices);
1510
1511 /* No devices left? */
1512 if (!_num_devices)
1513 return r;
1514
1515 r |= _process_all(cmd, argc, argv, 1, _error_device);
1516 r |= _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL);
1517
1518 _num_devices = 0;
1519 r |= _process_all(cmd, argc, argv, 1, _count_devices);
1520 if (!_num_devices)
1521 return r;
1522
1523 fprintf(stderr, "Unable to remove %d device(s).\n", _num_devices);
1524
1525 return r;
1526 }
1527
1528 static void _display_dev(struct dm_task *dmt, const char *name)
1529 {
1530 struct dm_info info;
1531
1532 if (dm_task_get_info(dmt, &info))
1533 printf("%s\t(%u, %u)\n", name, info.major, info.minor);
1534 }
1535
1536 static int _mknodes(CMD_ARGS)
1537 {
1538 return dm_mknodes(argc > 1 ? argv[1] : NULL);
1539 }
1540
1541 static int _exec_command(const char *name)
1542 {
1543 int n;
1544 static char path[PATH_MAX];
1545 static char *args[ARGS_MAX + 1];
1546 static int argc = 0;
1547 char *c;
1548 pid_t pid;
1549
1550 if (argc < 0)
1551 return 0;
1552
1553 if (!dm_mknodes(name))
1554 return 0;
1555
1556 n = snprintf(path, sizeof(path), "%s/%s", dm_dir(), name);
1557 if (n < 0 || n > (int) sizeof(path) - 1)
1558 return 0;
1559
1560 if (!argc) {
1561 c = _command;
1562 while (argc < ARGS_MAX) {
1563 while (*c && isspace(*c))
1564 c++;
1565 if (!*c)
1566 break;
1567 args[argc++] = c;
1568 while (*c && !isspace(*c))
1569 c++;
1570 if (*c)
1571 *c++ = '\0';
1572 }
1573
1574 if (!argc) {
1575 argc = -1;
1576 return 0;
1577 }
1578
1579 if (argc == ARGS_MAX) {
1580 err("Too many args to --exec\n");
1581 argc = -1;
1582 return 0;
1583 }
1584
1585 args[argc++] = path;
1586 args[argc] = NULL;
1587 }
1588
1589 if (!(pid = fork())) {
1590 execvp(args[0], args);
1591 _exit(127);
1592 } else if (pid < (pid_t) 0)
1593 return 0;
1594
1595 TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
1596
1597 return 1;
1598 }
1599
1600 static int _status(CMD_ARGS)
1601 {
1602 int r = 0;
1603 struct dm_task *dmt;
1604 void *next = NULL;
1605 uint64_t start, length;
1606 char *target_type = NULL;
1607 char *params, *c;
1608 int cmdno;
1609 const char *name = NULL;
1610 int matched = 0;
1611 int ls_only = 0;
1612 struct dm_info info;
1613
1614 if (names)
1615 name = names->name;
1616 else {
1617 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1618 return _process_all(cmd, argc, argv, 0, _status);
1619 name = argv[1];
1620 }
1621
1622 if (!strcmp(cmd->name, "table"))
1623 cmdno = DM_DEVICE_TABLE;
1624 else
1625 cmdno = DM_DEVICE_STATUS;
1626
1627 if (!strcmp(cmd->name, "ls"))
1628 ls_only = 1;
1629
1630 if (!(dmt = dm_task_create(cmdno)))
1631 return 0;
1632
1633 if (!_set_task_device(dmt, name, 0))
1634 goto out;
1635
1636 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1637 goto out;
1638
1639 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1640 goto out;
1641
1642 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
1643 goto out;
1644
1645 if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt))
1646 goto out;
1647
1648 if (!dm_task_run(dmt))
1649 goto out;
1650
1651 if (!dm_task_get_info(dmt, &info) || !info.exists)
1652 goto out;
1653
1654 if (!name)
1655 name = dm_task_get_name(dmt);
1656
1657 /* Fetch targets and print 'em */
1658 do {
1659 next = dm_get_next_target(dmt, next, &start, &length,
1660 &target_type, &params);
1661 /* Skip if target type doesn't match */
1662 if (_switches[TARGET_ARG] &&
1663 (!target_type || strcmp(target_type, _target)))
1664 continue;
1665 if (ls_only) {
1666 if (!_switches[EXEC_ARG] || !_command ||
1667 _switches[VERBOSE_ARG])
1668 _display_dev(dmt, name);
1669 next = NULL;
1670 } else if (!_switches[EXEC_ARG] || !_command ||
1671 _switches[VERBOSE_ARG]) {
1672 if (!matched && _switches[VERBOSE_ARG])
1673 _display_info(dmt);
1674 if (multiple_devices && !_switches[VERBOSE_ARG])
1675 printf("%s: ", name);
1676 if (target_type) {
1677 /* Suppress encryption key */
1678 if (!_switches[SHOWKEYS_ARG] &&
1679 cmdno == DM_DEVICE_TABLE &&
1680 !strcmp(target_type, "crypt")) {
1681 c = params;
1682 while (*c && *c != ' ')
1683 c++;
1684 if (*c)
1685 c++;
1686 while (*c && *c != ' ')
1687 *c++ = '0';
1688 }
1689 printf("%" PRIu64 " %" PRIu64 " %s %s",
1690 start, length, target_type, params);
1691 }
1692 printf("\n");
1693 }
1694 matched = 1;
1695 } while (next);
1696
1697 if (multiple_devices && _switches[VERBOSE_ARG] && matched && !ls_only)
1698 printf("\n");
1699
1700 if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name))
1701 goto out;
1702
1703 r = 1;
1704
1705 out:
1706 dm_task_destroy(dmt);
1707 return r;
1708 }
1709
1710 /* Show target names and their version numbers */
1711 static int _targets(CMD_ARGS)
1712 {
1713 int r = 0;
1714 struct dm_task *dmt;
1715 struct dm_versions *target;
1716 struct dm_versions *last_target;
1717
1718 if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
1719 return 0;
1720
1721 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
1722 goto out;
1723
1724 if (!dm_task_run(dmt))
1725 goto out;
1726
1727 target = dm_task_get_versions(dmt);
1728
1729 /* Fetch targets and print 'em */
1730 do {
1731 last_target = target;
1732
1733 printf("%-16s v%d.%d.%d\n", target->name, target->version[0],
1734 target->version[1], target->version[2]);
1735
1736 target = (struct dm_versions *)((char *) target + target->next);
1737 } while (last_target != target);
1738
1739 r = 1;
1740
1741 out:
1742 dm_task_destroy(dmt);
1743 return r;
1744 }
1745
1746 static int _info(CMD_ARGS)
1747 {
1748 int r = 0;
1749
1750 struct dm_task *dmt;
1751 char *name = NULL;
1752
1753 if (names)
1754 name = names->name;
1755 else {
1756 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1757 return _process_all(cmd, argc, argv, 0, _info);
1758 name = argv[1];
1759 }
1760
1761 if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
1762 return 0;
1763
1764 if (!_set_task_device(dmt, name, 0))
1765 goto out;
1766
1767 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1768 goto out;
1769
1770 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1771 goto out;
1772
1773 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
1774 goto out;
1775
1776 if (!dm_task_run(dmt))
1777 goto out;
1778
1779 r = _display_info(dmt);
1780
1781 out:
1782 dm_task_destroy(dmt);
1783 return r;
1784 }
1785
1786 static int _deps(CMD_ARGS)
1787 {
1788 int r = 0;
1789 uint32_t i;
1790 struct dm_deps *deps;
1791 struct dm_task *dmt;
1792 struct dm_info info;
1793 char *name = NULL;
1794 char dev_name[PATH_MAX];
1795 int major, minor;
1796
1797 if (names)
1798 name = names->name;
1799 else {
1800 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1801 return _process_all(cmd, argc, argv, 0, _deps);
1802 name = argv[1];
1803 }
1804
1805 if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
1806 return 0;
1807
1808 if (!_set_task_device(dmt, name, 0))
1809 goto out;
1810
1811 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1812 goto out;
1813
1814 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1815 goto out;
1816
1817 if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
1818 goto out;
1819
1820 if (!dm_task_run(dmt))
1821 goto out;
1822
1823 if (!dm_task_get_info(dmt, &info))
1824 goto out;
1825
1826 if (!(deps = dm_task_get_deps(dmt)))
1827 goto out;
1828
1829 if (!info.exists) {
1830 printf("Device does not exist.\n");
1831 r = 1;
1832 goto out;
1833 }
1834
1835 if (_switches[VERBOSE_ARG])
1836 _display_info(dmt);
1837
1838 if (multiple_devices && !_switches[VERBOSE_ARG])
1839 printf("%s: ", name);
1840 printf("%d dependencies\t:", deps->count);
1841
1842 for (i = 0; i < deps->count; i++) {
1843 major = (int) MAJOR(deps->device[i]);
1844 minor = (int) MINOR(deps->device[i]);
1845
1846 if ((_dev_name_type == DN_BLK || _dev_name_type == DN_MAP) &&
1847 dm_device_get_name(major, minor, _dev_name_type == DN_BLK,
1848 dev_name, PATH_MAX))
1849 printf(" (%s)", dev_name);
1850 else
1851 printf(" (%d, %d)", major, minor);
1852 }
1853 printf("\n");
1854
1855 if (multiple_devices && _switches[VERBOSE_ARG])
1856 printf("\n");
1857
1858 r = 1;
1859
1860 out:
1861 dm_task_destroy(dmt);
1862 return r;
1863 }
1864
1865 static int _display_name(CMD_ARGS)
1866 {
1867 char dev_name[PATH_MAX];
1868
1869 if (!names)
1870 return 1;
1871
1872 if ((_dev_name_type == DN_BLK || _dev_name_type == DN_MAP) &&
1873 dm_device_get_name((int) MAJOR(names->dev), (int) MINOR(names->dev),
1874 _dev_name_type == DN_BLK, dev_name, PATH_MAX))
1875 printf("%s\t(%s)\n", names->name, dev_name);
1876 else
1877 printf("%s\t(%d:%d)\n", names->name,
1878 (int) MAJOR(names->dev),
1879 (int) MINOR(names->dev));
1880
1881 return 1;
1882 }
1883
1884 /*
1885 * Tree drawing code
1886 */
1887
1888 enum {
1889 TR_DEVICE=0, /* display device major:minor number */
1890 TR_BLKDEVNAME, /* display device kernel name */
1891 TR_TABLE,
1892 TR_STATUS,
1893 TR_ACTIVE,
1894 TR_RW,
1895 TR_OPENCOUNT,
1896 TR_UUID,
1897 TR_COMPACT,
1898 TR_TRUNCATE,
1899 TR_BOTTOMUP,
1900 NUM_TREEMODE,
1901 };
1902
1903 static int _tree_switches[NUM_TREEMODE];
1904
1905 #define TR_PRINT_ATTRIBUTE ( _tree_switches[TR_ACTIVE] || \
1906 _tree_switches[TR_RW] || \
1907 _tree_switches[TR_OPENCOUNT] || \
1908 _tree_switches[TR_UUID] )
1909
1910 #define TR_PRINT_TARGETS ( _tree_switches[TR_TABLE] || \
1911 _tree_switches[TR_STATUS] )
1912
1913 /* Compact - fewer newlines */
1914 #define TR_PRINT_COMPACT (_tree_switches[TR_COMPACT] && \
1915 !TR_PRINT_ATTRIBUTE && \
1916 !TR_PRINT_TARGETS)
1917
1918 /* FIXME Get rid of this */
1919 #define MAX_DEPTH 100
1920
1921 /* Drawing character definition from pstree */
1922 /* [pstree comment] UTF-8 defines by Johan Myreen, updated by Ben Winslow */
1923 #define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */
1924 #define UTF_VR "\342\224\234" /* U+251C, Vertical and right */
1925 #define UTF_H "\342\224\200" /* U+2500, Horizontal */
1926 #define UTF_UR "\342\224\224" /* U+2514, Up and right */
1927 #define UTF_HD "\342\224\254" /* U+252C, Horizontal and down */
1928
1929 #define VT_BEG "\033(0\017" /* use graphic chars */
1930 #define VT_END "\033(B" /* back to normal char set */
1931 #define VT_V "x" /* see UTF definitions above */
1932 #define VT_VR "t"
1933 #define VT_H "q"
1934 #define VT_UR "m"
1935 #define VT_HD "w"
1936
1937 static struct {
1938 const char *empty_2; /* */
1939 const char *branch_2; /* |- */
1940 const char *vert_2; /* | */
1941 const char *last_2; /* `- */
1942 const char *single_3; /* --- */
1943 const char *first_3; /* -+- */
1944 }
1945 _tsym_ascii = {
1946 " ",
1947 "|-",
1948 "| ",
1949 "`-",
1950 "---",
1951 "-+-"
1952 },
1953 _tsym_utf = {
1954 " ",
1955 UTF_VR UTF_H,
1956 UTF_V " ",
1957 UTF_UR UTF_H,
1958 UTF_H UTF_H UTF_H,
1959 UTF_H UTF_HD UTF_H
1960 },
1961 _tsym_vt100 = {
1962 " ",
1963 VT_BEG VT_VR VT_H VT_END,
1964 VT_BEG VT_V VT_END " ",
1965 VT_BEG VT_UR VT_H VT_END,
1966 VT_BEG VT_H VT_H VT_H VT_END,
1967 VT_BEG VT_H VT_HD VT_H VT_END
1968 },
1969 *_tsym = &_tsym_ascii;
1970
1971 /*
1972 * Tree drawing functions.
1973 */
1974 /* FIXME Get rid of these statics - use dynamic struct */
1975 /* FIXME Explain what these vars are for */
1976 static int _tree_width[MAX_DEPTH], _tree_more[MAX_DEPTH];
1977 static int _termwidth = 80; /* Maximum output width */
1978 static int _cur_x = 1; /* Current horizontal output position */
1979 static char _last_char = 0;
1980
1981 static void _out_char(const unsigned c)
1982 {
1983 /* Only first UTF-8 char counts */
1984 _cur_x += ((c & 0xc0) != 0x80);
1985
1986 if (!_tree_switches[TR_TRUNCATE]) {
1987 putchar((int) c);
1988 return;
1989 }
1990
1991 /* Truncation? */
1992 if (_cur_x <= _termwidth)
1993 putchar((int) c);
1994
1995 if (_cur_x == _termwidth + 1 && ((c & 0xc0) != 0x80)) {
1996 if (_last_char || (c & 0x80)) {
1997 putchar('.');
1998 putchar('.');
1999 putchar('.');
2000 } else {
2001 _last_char = c;
2002 _cur_x--;
2003 }
2004 }
2005 }
2006
2007 static void _out_string(const char *str)
2008 {
2009 while (*str)
2010 _out_char((unsigned char) *str++);
2011 }
2012
2013 /* non-negative integers only */
2014 static unsigned _out_int(unsigned num)
2015 {
2016 unsigned digits = 0;
2017 unsigned divi;
2018
2019 if (!num) {
2020 _out_char('0');
2021 return 1;
2022 }
2023
2024 /* non zero case */
2025 for (divi = 1; num / divi; divi *= 10)
2026 digits++;
2027
2028 for (divi /= 10; divi; divi /= 10)
2029 _out_char('0' + (num / divi) % 10);
2030
2031 return digits;
2032 }
2033
2034 static void _out_newline(void)
2035 {
2036 if (_last_char && _cur_x == _termwidth)
2037 putchar(_last_char);
2038 _last_char = 0;
2039 putchar('\n');
2040 _cur_x = 1;
2041 }
2042
2043 static void _out_prefix(unsigned depth)
2044 {
2045 unsigned x, d;
2046
2047 for (d = 0; d < depth; d++) {
2048 for (x = _tree_width[d] + 1; x > 0; x--)
2049 _out_char(' ');
2050
2051 _out_string(d == depth - 1 ?
2052 !_tree_more[depth] ? _tsym->last_2 : _tsym->branch_2
2053 : _tree_more[d + 1] ?
2054 _tsym->vert_2 : _tsym->empty_2);
2055 }
2056 }
2057
2058 /*
2059 * Display tree
2060 */
2061 static void _display_tree_attributes(struct dm_tree_node *node)
2062 {
2063 int attr = 0;
2064 const char *uuid;
2065 const struct dm_info *info;
2066
2067 uuid = dm_tree_node_get_uuid(node);
2068 info = dm_tree_node_get_info(node);
2069
2070 if (!info->exists)
2071 return;
2072
2073 if (_tree_switches[TR_ACTIVE]) {
2074 _out_string(attr++ ? ", " : " [");
2075 _out_string(info->suspended ? "SUSPENDED" : "ACTIVE");
2076 }
2077
2078 if (_tree_switches[TR_RW]) {
2079 _out_string(attr++ ? ", " : " [");
2080 _out_string(info->read_only ? "RO" : "RW");
2081 }
2082
2083 if (_tree_switches[TR_OPENCOUNT]) {
2084 _out_string(attr++ ? ", " : " [");
2085 (void) _out_int((unsigned) info->open_count);
2086 }
2087
2088 if (_tree_switches[TR_UUID]) {
2089 _out_string(attr++ ? ", " : " [");
2090 _out_string(uuid && *uuid ? uuid : "");
2091 }
2092
2093 if (attr)
2094 _out_char(']');
2095 }
2096
2097 /* FIXME Display table or status line. (Disallow both?) */
2098 static void _display_tree_targets(struct dm_tree_node *node, unsigned depth)
2099 {
2100 }
2101
2102 static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
2103 unsigned first_child __attribute__((unused)),
2104 unsigned last_child, unsigned has_children)
2105 {
2106 int offset;
2107 const char *name;
2108 const struct dm_info *info;
2109 int first_on_line = 0;
2110 char dev_name[PATH_MAX];
2111
2112 /* Sub-tree for targets has 2 more depth */
2113 if (depth + 2 > MAX_DEPTH)
2114 return;
2115
2116 name = dm_tree_node_get_name(node);
2117
2118 if ((!name || !*name) &&
2119 (!_tree_switches[TR_DEVICE] && !_tree_switches[TR_BLKDEVNAME]))
2120 return;
2121
2122 /* Indicate whether there are more nodes at this depth */
2123 _tree_more[depth] = !last_child;
2124 _tree_width[depth] = 0;
2125
2126 if (_cur_x == 1)
2127 first_on_line = 1;
2128
2129 if (!TR_PRINT_COMPACT || first_on_line)
2130 _out_prefix(depth);
2131
2132 /* Remember the starting point for compact */
2133 offset = _cur_x;
2134
2135 if (TR_PRINT_COMPACT && !first_on_line)
2136 _out_string(_tree_more[depth] ? _tsym->first_3 : _tsym->single_3);
2137
2138 /* display node */
2139 if (name)
2140 _out_string(name);
2141
2142 info = dm_tree_node_get_info(node);
2143
2144 if (_tree_switches[TR_BLKDEVNAME] &&
2145 dm_device_get_name(info->major, info->minor, 1, dev_name, PATH_MAX)) {
2146 _out_string(name ? " <" : "<");
2147 _out_string(dev_name);
2148 _out_char('>');
2149 }
2150
2151 if (_tree_switches[TR_DEVICE]) {
2152 _out_string(name ? " (" : "(");
2153 (void) _out_int(info->major);
2154 _out_char(':');
2155 (void) _out_int(info->minor);
2156 _out_char(')');
2157 }
2158
2159 /* display additional info */
2160 if (TR_PRINT_ATTRIBUTE)
2161 _display_tree_attributes(node);
2162
2163 if (TR_PRINT_COMPACT)
2164 _tree_width[depth] = _cur_x - offset;
2165
2166 if (!TR_PRINT_COMPACT || !has_children)
2167 _out_newline();
2168
2169 if (TR_PRINT_TARGETS) {
2170 _tree_more[depth + 1] = has_children;
2171 _display_tree_targets(node, depth + 2);
2172 }
2173 }
2174
2175 /*
2176 * Walk the dependency tree
2177 */
2178 static void _display_tree_walk_children(struct dm_tree_node *node,
2179 unsigned depth)
2180 {
2181 struct dm_tree_node *child, *next_child;
2182 void *handle = NULL;
2183 uint32_t inverted = _tree_switches[TR_BOTTOMUP];
2184 unsigned first_child = 1;
2185 unsigned has_children;
2186
2187 next_child = dm_tree_next_child(&handle, node, inverted);
2188
2189 while ((child = next_child)) {
2190 next_child = dm_tree_next_child(&handle, node, inverted);
2191 has_children =
2192 dm_tree_node_num_children(child, inverted) ? 1 : 0;
2193
2194 _display_tree_node(child, depth, first_child,
2195 next_child ? 0U : 1U, has_children);
2196
2197 if (has_children)
2198 _display_tree_walk_children(child, depth + 1);
2199
2200 first_child = 0;
2201 }
2202 }
2203
2204 static int _add_dep(CMD_ARGS)
2205 {
2206 if (names &&
2207 !dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev)))
2208 return 0;
2209
2210 return 1;
2211 }
2212
2213 /*
2214 * Create and walk dependency tree
2215 */
2216 static int _build_whole_deptree(const struct command *cmd)
2217 {
2218 if (_dtree)
2219 return 1;
2220
2221 if (!(_dtree = dm_tree_create()))
2222 return 0;
2223
2224 if (!_process_all(cmd, 0, NULL, 0, _add_dep))
2225 return 0;
2226
2227 return 1;
2228 }
2229
2230 static int _display_tree(CMD_ARGS)
2231 {
2232 if (!_build_whole_deptree(cmd))
2233 return 0;
2234
2235 _display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
2236
2237 return 1;
2238 }
2239
2240 /*
2241 * Report device information
2242 */
2243
2244 /* dm specific display functions */
2245
2246 static int _int32_disp(struct dm_report *rh,
2247 struct dm_pool *mem __attribute__((unused)),
2248 struct dm_report_field *field, const void *data,
2249 void *private __attribute__((unused)))
2250 {
2251 const int32_t value = *(const int32_t *)data;
2252
2253 return dm_report_field_int32(rh, field, &value);
2254 }
2255
2256 static int _uint32_disp(struct dm_report *rh,
2257 struct dm_pool *mem __attribute__((unused)),
2258 struct dm_report_field *field, const void *data,
2259 void *private __attribute__((unused)))
2260 {
2261 const uint32_t value = *(const int32_t *)data;
2262
2263 return dm_report_field_uint32(rh, field, &value);
2264 }
2265
2266 static int _dm_name_disp(struct dm_report *rh,
2267 struct dm_pool *mem __attribute__((unused)),
2268 struct dm_report_field *field, const void *data,
2269 void *private __attribute__((unused)))
2270 {
2271 const char *name = dm_task_get_name((const struct dm_task *) data);
2272
2273 return dm_report_field_string(rh, field, &name);
2274 }
2275
2276 static int _dm_mangled_name_disp(struct dm_report *rh,
2277 struct dm_pool *mem __attribute__((unused)),
2278 struct dm_report_field *field, const void *data,
2279 void *private __attribute__((unused)))
2280 {
2281 char *name;
2282 int r = 0;
2283
2284 if ((name = dm_task_get_name_mangled((const struct dm_task *) data))) {
2285 r = dm_report_field_string(rh, field, (const char **) &name);
2286 dm_free(name);
2287 }
2288
2289 return r;
2290 }
2291
2292 static int _dm_unmangled_name_disp(struct dm_report *rh,
2293 struct dm_pool *mem __attribute__((unused)),
2294 struct dm_report_field *field, const void *data,
2295 void *private __attribute__((unused)))
2296 {
2297 char *name;
2298 int r = 0;
2299
2300 if ((name = dm_task_get_name_unmangled((const struct dm_task *) data))) {
2301 r = dm_report_field_string(rh, field, (const char **) &name);
2302 dm_free(name);
2303 }
2304
2305 return r;
2306 }
2307
2308 static int _dm_uuid_disp(struct dm_report *rh,
2309 struct dm_pool *mem __attribute__((unused)),
2310 struct dm_report_field *field,
2311 const void *data, void *private __attribute__((unused)))
2312 {
2313 const char *uuid = dm_task_get_uuid((const struct dm_task *) data);
2314
2315 if (!uuid || !*uuid)
2316 uuid = "";
2317
2318 return dm_report_field_string(rh, field, &uuid);
2319 }
2320
2321 static int _dm_read_ahead_disp(struct dm_report *rh,
2322 struct dm_pool *mem __attribute__((unused)),
2323 struct dm_report_field *field, const void *data,
2324 void *private __attribute__((unused)))
2325 {
2326 uint32_t value;
2327
2328 if (!dm_task_get_read_ahead((const struct dm_task *) data, &value))
2329 value = 0;
2330
2331 return dm_report_field_uint32(rh, field, &value);
2332 }
2333
2334 static int _dm_blk_name_disp(struct dm_report *rh,
2335 struct dm_pool *mem __attribute__((unused)),
2336 struct dm_report_field *field, const void *data,
2337 void *private __attribute__((unused)))
2338 {
2339 char dev_name[PATH_MAX];
2340 const char *s = dev_name;
2341 const struct dm_info *info = data;
2342
2343 if (!dm_device_get_name(info->major, info->minor, 1, dev_name, PATH_MAX)) {
2344 log_error("Could not resolve block device name for %d:%d.",
2345 info->major, info->minor);
2346 return 0;
2347 }
2348
2349 return dm_report_field_string(rh, field, &s);
2350 }
2351
2352 static int _dm_info_status_disp(struct dm_report *rh,
2353 struct dm_pool *mem __attribute__((unused)),
2354 struct dm_report_field *field, const void *data,
2355 void *private __attribute__((unused)))
2356 {
2357 char buf[5];
2358 const char *s = buf;
2359 const struct dm_info *info = data;
2360
2361 buf[0] = info->live_table ? 'L' : '-';
2362 buf[1] = info->inactive_table ? 'I' : '-';
2363 buf[2] = info->suspended ? 's' : '-';
2364 buf[3] = info->read_only ? 'r' : 'w';
2365 buf[4] = '\0';
2366
2367 return dm_report_field_string(rh, field, &s);
2368 }
2369
2370 static int _dm_info_table_loaded_disp(struct dm_report *rh,
2371 struct dm_pool *mem __attribute__((unused)),
2372 struct dm_report_field *field,
2373 const void *data,
2374 void *private __attribute__((unused)))
2375 {
2376 const struct dm_info *info = data;
2377
2378 if (info->live_table) {
2379 if (info->inactive_table)
2380 dm_report_field_set_value(field, "Both", NULL);
2381 else
2382 dm_report_field_set_value(field, "Live", NULL);
2383 return 1;
2384 }
2385
2386 if (info->inactive_table)
2387 dm_report_field_set_value(field, "Inactive", NULL);
2388 else
2389 dm_report_field_set_value(field, "None", NULL);
2390
2391 return 1;
2392 }
2393
2394 static int _dm_info_suspended_disp(struct dm_report *rh,
2395 struct dm_pool *mem __attribute__((unused)),
2396 struct dm_report_field *field,
2397 const void *data,
2398 void *private __attribute__((unused)))
2399 {
2400 const struct dm_info *info = data;
2401
2402 if (info->suspended)
2403 dm_report_field_set_value(field, "Suspended", NULL);
2404 else
2405 dm_report_field_set_value(field, "Active", NULL);
2406
2407 return 1;
2408 }
2409
2410 static int _dm_info_read_only_disp(struct dm_report *rh,
2411 struct dm_pool *mem __attribute__((unused)),
2412 struct dm_report_field *field,
2413 const void *data,
2414 void *private __attribute__((unused)))
2415 {
2416 const struct dm_info *info = data;
2417
2418 if (info->read_only)
2419 dm_report_field_set_value(field, "Read-only", NULL);
2420 else
2421 dm_report_field_set_value(field, "Writeable", NULL);
2422
2423 return 1;
2424 }
2425
2426
2427 static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem,
2428 struct dm_report_field *field, const void *data,
2429 void *private)
2430 {
2431 char buf[PATH_MAX], *repstr;
2432 const struct dm_info *info = data;
2433
2434 if (!dm_pool_begin_object(mem, 8)) {
2435 log_error("dm_pool_begin_object failed");
2436 return 0;
2437 }
2438
2439 if (private) {
2440 if (!dm_device_get_name(info->major, info->minor,
2441 1, buf, PATH_MAX))
2442 goto out_abandon;
2443 }
2444 else {
2445 if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2446 info->major, info->minor) < 0) {
2447 log_error("dm_pool_alloc failed");
2448 goto out_abandon;
2449 }
2450 }
2451
2452 if (!dm_pool_grow_object(mem, buf, strlen(buf) + 1)) {
2453 log_error("dm_pool_grow_object failed");
2454 goto out_abandon;
2455 }
2456
2457 repstr = dm_pool_end_object(mem);
2458 dm_report_field_set_value(field, repstr, repstr);
2459 return 1;
2460
2461 out_abandon:
2462 dm_pool_abandon_object(mem);
2463 return 0;
2464 }
2465
2466 static int _dm_tree_names(struct dm_report *rh, struct dm_pool *mem,
2467 struct dm_report_field *field, const void *data,
2468 void *private, unsigned inverted)
2469 {
2470 const struct dm_tree_node *node = data;
2471 struct dm_tree_node *parent;
2472 void *t = NULL;
2473 const char *name;
2474 int first_node = 1;
2475 char *repstr;
2476
2477 if (!dm_pool_begin_object(mem, 16)) {
2478 log_error("dm_pool_begin_object failed");
2479 return 0;
2480 }
2481
2482 while ((parent = dm_tree_next_child(&t, node, inverted))) {
2483 name = dm_tree_node_get_name(parent);
2484 if (!name || !*name)
2485 continue;
2486 if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
2487 log_error("dm_pool_grow_object failed");
2488 goto out_abandon;
2489 }
2490 if (!dm_pool_grow_object(mem, name, 0)) {
2491 log_error("dm_pool_grow_object failed");
2492 goto out_abandon;
2493 }
2494 if (first_node)
2495 first_node = 0;
2496 }
2497
2498 if (!dm_pool_grow_object(mem, "\0", 1)) {
2499 log_error("dm_pool_grow_object failed");
2500 goto out_abandon;
2501 }
2502
2503 repstr = dm_pool_end_object(mem);
2504 dm_report_field_set_value(field, repstr, repstr);
2505 return 1;
2506
2507 out_abandon:
2508 dm_pool_abandon_object(mem);
2509 return 0;
2510 }
2511
2512 static int _dm_deps_names_disp(struct dm_report *rh,
2513 struct dm_pool *mem,
2514 struct dm_report_field *field,
2515 const void *data, void *private)
2516 {
2517 return _dm_tree_names(rh, mem, field, data, private, 0);
2518 }
2519
2520 static int _dm_tree_parents_names_disp(struct dm_report *rh,
2521 struct dm_pool *mem,
2522 struct dm_report_field *field,
2523 const void *data, void *private)
2524 {
2525 return _dm_tree_names(rh, mem, field, data, private, 1);
2526 }
2527
2528 static int _dm_tree_parents_devs_disp(struct dm_report *rh, struct dm_pool *mem,
2529 struct dm_report_field *field,
2530 const void *data, void *private)
2531 {
2532 const struct dm_tree_node *node = data;
2533 struct dm_tree_node *parent;
2534 void *t = NULL;
2535 const struct dm_info *info;
2536 int first_node = 1;
2537 char buf[DM_MAX_TYPE_NAME], *repstr;
2538
2539 if (!dm_pool_begin_object(mem, 16)) {
2540 log_error("dm_pool_begin_object failed");
2541 return 0;
2542 }
2543
2544 while ((parent = dm_tree_next_child(&t, node, 1))) {
2545 info = dm_tree_node_get_info(parent);
2546 if (!info->major && !info->minor)
2547 continue;
2548 if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
2549 log_error("dm_pool_grow_object failed");
2550 goto out_abandon;
2551 }
2552 if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2553 info->major, info->minor) < 0) {
2554 log_error("dm_snprintf failed");
2555 goto out_abandon;
2556 }
2557 if (!dm_pool_grow_object(mem, buf, 0)) {
2558 log_error("dm_pool_grow_object failed");
2559 goto out_abandon;
2560 }
2561 if (first_node)
2562 first_node = 0;
2563 }
2564
2565 if (!dm_pool_grow_object(mem, "\0", 1)) {
2566 log_error("dm_pool_grow_object failed");
2567 goto out_abandon;
2568 }
2569
2570 repstr = dm_pool_end_object(mem);
2571 dm_report_field_set_value(field, repstr, repstr);
2572 return 1;
2573
2574 out_abandon:
2575 dm_pool_abandon_object(mem);
2576 return 0;
2577 }
2578
2579 static int _dm_tree_parents_count_disp(struct dm_report *rh,
2580 struct dm_pool *mem,
2581 struct dm_report_field *field,
2582 const void *data, void *private)
2583 {
2584 const struct dm_tree_node *node = data;
2585 int num_parent = dm_tree_node_num_children(node, 1);
2586
2587 return dm_report_field_int(rh, field, &num_parent);
2588 }
2589
2590 static int _dm_deps_disp_common(struct dm_report *rh, struct dm_pool*mem,
2591 struct dm_report_field *field, const void *data,
2592 void *private, int disp_blk_dev_names)
2593 {
2594 const struct dm_deps *deps = data;
2595 char buf[PATH_MAX], *repstr;
2596 int major, minor;
2597 unsigned i;
2598
2599 if (!dm_pool_begin_object(mem, 16)) {
2600 log_error("dm_pool_begin_object failed");
2601 return 0;
2602 }
2603
2604 for (i = 0; i < deps->count; i++) {
2605 major = (int) MAJOR(deps->device[i]);
2606 minor = (int) MINOR(deps->device[i]);
2607
2608 if (disp_blk_dev_names) {
2609 if (!dm_device_get_name(major, minor, 1, buf, PATH_MAX)) {
2610 log_error("Could not resolve block device "
2611 "name for %d:%d.", major, minor);
2612 goto out_abandon;
2613 }
2614 }
2615 else if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2616 major, minor) < 0) {
2617 log_error("dm_snprintf failed");
2618 goto out_abandon;
2619 }
2620
2621 if (!dm_pool_grow_object(mem, buf, 0)) {
2622 log_error("dm_pool_grow_object failed");
2623 goto out_abandon;
2624 }
2625
2626 if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) {
2627 log_error("dm_pool_grow_object failed");
2628 goto out_abandon;
2629 }
2630 }
2631
2632 if (!dm_pool_grow_object(mem, "\0", 1)) {
2633 log_error("dm_pool_grow_object failed");
2634 goto out_abandon;
2635 }
2636
2637 repstr = dm_pool_end_object(mem);
2638 dm_report_field_set_value(field, repstr, repstr);
2639 return 1;
2640
2641 out_abandon:
2642 dm_pool_abandon_object(mem);
2643 return 0;
2644 }
2645
2646 static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
2647 struct dm_report_field *field, const void *data,
2648 void *private)
2649 {
2650 return _dm_deps_disp_common(rh, mem, field, data, private, 0);
2651 }
2652
2653 static int _dm_deps_blk_names_disp(struct dm_report *rh, struct dm_pool *mem,
2654 struct dm_report_field *field,
2655 const void *data, void *private)
2656 {
2657 return _dm_deps_disp_common(rh, mem, field, data, private, 1);
2658 }
2659
2660 static int _dm_subsystem_disp(struct dm_report *rh,
2661 struct dm_pool *mem __attribute__((unused)),
2662 struct dm_report_field *field, const void *data,
2663 void *private __attribute__((unused)))
2664 {
2665 return dm_report_field_string(rh, field, (const char *const *) data);
2666 }
2667
2668 static int _dm_vg_name_disp(struct dm_report *rh,
2669 struct dm_pool *mem __attribute__((unused)),
2670 struct dm_report_field *field, const void *data,
2671 void *private __attribute__((unused)))
2672 {
2673
2674 return dm_report_field_string(rh, field, (const char *const *) data);
2675 }
2676
2677 static int _dm_lv_name_disp(struct dm_report *rh,
2678 struct dm_pool *mem __attribute__((unused)),
2679 struct dm_report_field *field, const void *data,
2680 void *private __attribute__((unused)))
2681
2682 {
2683 return dm_report_field_string(rh, field, (const char *const *) data);
2684 }
2685
2686 static int _dm_lv_layer_name_disp(struct dm_report *rh,
2687 struct dm_pool *mem __attribute__((unused)),
2688 struct dm_report_field *field, const void *data,
2689 void *private __attribute__((unused)))
2690
2691 {
2692 return dm_report_field_string(rh, field, (const char *const *) data);
2693 }
2694
2695 static void *_task_get_obj(void *obj)
2696 {
2697 return ((struct dmsetup_report_obj *)obj)->task;
2698 }
2699
2700 static void *_info_get_obj(void *obj)
2701 {
2702 return ((struct dmsetup_report_obj *)obj)->info;
2703 }
2704
2705 static void *_deps_get_obj(void *obj)
2706 {
2707 return dm_task_get_deps(((struct dmsetup_report_obj *)obj)->deps_task);
2708 }
2709
2710 static void *_tree_get_obj(void *obj)
2711 {
2712 return ((struct dmsetup_report_obj *)obj)->tree_node;
2713 }
2714
2715 static void *_split_name_get_obj(void *obj)
2716 {
2717 return ((struct dmsetup_report_obj *)obj)->split_name;
2718 }
2719
2720 static const struct dm_report_object_type _report_types[] = {
2721 { DR_TASK, "Mapped Device Name", "", _task_get_obj },
2722 { DR_INFO, "Mapped Device Information", "", _info_get_obj },
2723 { DR_DEPS, "Mapped Device Relationship Information", "", _deps_get_obj },
2724 { DR_TREE, "Mapped Device Relationship Information", "", _tree_get_obj },
2725 { DR_NAME, "Mapped Device Name Components", "", _split_name_get_obj },
2726 { 0, "", "", NULL },
2727 };
2728
2729 /* Column definitions */
2730 #define OFFSET_OF(strct, field) (((char*)&((struct strct*)0)->field) - (char*)0)
2731 #define STR (DM_REPORT_FIELD_TYPE_STRING)
2732 #define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
2733 #define FIELD_O(type, strct, sorttype, head, field, width, func, id, desc) {DR_ ## type, sorttype, OFFSET_OF(strct, field), width, id, head, &_ ## func ## _disp, desc},
2734 #define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},
2735
2736 static const struct dm_report_field_type _report_fields[] = {
2737 /* *INDENT-OFF* */
2738 FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
2739 FIELD_F(TASK, STR, "MangledName", 16, dm_mangled_name, "mangled_name", "Mangled name of mapped device.")
2740 FIELD_F(TASK, STR, "UnmangledName", 16, dm_unmangled_name, "unmangled_name", "Unmangled name of mapped device.")
2741 FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
2742
2743 /* FIXME Next one should be INFO */
2744 FIELD_F(TASK, NUM, "RAhead", 6, dm_read_ahead, "read_ahead", "Read ahead in sectors.")
2745
2746 FIELD_F(INFO, STR, "BlkDevName", 16, dm_blk_name, "blkdevname", "Name of block device.")
2747 FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
2748 FIELD_F(INFO, STR, "Tables", 6, dm_info_table_loaded, "tables_loaded", "Which of the live and inactive table slots are filled.")
2749 FIELD_F(INFO, STR, "Suspended", 9, dm_info_suspended, "suspended", "Whether the device is suspended.")
2750 FIELD_F(INFO, STR, "Read-only", 9, dm_info_read_only, "readonly", "Whether the device is read-only or writeable.")
2751 FIELD_F(INFO, STR, "DevNo", 5, dm_info_devno, "devno", "Device major and minor numbers")
2752 FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.")
2753 FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.")
2754 FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.")
2755 FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.")
2756 FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
2757
2758 FIELD_O(DEPS, dm_deps, NUM, "#Devs", count, 5, int32, "device_count", "Number of devices used by this one.")
2759 FIELD_F(TREE, STR, "DevNamesUsed", 16, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.")
2760 FIELD_F(DEPS, STR, "DevNosUsed", 16, dm_deps, "devnos_used", "List of device numbers of devices used by this one.")
2761 FIELD_F(DEPS, STR, "BlkDevNamesUsed", 16, dm_deps_blk_names, "blkdevs_used", "List of names of block devices used by this one.")
2762
2763 FIELD_F(TREE, NUM, "#Refs", 5, dm_tree_parents_count, "device_ref_count", "Number of mapped devices referencing this one.")
2764 FIELD_F(TREE, STR, "RefNames", 8, dm_tree_parents_names, "names_using_dev", "List of names of mapped devices using this one.")
2765 FIELD_F(TREE, STR, "RefDevNos", 9, dm_tree_parents_devs, "devnos_using_dev", "List of device numbers of mapped devices using this one.")
2766
2767 FIELD_O(NAME, dm_split_name, STR, "Subsys", subsystem, 6, dm_subsystem, "subsystem", "Userspace subsystem responsible for this device.")
2768 FIELD_O(NAME, dm_split_name, STR, "VG", vg_name, 4, dm_vg_name, "vg_name", "LVM Volume Group name.")
2769 FIELD_O(NAME, dm_split_name, STR, "LV", lv_name, 4, dm_lv_name, "lv_name", "LVM Logical Volume name.")
2770 FIELD_O(NAME, dm_split_name, STR, "LVLayer", lv_layer, 7, dm_lv_layer_name, "lv_layer", "LVM device layer.")
2771
2772 {0, 0, 0, 0, "", "", NULL, NULL},
2773 /* *INDENT-ON* */
2774 };
2775
2776 #undef STR
2777 #undef NUM
2778 #undef FIELD_O
2779 #undef FIELD_F
2780
2781 static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid";
2782 static const char *splitname_report_options = "vg_name,lv_name,lv_layer";
2783
2784 static int _report_init(const struct command *cmd)
2785 {
2786 char *options = (char *) default_report_options;
2787 const char *keys = "";
2788 const char *separator = " ";
2789 int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0;
2790 int quoted = 1, columns_as_rows = 0;
2791 uint32_t flags = 0;
2792 size_t len = 0;
2793 int r = 0;
2794
2795 if (cmd && !strcmp(cmd->name, "splitname"))
2796 options = (char *) splitname_report_options;
2797
2798 /* emulate old dmsetup behaviour */
2799 if (_switches[NOHEADINGS_ARG]) {
2800 separator = ":";
2801 aligned = 0;
2802 headings = 0;
2803 }
2804
2805 if (_switches[UNBUFFERED_ARG])
2806 buffered = 0;
2807
2808 if (_switches[ROWS_ARG])
2809 columns_as_rows = 1;
2810
2811 if (_switches[UNQUOTED_ARG])
2812 quoted = 0;
2813
2814 if (_switches[NAMEPREFIXES_ARG]) {
2815 aligned = 0;
2816 field_prefixes = 1;
2817 }
2818
2819 if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) {
2820 if (*_string_args[OPTIONS_ARG] != '+')
2821 options = _string_args[OPTIONS_ARG];
2822 else {
2823 len = strlen(default_report_options) +
2824 strlen(_string_args[OPTIONS_ARG]) + 1;
2825 if (!(options = dm_malloc(len))) {
2826 err("Failed to allocate option string.");
2827 return 0;
2828 }
2829 if (dm_snprintf(options, len, "%s,%s",
2830 default_report_options,
2831 &_string_args[OPTIONS_ARG][1]) < 0) {
2832 err("snprintf failed");
2833 goto out;
2834 }
2835 }
2836 }
2837
2838 if (_switches[SORT_ARG] && _string_args[SORT_ARG]) {
2839 keys = _string_args[SORT_ARG];
2840 buffered = 1;
2841 if (cmd && (!strcmp(cmd->name, "status") || !strcmp(cmd->name, "table"))) {
2842 err("--sort is not yet supported with status and table");
2843 goto out;
2844 }
2845 }
2846
2847 if (_switches[SEPARATOR_ARG] && _string_args[SEPARATOR_ARG]) {
2848 separator = _string_args[SEPARATOR_ARG];
2849 aligned = 0;
2850 }
2851
2852 if (aligned)
2853 flags |= DM_REPORT_OUTPUT_ALIGNED;
2854
2855 if (buffered)
2856 flags |= DM_REPORT_OUTPUT_BUFFERED;
2857
2858 if (headings)
2859 flags |= DM_REPORT_OUTPUT_HEADINGS;
2860
2861 if (field_prefixes)
2862 flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX;
2863
2864 if (!quoted)
2865 flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED;
2866
2867 if (columns_as_rows)
2868 flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
2869
2870 if (!(_report = dm_report_init(&_report_type,
2871 _report_types, _report_fields,
2872 options, separator, flags, keys, NULL)))
2873 goto out;
2874
2875 if ((_report_type & DR_TREE) && !_build_whole_deptree(cmd)) {
2876 err("Internal device dependency tree creation failed.");
2877 goto out;
2878 }
2879
2880 if (field_prefixes)
2881 dm_report_set_output_field_name_prefix(_report, "dm_");
2882
2883 r = 1;
2884
2885 out:
2886 if (!strcasecmp(options, "help") || !strcmp(options, "?"))
2887 r = 1;
2888
2889 if (len)
2890 dm_free(options);
2891
2892 return r;
2893 }
2894
2895 /*
2896 * List devices
2897 */
2898 static int _ls(CMD_ARGS)
2899 {
2900 if ((_switches[TARGET_ARG] && _target) ||
2901 (_switches[EXEC_ARG] && _command))
2902 return _status(cmd, argc, argv, NULL, 0);
2903 else if ((_switches[TREE_ARG]))
2904 return _display_tree(cmd, 0, NULL, NULL, 0);
2905 else
2906 return _process_all(cmd, argc, argv, 0, _display_name);
2907 }
2908
2909 static int _mangle(CMD_ARGS)
2910 {
2911 char *name;
2912 char *new_name = NULL;
2913 struct dm_task *dmt;
2914 struct dm_info info;
2915 int r = 0;
2916 int target_format;
2917
2918 if (names)
2919 name = names->name;
2920 else {
2921 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
2922 return _process_all(cmd, argc, argv, 0, _mangle);
2923 name = argv[1];
2924 }
2925
2926 if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
2927 return 0;
2928
2929 if (!(_set_task_device(dmt, name, 0)))
2930 goto out;
2931
2932 if (!_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
2933 goto out;
2934
2935 if (!dm_task_run(dmt))
2936 goto out;
2937
2938 if (!dm_task_get_info(dmt, &info) || !info.exists)
2939 goto out;
2940
2941 target_format = _switches[MANGLENAME_ARG] ? _int_args[MANGLENAME_ARG]
2942 : DEFAULT_DM_NAME_MANGLING;
2943
2944 if (target_format == DM_STRING_MANGLING_AUTO && strstr(name, "\\x5cx")) {
2945 log_error("The name \"%s\" seems to be mangled more than once. "
2946 "Manual intervention required to rename the device.", name);
2947 goto out;
2948 }
2949
2950 if (target_format == DM_STRING_MANGLING_NONE) {
2951 if (!(new_name = dm_task_get_name_unmangled(dmt)))
2952 goto out;
2953 }
2954 else if (!(new_name = dm_task_get_name_mangled(dmt)))
2955 goto out;
2956
2957 /* Nothing to do if the name is in correct form already. */
2958 if (!strcmp(name, new_name)) {
2959 log_print("%s: name already in correct form", name);
2960 r = 1;
2961 goto out;
2962 }
2963 else
2964 log_print("%s: renaming to %s", name, new_name);
2965
2966 /* Rename to correct form of the name. */
2967 r = _do_rename(name, new_name, NULL);
2968
2969 out:
2970 dm_free(new_name);
2971 dm_task_destroy(dmt);
2972 return r;
2973 }
2974
2975 static int _help(CMD_ARGS);
2976
2977 /*
2978 * Dispatch table
2979 */
2980 static struct command _commands[] = {
2981 {"help", "[-c|-C|--columns]", 0, 0, 0, _help},
2982 {"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
2983 "\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
2984 "\t [-u|uuid <uuid>] [{--addnodeonresume|--addnodeoncreate}]\n"
2985 "\t [--notable | --table <table> | <table_file>]",
2986 1, 2,0, _create},
2987 {"remove", "[-f|--force] <device>", 0, -1, 1, _remove},
2988 {"remove_all", "[-f|--force]", 0, 0, 0, _remove_all},
2989 {"suspend", "[--noflush] <device>", 0, -1, 1, _suspend},
2990 {"resume", "<device> [{--addnodeonresume|--addnodeoncreate}]", 0, -1, 1, _resume},
2991 {"load", "<device> [<table_file>]", 0, 2, 0, _load},
2992 {"clear", "<device>", 0, -1, 1, _clear},
2993 {"reload", "<device> [<table_file>]", 0, 2, 0, _load},
2994 {"wipe_table", "<device>", 0, -1, 1, _error_device},
2995 {"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, 0, _rename},
2996 {"message", "<device> <sector> <message>", 2, -1, 0, _message},
2997 {"ls", "[--target <target_type>] [--exec <command>] [-o options] [--tree]", 0, 0, 0, _ls},
2998 {"info", "[<device>]", 0, -1, 1, _info},
2999 {"deps", "[-o options] [<device>]", 0, -1, 1, _deps},
3000 {"status", "[<device>] [--noflush] [--target <target_type>]", 0, -1, 1, _status},
3001 {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, -1, 1, _status},
3002 {"wait", "<device> [<event_nr>] [--noflush]", 0, 2, 0, _wait},
3003 {"mknodes", "[<device>]", 0, -1, 1, _mknodes},
3004 {"mangle", "[<device>]", 0, -1, 1, _mangle},
3005 {"udevcreatecookie", "", 0, 0, 0, _udevcreatecookie},
3006 {"udevreleasecookie", "[<cookie>]", 0, 1, 0, _udevreleasecookie},
3007 {"udevflags", "<cookie>", 1, 1, 0, _udevflags},
3008 {"udevcomplete", "<cookie>", 1, 1, 0, _udevcomplete},
3009 {"udevcomplete_all", "<age_in_minutes>", 0, 1, 0, _udevcomplete_all},
3010 {"udevcookies", "", 0, 0, 0, _udevcookies},
3011 {"targets", "", 0, 0, 0, _targets},
3012 {"version", "", 0, 0, 0, _version},
3013 {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, 0, _setgeometry},
3014 {"splitname", "<device> [<subsystem>]", 1, 2, 0, _splitname},
3015 {NULL, NULL, 0, 0, 0, NULL}
3016 };
3017
3018 static void _usage(FILE *out)
3019 {
3020 int i;
3021
3022 fprintf(out, "Usage:\n\n");
3023 fprintf(out, "dmsetup [--version] [-h|--help [-c|-C|--columns]]\n"
3024 " [--checks] [--manglename <mangling_mode>] [-v|--verbose [-v|--verbose ...]]\n"
3025 " [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n"
3026 " [--udevcookie [cookie]] [--noudevrules] [--noudevsync] [--verifyudev]\n"
3027 " [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n"
3028 " [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
3029 " [--nameprefixes] [--noheadings] [--separator <separator>]\n\n");
3030 for (i = 0; _commands[i].name; i++)
3031 fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
3032 fprintf(out, "\n<device> may be device name or -u <uuid> or "
3033 "-j <major> -m <minor>\n");
3034 fprintf(out, "<mangling_mode> is one of 'none', 'auto' and 'hex'.\n");
3035 fprintf(out, "<fields> are comma-separated. Use 'help -c' for list.\n");
3036 fprintf(out, "Table_file contents may be supplied on stdin.\n");
3037 fprintf(out, "Options are: devno, devname, blkdevname.\n");
3038 fprintf(out, "Tree specific options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
3039 " blkdevname, [no]device, active, open, rw and uuid.\n");
3040 fprintf(out, "\n");
3041 }
3042
3043 static void _losetup_usage(FILE *out)
3044 {
3045 fprintf(out, "Usage:\n\n");
3046 fprintf(out, "losetup [-d|-a] [-e encryption] "
3047 "[-o offset] [-f|loop_device] [file]\n\n");
3048 }
3049
3050 static int _help(CMD_ARGS)
3051 {
3052 _usage(stderr);
3053
3054 if (_switches[COLS_ARG]) {
3055 _switches[OPTIONS_ARG] = 1;
3056 _string_args[OPTIONS_ARG] = (char *) "help";
3057 _switches[SORT_ARG] = 0;
3058
3059 if (_report) {
3060 dm_report_free(_report);
3061 _report = NULL;
3062 }
3063 (void) _report_init(cmd);
3064 }
3065
3066 return 1;
3067 }
3068
3069 static struct command *_find_command(const char *name)
3070 {
3071 int i;
3072
3073 for (i = 0; _commands[i].name; i++)
3074 if (!strcmp(_commands[i].name, name))
3075 return _commands + i;
3076
3077 return NULL;
3078 }
3079
3080 static int _process_tree_options(const char *options)
3081 {
3082 const char *s, *end;
3083 struct winsize winsz;
3084 size_t len;
3085
3086 /* Symbol set default */
3087 if (!strcmp(nl_langinfo(CODESET), "UTF-8"))
3088 _tsym = &_tsym_utf;
3089 else
3090 _tsym = &_tsym_ascii;
3091
3092 /* Default */
3093 _tree_switches[TR_DEVICE] = 1;
3094 _tree_switches[TR_TRUNCATE] = 1;
3095
3096 /* parse */
3097 for (s = options; s && *s; s++) {
3098 len = 0;
3099 for (end = s; *end && *end != ','; end++, len++)
3100 ;
3101 if (!strncmp(s, "device", len))
3102 _tree_switches[TR_DEVICE] = 1;
3103 else if (!strncmp(s, "blkdevname", len))
3104 _tree_switches[TR_BLKDEVNAME] = 1;
3105 else if (!strncmp(s, "nodevice", len))
3106 _tree_switches[TR_DEVICE] = 0;
3107 else if (!strncmp(s, "status", len))
3108 _tree_switches[TR_STATUS] = 1;
3109 else if (!strncmp(s, "table", len))
3110 _tree_switches[TR_TABLE] = 1;
3111 else if (!strncmp(s, "active", len))
3112 _tree_switches[TR_ACTIVE] = 1;
3113 else if (!strncmp(s, "open", len))
3114 _tree_switches[TR_OPENCOUNT] = 1;
3115 else if (!strncmp(s, "uuid", len))
3116 _tree_switches[TR_UUID] = 1;
3117 else if (!strncmp(s, "rw", len))
3118 _tree_switches[TR_RW] = 1;
3119 else if (!strncmp(s, "utf", len))
3120 _tsym = &_tsym_utf;
3121 else if (!strncmp(s, "vt100", len))
3122 _tsym = &_tsym_vt100;
3123 else if (!strncmp(s, "ascii", len))
3124 _tsym = &_tsym_ascii;
3125 else if (!strncmp(s, "inverted", len))
3126 _tree_switches[TR_BOTTOMUP] = 1;
3127 else if (!strncmp(s, "compact", len))
3128 _tree_switches[TR_COMPACT] = 1;
3129 else if (!strncmp(s, "notrunc", len))
3130 _tree_switches[TR_TRUNCATE] = 0;
3131 else {
3132 fprintf(stderr, "Tree options not recognised: %s\n", s);
3133 return 0;
3134 }
3135 if (!*end)
3136 break;
3137 s = end;
3138 }
3139
3140 /* Truncation doesn't work well with vt100 drawing char */
3141 if (_tsym != &_tsym_vt100)
3142 if (ioctl(1, (unsigned long) TIOCGWINSZ, &winsz) >= 0 && winsz.ws_col > 3)
3143 _termwidth = winsz.ws_col - 3;
3144
3145 return 1;
3146 }
3147
3148 /*
3149 * Returns the full absolute path, or NULL if the path could
3150 * not be resolved.
3151 */
3152 static char *_get_abspath(const char *path)
3153 {
3154 char *_path;
3155
3156 #ifdef HAVE_CANONICALIZE_FILE_NAME
3157 _path = canonicalize_file_name(path);
3158 #else
3159 /* FIXME Provide alternative */
3160 log_error(INTERNAL_ERROR "Unimplemented _get_abspath.");
3161 _path = NULL;
3162 #endif
3163 return _path;
3164 }
3165
3166 static char *parse_loop_device_name(const char *dev, const char *dev_dir)
3167 {
3168 char *buf;
3169 char *device = NULL;
3170
3171 if (!(buf = dm_malloc(PATH_MAX)))
3172 return NULL;
3173
3174 if (dev[0] == '/') {
3175 if (!(device = _get_abspath(dev)))
3176 goto error;
3177
3178 if (strncmp(device, dev_dir, strlen(dev_dir)))
3179 goto error;
3180
3181 /* If dev_dir does not end in a slash, ensure that the
3182 following byte in the device string is "/". */
3183 if (dev_dir[strlen(dev_dir) - 1] != '/' &&
3184 device[strlen(dev_dir)] != '/')
3185 goto error;
3186
3187 strncpy(buf, strrchr(device, '/') + 1, PATH_MAX - 1);
3188 buf[PATH_MAX - 1] = '\0';
3189 dm_free(device);
3190
3191 } else {
3192 /* check for device number */
3193 if (!strncmp(dev, "loop", strlen("loop")))
3194 strncpy(buf, dev, (size_t) PATH_MAX);
3195 else
3196 goto error;
3197 }
3198
3199 return buf;
3200
3201 error:
3202 dm_free(device);
3203 dm_free(buf);
3204
3205 return NULL;
3206 }
3207
3208 /*
3209 * create a table for a mapped device using the loop target.
3210 */
3211 static int _loop_table(char *table, size_t tlen, char *file,
3212 char *dev __attribute__((unused)), off_t off)
3213 {
3214 struct stat fbuf;
3215 off_t size, sectors;
3216 int fd = -1;
3217 #ifdef HAVE_SYS_STATVFS_H
3218 struct statvfs fsbuf;
3219 off_t blksize;
3220 #endif
3221
3222 if (!_switches[READ_ONLY])
3223 fd = open(file, O_RDWR);
3224
3225 if (fd < 0) {
3226 _switches[READ_ONLY]++;
3227 fd = open(file, O_RDONLY);
3228 }
3229
3230 if (fd < 0)
3231 goto error;
3232
3233 if (fstat(fd, &fbuf))
3234 goto error;
3235
3236 size = (fbuf.st_size - off);
3237 sectors = size >> SECTOR_SHIFT;
3238
3239 if (_switches[VERBOSE_ARG])
3240 fprintf(stderr, "losetup: set loop size to %llukB "
3241 "(%llu sectors)\n", (long long unsigned) sectors >> 1,
3242 (long long unsigned) sectors);
3243
3244 #ifdef HAVE_SYS_STATVFS_H
3245 if (fstatvfs(fd, &fsbuf))
3246 goto error;
3247
3248 /* FIXME Fragment size currently unused */
3249 blksize = fsbuf.f_frsize;
3250 #endif
3251
3252 if (close(fd))
3253 log_sys_error("close", file);
3254
3255 if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
3256 (long long unsigned)sectors, file, (long long unsigned)off) < 0)
3257 return 0;
3258
3259 if (_switches[VERBOSE_ARG] > 1)
3260 fprintf(stderr, "Table: %s\n", table);
3261
3262 return 1;
3263
3264 error:
3265 if (fd > -1 && close(fd))
3266 log_sys_error("close", file);
3267
3268 return 0;
3269 }
3270
3271 static int _process_losetup_switches(const char *base, int *argc, char ***argv,
3272 const char *dev_dir)
3273 {
3274 int c;
3275 int encrypt_loop = 0, delete = 0, find = 0, show_all = 0;
3276 char *device_name = NULL;
3277 char *loop_file = NULL;
3278 off_t offset = 0;
3279
3280 #ifdef HAVE_GETOPTLONG
3281 static struct option long_options[] = {
3282 {0, 0, 0, 0}
3283 };
3284 #endif
3285
3286 optarg = 0;
3287 optind = OPTIND_INIT;
3288 while ((c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
3289 long_options, NULL)) != -1 ) {
3290 if (c == ':' || c == '?')
3291 return 0;
3292 if (c == 'a')
3293 show_all++;
3294 if (c == 'd')
3295 delete++;
3296 if (c == 'e')
3297 encrypt_loop++;
3298 if (c == 'f')
3299 find++;
3300 if (c == 'o')
3301 offset = atoi(optarg);
3302 if (c == 'v')
3303 _switches[VERBOSE_ARG]++;
3304 }
3305
3306 *argv += optind ;
3307 *argc -= optind ;
3308
3309 if (encrypt_loop){
3310 fprintf(stderr, "%s: Sorry, cryptoloop is not yet implemented "
3311 "in this version.\n", base);
3312 return 0;
3313 }
3314
3315 if (show_all) {
3316 fprintf(stderr, "%s: Sorry, show all is not yet implemented "
3317 "in this version.\n", base);
3318 return 0;
3319 }
3320
3321 if (find) {
3322 fprintf(stderr, "%s: Sorry, find is not yet implemented "
3323 "in this version.\n", base);
3324 if (!*argc)
3325 return 0;
3326 }
3327
3328 if (!*argc) {
3329 fprintf(stderr, "%s: Please specify loop_device.\n", base);
3330 _losetup_usage(stderr);
3331 return 0;
3332 }
3333
3334 if (!(device_name = parse_loop_device_name((*argv)[0], dev_dir))) {
3335 fprintf(stderr, "%s: Could not parse loop_device %s\n",
3336 base, (*argv)[0]);
3337 _losetup_usage(stderr);
3338 return 0;
3339 }
3340
3341 if (delete) {
3342 *argc = 2;
3343
3344 (*argv)[1] = device_name;
3345 (*argv)[0] = (char *) "remove";
3346
3347 return 1;
3348 }
3349
3350 if (*argc != 2) {
3351 fprintf(stderr, "%s: Too few arguments\n", base);
3352 _losetup_usage(stderr);
3353 dm_free(device_name);
3354 return 0;
3355 }
3356
3357 /* FIXME move these to make them available to native dmsetup */
3358 if (!(loop_file = _get_abspath((*argv)[(find) ? 0 : 1]))) {
3359 fprintf(stderr, "%s: Could not parse loop file name %s\n",
3360 base, (*argv)[1]);
3361 _losetup_usage(stderr);
3362 dm_free(device_name);
3363 return 0;
3364 }
3365
3366 _table = dm_malloc(LOOP_TABLE_SIZE);
3367 if (!_table ||
3368 !_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
3369 fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]);
3370 dm_free(device_name);
3371 return 0;
3372 }
3373 _switches[TABLE_ARG]++;
3374
3375 (*argv)[0] = (char *) "create";
3376 (*argv)[1] = device_name ;
3377
3378 return 1;
3379 }
3380
3381 static int _process_options(const char *options)
3382 {
3383 const char *s, *end;
3384 size_t len;
3385
3386 /* Tree options are processed separately. */
3387 if (_switches[TREE_ARG])
3388 return _process_tree_options(_string_args[OPTIONS_ARG]);
3389
3390 /* Column options are processed separately by _report_init (called later). */
3391 if (_switches[COLS_ARG])
3392 return 1;
3393
3394 /* No options specified. */
3395 if (!_switches[OPTIONS_ARG])
3396 return 1;
3397
3398 /* Set defaults. */
3399 _dev_name_type = DN_DEVNO;
3400
3401 /* Parse. */
3402 for (s = options; s && *s; s++) {
3403 len = 0;
3404 for (end = s; *end && *end != ','; end++, len++)
3405 ;
3406 if (!strncmp(s, "devno", len))
3407 _dev_name_type = DN_DEVNO;
3408 else if (!strncmp(s, "blkdevname", len))
3409 _dev_name_type = DN_BLK;
3410 else if (!strncmp(s, "devname", len))
3411 _dev_name_type = DN_MAP;
3412 else {
3413 fprintf(stderr, "Option not recognised: %s\n", s);
3414 return 0;
3415 }
3416
3417 if (!*end)
3418 break;
3419 s = end;
3420 }
3421
3422 return 1;
3423 }
3424
3425 static int _process_switches(int *argc, char ***argv, const char *dev_dir)
3426 {
3427 const char *base;
3428 char *namebase, *s;
3429 static int ind;
3430 int c, r;
3431
3432 #ifdef HAVE_GETOPTLONG
3433 static struct option long_options[] = {
3434 {"readonly", 0, &ind, READ_ONLY},
3435 {"checks", 0, &ind, CHECKS_ARG},
3436 {"columns", 0, &ind, COLS_ARG},
3437 {"exec", 1, &ind, EXEC_ARG},
3438 {"force", 0, &ind, FORCE_ARG},
3439 {"gid", 1, &ind, GID_ARG},
3440 {"help", 0, &ind, HELP_ARG},
3441 {"inactive", 0, &ind, INACTIVE_ARG},
3442 {"manglename", 1, &ind, MANGLENAME_ARG},
3443 {"major", 1, &ind, MAJOR_ARG},
3444 {"minor", 1, &ind, MINOR_ARG},
3445 {"mode", 1, &ind, MODE_ARG},
3446 {"nameprefixes", 0, &ind, NAMEPREFIXES_ARG},
3447 {"noflush", 0, &ind, NOFLUSH_ARG},
3448 {"noheadings", 0, &ind, NOHEADINGS_ARG},
3449 {"nolockfs", 0, &ind, NOLOCKFS_ARG},
3450 {"noopencount", 0, &ind, NOOPENCOUNT_ARG},
3451 {"notable", 0, &ind, NOTABLE_ARG},
3452 {"udevcookie", 1, &ind, UDEVCOOKIE_ARG},
3453 {"noudevrules", 0, &ind, NOUDEVRULES_ARG},
3454 {"noudevsync", 0, &ind, NOUDEVSYNC_ARG},
3455 {"options", 1, &ind, OPTIONS_ARG},
3456 {"readahead", 1, &ind, READAHEAD_ARG},
3457 {"retry", 0, &ind, RETRY_ARG},
3458 {"rows", 0, &ind, ROWS_ARG},
3459 {"separator", 1, &ind, SEPARATOR_ARG},
3460 {"setuuid", 0, &ind, SETUUID_ARG},
3461 {"showkeys", 0, &ind, SHOWKEYS_ARG},
3462 {"sort", 1, &ind, SORT_ARG},
3463 {"table", 1, &ind, TABLE_ARG},
3464 {"target", 1, &ind, TARGET_ARG},
3465 {"tree", 0, &ind, TREE_ARG},
3466 {"uid", 1, &ind, UID_ARG},
3467 {"uuid", 1, &ind, UUID_ARG},
3468 {"unbuffered", 0, &ind, UNBUFFERED_ARG},
3469 {"unquoted", 0, &ind, UNQUOTED_ARG},
3470 {"verbose", 1, &ind, VERBOSE_ARG},
3471 {"verifyudev", 0, &ind, VERIFYUDEV_ARG},
3472 {"version", 0, &ind, VERSION_ARG},
3473 {"yes", 0, &ind, YES_ARG},
3474 {"addnodeonresume", 0, &ind, ADD_NODE_ON_RESUME_ARG},
3475 {"addnodeoncreate", 0, &ind, ADD_NODE_ON_CREATE_ARG},
3476 {0, 0, 0, 0}
3477 };
3478 #else
3479 struct option long_options;
3480 #endif
3481
3482 /*
3483 * Zero all the index counts.
3484 */
3485 memset(&_switches, 0, sizeof(_switches));
3486 memset(&_int_args, 0, sizeof(_int_args));
3487 _read_ahead_flags = 0;
3488
3489 if (!(namebase = strdup((*argv)[0]))) {
3490 fprintf(stderr, "Failed to duplicate name.\n");
3491 return 0;
3492 }
3493 base = dm_basename(namebase);
3494
3495 if (!strcmp(base, "devmap_name")) {
3496 free(namebase);
3497 _switches[COLS_ARG]++;
3498 _switches[NOHEADINGS_ARG]++;
3499 _switches[OPTIONS_ARG]++;
3500 _switches[MAJOR_ARG]++;
3501 _switches[MINOR_ARG]++;
3502 _string_args[OPTIONS_ARG] = (char *) "name";
3503
3504 if (*argc == 3) {
3505 _int_args[MAJOR_ARG] = atoi((*argv)[1]);
3506 _int_args[MINOR_ARG] = atoi((*argv)[2]);
3507 *argc -= 2;
3508 *argv += 2;
3509 } else if ((*argc == 2) &&
3510 (2 == sscanf((*argv)[1], "%i:%i",
3511 &_int_args[MAJOR_ARG],
3512 &_int_args[MINOR_ARG]))) {
3513 *argc -= 1;
3514 *argv += 1;
3515 } else {
3516 fprintf(stderr, "Usage: devmap_name <major> <minor>\n");
3517 return 0;
3518 }
3519
3520 (*argv)[0] = (char *) "info";
3521 return 1;
3522 }
3523
3524 if (!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
3525 r = _process_losetup_switches(base, argc, argv, dev_dir);
3526 free(namebase);
3527 return r;
3528 }
3529
3530 free(namebase);
3531
3532 optarg = 0;
3533 optind = OPTIND_INIT;
3534 while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:hj:m:M:no:O:ru:U:vy",
3535 long_options, NULL)) != -1) {
3536 if (c == ':' || c == '?')
3537 return 0;
3538 if (c == 'h' || ind == HELP_ARG)
3539 _switches[HELP_ARG]++;
3540 if (c == 'c' || c == 'C' || ind == COLS_ARG)
3541 _switches[COLS_ARG]++;
3542 if (c == 'f' || ind == FORCE_ARG)
3543 _switches[FORCE_ARG]++;
3544 if (c == 'r' || ind == READ_ONLY)
3545 _switches[READ_ONLY]++;
3546 if (c == 'j' || ind == MAJOR_ARG) {
3547 _switches[MAJOR_ARG]++;
3548 _int_args[MAJOR_ARG] = atoi(optarg);
3549 }
3550 if (c == 'm' || ind == MINOR_ARG) {
3551 _switches[MINOR_ARG]++;
3552 _int_args[MINOR_ARG] = atoi(optarg);
3553 }
3554 if (c == 'n' || ind == NOTABLE_ARG)
3555 _switches[NOTABLE_ARG]++;
3556 if (c == 'o' || ind == OPTIONS_ARG) {
3557 _switches[OPTIONS_ARG]++;
3558 _string_args[OPTIONS_ARG] = optarg;
3559 }
3560 if (ind == SEPARATOR_ARG) {
3561 _switches[SEPARATOR_ARG]++;
3562 _string_args[SEPARATOR_ARG] = optarg;
3563 }
3564 if (c == 'O' || ind == SORT_ARG) {
3565 _switches[SORT_ARG]++;
3566 _string_args[SORT_ARG] = optarg;
3567 }
3568 if (c == 'v' || ind == VERBOSE_ARG)
3569 _switches[VERBOSE_ARG]++;
3570 if (c == 'u' || ind == UUID_ARG) {
3571 _switches[UUID_ARG]++;
3572 _uuid = optarg;
3573 }
3574 if (c == 'y' || ind == YES_ARG)
3575 _switches[YES_ARG]++;
3576 if (ind == ADD_NODE_ON_RESUME_ARG)
3577 _switches[ADD_NODE_ON_RESUME_ARG]++;
3578 if (ind == ADD_NODE_ON_CREATE_ARG)
3579 _switches[ADD_NODE_ON_CREATE_ARG]++;
3580 if (ind == CHECKS_ARG)
3581 _switches[CHECKS_ARG]++;
3582 if (ind == UDEVCOOKIE_ARG) {
3583 _switches[UDEVCOOKIE_ARG]++;
3584 _udev_cookie = _get_cookie_value(optarg);
3585 }
3586 if (ind == NOUDEVRULES_ARG)
3587 _switches[NOUDEVRULES_ARG]++;
3588 if (ind == NOUDEVSYNC_ARG)
3589 _switches[NOUDEVSYNC_ARG]++;
3590 if (ind == VERIFYUDEV_ARG)
3591 _switches[VERIFYUDEV_ARG]++;
3592 if (c == 'G' || ind == GID_ARG) {
3593 _switches[GID_ARG]++;
3594 _int_args[GID_ARG] = atoi(optarg);
3595 }
3596 if (c == 'U' || ind == UID_ARG) {
3597 _switches[UID_ARG]++;
3598 _int_args[UID_ARG] = atoi(optarg);
3599 }
3600 if (c == 'M' || ind == MODE_ARG) {
3601 _switches[MODE_ARG]++;
3602 /* FIXME Accept modes as per chmod */
3603 _int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
3604 }
3605 if (ind == EXEC_ARG) {
3606 _switches[EXEC_ARG]++;
3607 _command = optarg;
3608 }
3609 if (ind == TARGET_ARG) {
3610 _switches[TARGET_ARG]++;
3611 _target = optarg;
3612 }
3613 if (ind == INACTIVE_ARG)
3614 _switches[INACTIVE_ARG]++;
3615 if ((ind == MANGLENAME_ARG)) {
3616 _switches[MANGLENAME_ARG]++;
3617 if (!strcasecmp(optarg, "none"))
3618 _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_NONE;
3619 else if (!strcasecmp(optarg, "auto"))
3620 _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_AUTO;
3621 else if (!strcasecmp(optarg, "hex"))
3622 _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_HEX;
3623 else {
3624 log_error("Unknown name mangling mode");
3625 return 0;
3626 }
3627 dm_set_name_mangling_mode((dm_string_mangling_t) _int_args[MANGLENAME_ARG]);
3628 }
3629 if (ind == NAMEPREFIXES_ARG)
3630 _switches[NAMEPREFIXES_ARG]++;
3631 if (ind == NOFLUSH_ARG)
3632 _switches[NOFLUSH_ARG]++;
3633 if (ind == NOHEADINGS_ARG)
3634 _switches[NOHEADINGS_ARG]++;
3635 if (ind == NOLOCKFS_ARG)
3636 _switches[NOLOCKFS_ARG]++;
3637 if (ind == NOOPENCOUNT_ARG)
3638 _switches[NOOPENCOUNT_ARG]++;
3639 if (ind == READAHEAD_ARG) {
3640 _switches[READAHEAD_ARG]++;
3641 if (!strcasecmp(optarg, "auto"))
3642 _int_args[READAHEAD_ARG] = DM_READ_AHEAD_AUTO;
3643 else if (!strcasecmp(optarg, "none"))
3644 _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE;
3645 else {
3646 for (s = optarg; isspace(*s); s++)
3647 ;
3648 if (*s == '+')
3649 _read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG;
3650 _int_args[READAHEAD_ARG] = atoi(optarg);
3651 if (_int_args[READAHEAD_ARG] < -1) {
3652 log_error("Negative read ahead value "
3653 "(%d) is not understood.",
3654 _int_args[READAHEAD_ARG]);
3655 return 0;
3656 }
3657 }
3658 }
3659 if (ind == RETRY_ARG)
3660 _switches[RETRY_ARG]++;
3661 if (ind == ROWS_ARG)
3662 _switches[ROWS_ARG]++;
3663 if (ind == SETUUID_ARG)
3664 _switches[SETUUID_ARG]++;
3665 if (ind == SHOWKEYS_ARG)
3666 _switches[SHOWKEYS_ARG]++;
3667 if (ind == TABLE_ARG) {
3668 _switches[TABLE_ARG]++;
3669 if (!(_table = dm_strdup(optarg))) {
3670 log_error("Could not allocate memory for table string.");
3671 return 0;
3672 }
3673 }
3674 if (ind == TREE_ARG)
3675 _switches[TREE_ARG]++;
3676 if (ind == UNQUOTED_ARG)
3677 _switches[UNQUOTED_ARG]++;
3678 if (ind == VERSION_ARG)
3679 _switches[VERSION_ARG]++;
3680 }
3681
3682 if (_switches[VERBOSE_ARG] > 1)
3683 dm_log_init_verbose(_switches[VERBOSE_ARG] - 1);
3684
3685 if ((_switches[MAJOR_ARG] && !_switches[MINOR_ARG]) ||
3686 (!_switches[MAJOR_ARG] && _switches[MINOR_ARG])) {
3687 fprintf(stderr, "Please specify both major number and "
3688 "minor number.\n");
3689 return 0;
3690 }
3691
3692 if (!_process_options(_string_args[OPTIONS_ARG]))
3693 return 0;
3694
3695 if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
3696 fprintf(stderr, "--table and --notable are incompatible.\n");
3697 return 0;
3698 }
3699
3700 if (_switches[ADD_NODE_ON_RESUME_ARG] && _switches[ADD_NODE_ON_CREATE_ARG]) {
3701 fprintf(stderr, "--addnodeonresume and --addnodeoncreate are incompatible.\n");
3702 return 0;
3703 }
3704
3705 *argv += optind;
3706 *argc -= optind;
3707 return 1;
3708 }
3709
3710 int main(int argc, char **argv)
3711 {
3712 int r = 1;
3713 const char *dev_dir;
3714 const struct command *cmd;
3715 int multiple_devices;
3716
3717 (void) setlocale(LC_ALL, "");
3718
3719 dev_dir = getenv (DM_DEV_DIR_ENV_VAR_NAME);
3720 if (dev_dir && *dev_dir) {
3721 if (!dm_set_dev_dir(dev_dir)) {
3722 fprintf(stderr, "Invalid DM_DEV_DIR environment variable value.\n");
3723 goto out;
3724 }
3725 } else
3726 dev_dir = DEFAULT_DM_DEV_DIR;
3727
3728 if (!_process_switches(&argc, &argv, dev_dir)) {
3729 fprintf(stderr, "Couldn't process command line.\n");
3730 goto out;
3731 }
3732
3733 if (_switches[HELP_ARG]) {
3734 cmd = _find_command("help");
3735 goto doit;
3736 }
3737
3738 if (_switches[VERSION_ARG]) {
3739 cmd = _find_command("version");
3740 goto doit;
3741 }
3742
3743 if (argc == 0) {
3744 _usage(stderr);
3745 goto out;
3746 }
3747
3748 if (!(cmd = _find_command(argv[0]))) {
3749 fprintf(stderr, "Unknown command\n");
3750 _usage(stderr);
3751 goto out;
3752 }
3753
3754 if (argc < cmd->min_args + 1 ||
3755 (cmd->max_args >= 0 && argc > cmd->max_args + 1)) {
3756 fprintf(stderr, "Incorrect number of arguments\n");
3757 _usage(stderr);
3758 goto out;
3759 }
3760
3761 if (!_switches[COLS_ARG] && !strcmp(cmd->name, "splitname"))
3762 _switches[COLS_ARG]++;
3763
3764 if (!strcmp(cmd->name, "mangle"))
3765 dm_set_name_mangling_mode(DM_STRING_MANGLING_NONE);
3766
3767 if (_switches[COLS_ARG]) {
3768 if (!_report_init(cmd))
3769 goto out;
3770 if (!_report) {
3771 if (!strcmp(cmd->name, "info"))
3772 r = 0; /* info -c -o help */
3773 goto out;
3774 }
3775 }
3776
3777 #ifdef UDEV_SYNC_SUPPORT
3778 if (!_set_up_udev_support(dev_dir))
3779 goto out;
3780 #endif
3781
3782 doit:
3783 multiple_devices = (cmd->repeatable_cmd && argc != 2 &&
3784 (argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG])));
3785 do {
3786 if (!cmd->fn(cmd, argc--, argv++, NULL, multiple_devices)) {
3787 fprintf(stderr, "Command failed\n");
3788 goto out;
3789 }
3790 } while (cmd->repeatable_cmd && argc > 1);
3791
3792 r = 0;
3793
3794 out:
3795 if (_report) {
3796 dm_report_output(_report);
3797 dm_report_free(_report);
3798 }
3799
3800 if (_dtree)
3801 dm_tree_free(_dtree);
3802
3803 dm_free(_table);
3804
3805 return r;
3806 }
This page took 0.20666 seconds and 5 git commands to generate.