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
6 * This file is part of the device-mapper userspace tools.
8 * It includes tree drawing code based on pstree: http://psmisc.sourceforge.net/
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.
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
20 #define _FILE_OFFSET_BITS 64
22 #include "configure.h"
24 #include "dm-logging.h"
36 #include <sys/param.h>
44 #ifdef UDEV_SYNC_SUPPORT
45 # include <sys/types.h>
51 /* FIXME Unused so far */
52 #undef HAVE_SYS_STATVFS_H
54 #ifdef HAVE_SYS_STATVFS_H
55 # include <sys/statvfs.h>
58 #ifdef HAVE_SYS_IOCTL_H
59 # include <sys/ioctl.h>
66 #ifdef HAVE_GETOPTLONG
68 # define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
69 # define OPTIND_INIT 0
75 # define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))
76 # define OPTIND_INIT 1
79 #ifndef TEMP_FAILURE_RETRY
80 # define TEMP_FAILURE_RETRY(expression) \
82 ({ long int __result; \
83 do __result = (long int) (expression); \
84 while (__result == -1L && errno == EINTR); \
91 # define MAJOR(x) major((x))
92 # define MINOR(x) minor((x))
93 # define MKDEV(x,y) makedev((x),(y))
96 #define LINE_SIZE 4096
98 #define LOOP_TABLE_SIZE (PATH_MAX + 255)
100 #define DEFAULT_DM_DEV_DIR "/dev/"
102 #define DM_DEV_DIR_ENV_VAR_NAME "DM_DEV_DIR"
103 #define DM_UDEV_COOKIE_ENV_VAR_NAME "DM_UDEV_COOKIE"
105 /* FIXME Should be imported */
106 #ifndef DM_MAX_TYPE_NAME
107 # define DM_MAX_TYPE_NAME 16
110 /* FIXME Should be elsewhere */
111 #define SECTOR_SHIFT 9L
113 #define err(msg, x...) fprintf(stderr, msg "\n", ##x)
116 * We have only very simple switches ATM.
120 ADD_NODE_ON_CREATE_ARG
,
121 ADD_NODE_ON_RESUME_ARG
,
168 DR_TREE
= 8, /* Complete dependency tree required */
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) */
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
;
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
;
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
);
207 int repeatable_cmd
; /* Repeat to process device list? */
211 static int _parse_line(struct dm_task
*dmt
, char *buffer
, const char *file
,
214 char ttype
[LINE_SIZE
], *ptr
, *comment
;
215 unsigned long long start
, size
;
218 /* trim trailing space */
219 for (ptr
= buffer
+ strlen(buffer
) - 1; ptr
>= buffer
; ptr
--)
220 if (!isspace((int) *ptr
))
225 /* trim leading space */
226 for (ptr
= buffer
; *ptr
&& isspace((int) *ptr
); ptr
++)
229 if (!*ptr
|| *ptr
== '#')
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
);
239 if ((comment
= strchr(ptr
, (int) '#')))
242 if (!dm_task_add_target(dmt
, start
, size
, ttype
, ptr
))
248 static int _parse_file(struct dm_task
*dmt
, const char *file
)
251 size_t buffer_size
= 0;
255 /* one-line table on cmdline */
257 return _parse_line(dmt
, _table
, "", ++line
);
259 /* OK for empty stdin */
261 if (!(fp
= fopen(file
, "r"))) {
262 err("Couldn't open '%s' for reading", file
);
269 buffer_size
= LINE_SIZE
;
270 if (!(buffer
= dm_malloc(buffer_size
))) {
271 err("Failed to malloc line buffer.");
275 while (fgets(buffer
, (int) buffer_size
, fp
))
277 while (getline(&buffer
, &buffer_size
, fp
) > 0)
279 if (!_parse_line(dmt
, buffer
, file
? : "on stdin", ++line
))
285 memset(buffer
, 0, buffer_size
);
291 if (file
&& fclose(fp
))
292 fprintf(stderr
, "%s: fclose failed: %s", file
, strerror(errno
));
297 struct dm_split_name
{
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
;
312 static struct dm_task
*_get_deps_task(int major
, int minor
)
317 if (!(dmt
= dm_task_create(DM_DEVICE_DEPS
)))
320 if (!dm_task_set_major(dmt
, major
) ||
321 !dm_task_set_minor(dmt
, minor
))
324 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
327 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
330 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
333 if (!dm_task_run(dmt
))
336 if (!dm_task_get_info(dmt
, &info
))
345 dm_task_destroy(dmt
);
349 static char *_extract_uuid_prefix(const char *uuid
, const int separator
)
352 char *uuid_prefix
= NULL
;
356 ptr
= strchr(uuid
, separator
);
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.");
365 memcpy(uuid_prefix
, uuid
, len
);
367 uuid_prefix
[len
] = '\0';
372 static struct dm_split_name
*_get_split_name(const char *uuid
, const char *name
,
375 struct dm_split_name
*split_name
;
377 if (!(split_name
= dm_malloc(sizeof(*split_name
)))) {
378 log_error("Failed to allocate memory to split device name "
383 if (!(split_name
->subsystem
= _extract_uuid_prefix(uuid
, separator
)))
386 split_name
->vg_name
= split_name
->lv_name
=
387 split_name
->lv_layer
= (char *) "";
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 "
399 static void _destroy_split_name(struct dm_split_name
*split_name
)
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.
405 if (!strcmp(split_name
->subsystem
, "LVM"))
406 dm_free(split_name
->vg_name
);
408 dm_free(split_name
->subsystem
);
412 static int _display_info_cols(struct dm_task
*dmt
, struct dm_info
*info
)
414 struct dmsetup_report_obj obj
;
418 fprintf(stderr
, "Device does not exist.\n");
424 obj
.deps_task
= NULL
;
425 obj
.split_name
= NULL
;
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
);
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
);
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
), '-')))
444 if (!dm_report_object(_report
, &obj
))
451 dm_task_destroy(obj
.deps_task
);
453 _destroy_split_name(obj
.split_name
);
457 static void _display_info_long(struct dm_task
*dmt
, struct dm_info
*info
)
463 printf("Device does not exist.\n");
467 printf("Name: %s\n", dm_task_get_name(dmt
));
469 printf("State: %s%s\n",
470 info
->suspended
? "SUSPENDED" : "ACTIVE",
471 info
->read_only
? " (READ-ONLY)" : "");
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
);
477 if (!info
->live_table
&& !info
->inactive_table
)
478 printf("Tables present: None\n");
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" : "");
485 if (info
->open_count
!= -1)
486 printf("Open count: %d\n", info
->open_count
);
488 printf("Event number: %" PRIu32
"\n", info
->event_nr
);
489 printf("Major, minor: %d, %d\n", info
->major
, info
->minor
);
491 if (info
->target_count
!= -1)
492 printf("Number of targets: %d\n", info
->target_count
);
494 if ((uuid
= dm_task_get_uuid(dmt
)) && *uuid
)
495 printf("UUID: %s\n", uuid
);
500 static int _display_info(struct dm_task
*dmt
)
504 if (!dm_task_get_info(dmt
, &info
))
507 if (!_switches
[COLS_ARG
])
508 _display_info_long(dmt
, &info
);
510 /* FIXME return code */
511 _display_info_cols(dmt
, &info
);
513 return info
.exists
? 1 : 0;
516 static int _set_task_device(struct dm_task
*dmt
, const char *name
, int optional
)
519 if (!dm_task_set_name(dmt
, name
))
521 } else if (_switches
[UUID_ARG
]) {
522 if (!dm_task_set_uuid(dmt
, _uuid
))
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
]))
528 } else if (!optional
) {
529 fprintf(stderr
, "No device specified.\n");
536 static int _set_task_add_node(struct dm_task
*dmt
)
538 if (!dm_task_set_add_node(dmt
, DEFAULT_DM_ADD_NODE
))
541 if (_switches
[ADD_NODE_ON_RESUME_ARG
] &&
542 !dm_task_set_add_node(dmt
, DM_ADD_NODE_ON_RESUME
))
545 if (_switches
[ADD_NODE_ON_CREATE_ARG
] &&
546 !dm_task_set_add_node(dmt
, DM_ADD_NODE_ON_CREATE
))
552 static int _load(CMD_ARGS
)
556 const char *file
= NULL
;
557 const char *name
= NULL
;
559 if (_switches
[NOTABLE_ARG
]) {
560 err("--notable only available when creating new device\n");
564 if (!_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
]) {
566 err("Please specify device.\n");
572 } else if (argc
> 2) {
573 err("Too many command line arguments.\n");
580 if (!(dmt
= dm_task_create(DM_DEVICE_RELOAD
)))
583 if (!_set_task_device(dmt
, name
, 0))
586 if (!_switches
[NOTABLE_ARG
] && !_parse_file(dmt
, file
))
589 if (_switches
[READ_ONLY
] && !dm_task_set_ro(dmt
))
592 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
595 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
598 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
601 if (!dm_task_run(dmt
))
606 if (_switches
[VERBOSE_ARG
])
607 r
= _display_info(dmt
);
610 dm_task_destroy(dmt
);
615 static int _create(CMD_ARGS
)
619 const char *file
= NULL
;
621 uint16_t udev_flags
= 0;
626 if (!(dmt
= dm_task_create(DM_DEVICE_CREATE
)))
629 if (!dm_task_set_name(dmt
, argv
[1]))
632 if (_switches
[UUID_ARG
] && !dm_task_set_uuid(dmt
, _uuid
))
635 if (!_switches
[NOTABLE_ARG
] && !_parse_file(dmt
, file
))
638 if (_switches
[READ_ONLY
] && !dm_task_set_ro(dmt
))
641 if (_switches
[MAJOR_ARG
] && !dm_task_set_major(dmt
, _int_args
[MAJOR_ARG
]))
644 if (_switches
[MINOR_ARG
] && !dm_task_set_minor(dmt
, _int_args
[MINOR_ARG
]))
647 if (_switches
[UID_ARG
] && !dm_task_set_uid(dmt
, _int_args
[UID_ARG
]))
650 if (_switches
[GID_ARG
] && !dm_task_set_gid(dmt
, _int_args
[GID_ARG
]))
653 if (_switches
[MODE_ARG
] && !dm_task_set_mode(dmt
, _int_args
[MODE_ARG
]))
656 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
659 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
662 if (_switches
[READAHEAD_ARG
] &&
663 !dm_task_set_read_ahead(dmt
, _int_args
[READAHEAD_ARG
],
667 if (_switches
[NOTABLE_ARG
])
668 dm_udev_set_sync_support(0);
670 if (_switches
[NOUDEVRULES_ARG
])
671 udev_flags
|= DM_UDEV_DISABLE_DM_RULES_FLAG
|
672 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG
;
674 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
677 if (!_set_task_add_node(dmt
))
681 cookie
= _udev_cookie
;
684 udev_flags
|= DM_UDEV_DISABLE_LIBRARY_FALLBACK
;
686 if (!dm_task_set_cookie(dmt
, &cookie
, udev_flags
) ||
694 (void) dm_udev_wait(cookie
);
696 if (r
&& _switches
[VERBOSE_ARG
])
697 r
= _display_info(dmt
);
699 dm_task_destroy(dmt
);
704 static int _do_rename(const char *name
, const char *new_name
, const char *new_uuid
) {
708 uint16_t udev_flags
= 0;
710 if (!(dmt
= dm_task_create(DM_DEVICE_RENAME
)))
713 /* FIXME Kernel doesn't support uuid or device number here yet */
714 if (!_set_task_device(dmt
, name
, 0))
718 if (!dm_task_set_newuuid(dmt
, new_uuid
))
720 } else if (!dm_task_set_newname(dmt
, new_name
))
723 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
726 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
729 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
732 if (_switches
[NOUDEVRULES_ARG
])
733 udev_flags
|= DM_UDEV_DISABLE_DM_RULES_FLAG
|
734 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG
;
737 cookie
= _udev_cookie
;
740 udev_flags
|= DM_UDEV_DISABLE_LIBRARY_FALLBACK
;
742 if (!dm_task_set_cookie(dmt
, &cookie
, udev_flags
) ||
750 (void) dm_udev_wait(cookie
);
752 dm_task_destroy(dmt
);
757 static int _rename(CMD_ARGS
)
759 const char *name
= (argc
== 3) ? argv
[1] : NULL
;
761 return _switches
[SETUUID_ARG
] ? _do_rename(name
, NULL
, argv
[argc
- 1]) :
762 _do_rename(name
, argv
[argc
- 1], NULL
);
766 static int _message(CMD_ARGS
)
773 if (!(dmt
= dm_task_create(DM_DEVICE_TARGET_MSG
)))
776 if (_switches
[UUID_ARG
] || _switches
[MAJOR_ARG
]) {
777 if (!_set_task_device(dmt
, NULL
, 0))
780 if (!_set_task_device(dmt
, argv
[1], 0))
786 if (!dm_task_set_sector(dmt
, (uint64_t) atoll(argv
[1])))
793 err("No message supplied.\n");
795 for (i
= 0; i
< argc
; i
++)
796 sz
+= strlen(argv
[i
]) + 1;
798 if (!(str
= dm_zalloc(sz
))) {
799 err("message string allocation failed");
803 for (i
= 0; i
< argc
; i
++) {
806 strcat(str
, argv
[i
]);
809 i
= dm_task_set_message(dmt
, str
);
816 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
819 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
822 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
825 if (!dm_task_run(dmt
))
831 dm_task_destroy(dmt
);
836 static int _setgeometry(CMD_ARGS
)
841 if (!(dmt
= dm_task_create(DM_DEVICE_SET_GEOMETRY
)))
844 if (_switches
[UUID_ARG
] || _switches
[MAJOR_ARG
]) {
845 if (!_set_task_device(dmt
, NULL
, 0))
848 if (!_set_task_device(dmt
, argv
[1], 0))
854 if (!dm_task_set_geometry(dmt
, argv
[1], argv
[2], argv
[3], argv
[4]))
857 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
860 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
863 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
867 if (!dm_task_run(dmt
))
873 dm_task_destroy(dmt
);
878 static int _splitname(CMD_ARGS
)
880 struct dmsetup_report_obj obj
;
885 obj
.deps_task
= NULL
;
886 obj
.tree_node
= NULL
;
887 if (!(obj
.split_name
= _get_split_name((argc
== 3) ? argv
[2] : "LVM",
891 r
= dm_report_object(_report
, &obj
);
892 _destroy_split_name(obj
.split_name
);
897 static uint32_t _get_cookie_value(const char *str_value
)
899 unsigned long int value
;
902 if (!(value
= strtoul(str_value
, &p
, 0)) ||
904 (value
== ULONG_MAX
&& errno
== ERANGE
) ||
905 value
> 0xFFFFFFFF) {
906 err("Incorrect cookie value");
910 return (uint32_t) value
;
913 static int _udevflags(CMD_ARGS
)
918 static const char *dm_flag_names
[] = {"DISABLE_DM_RULES",
919 "DISABLE_SUBSYSTEM_RULES",
920 "DISABLE_DISK_RULES",
921 "DISABLE_OTHER_RULES",
923 "DISABLE_LIBRARY_FALLBACK",
927 if (!(cookie
= _get_cookie_value(argv
[1])))
930 flags
= cookie
>> DM_UDEV_FLAGS_SHIFT
;
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)
938 * This is just a fallback. Each new DM flag
939 * should have its symbolic name assigned.
941 printf("DM_UDEV_FLAG%d='1'\n", i
);
944 * We can't assign symbolic names to subsystem
945 * flags. Their semantics vary based on the
946 * subsystem that is currently used.
948 printf("DM_SUBSYSTEM_UDEV_FLAG%d='1'\n",
949 i
- DM_UDEV_FLAGS_SHIFT
/ 2);
955 static int _udevcomplete(CMD_ARGS
)
959 if (!(cookie
= _get_cookie_value(argv
[1])))
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
969 if (!(cookie
&= ~DM_UDEV_FLAGS_MASK
))
972 cookie
|= DM_COOKIE_MAGIC
<< DM_UDEV_FLAGS_SHIFT
;
974 return dm_udev_complete(cookie
);
977 #ifndef UDEV_SYNC_SUPPORT
978 static const char _cmd_not_supported
[] = "Command not supported. Recompile with \"--enable-udev-sync\" to enable.";
980 static int _udevcreatecookie(CMD_ARGS
)
982 log_error(_cmd_not_supported
);
987 static int _udevreleasecookie(CMD_ARGS
)
989 log_error(_cmd_not_supported
);
994 static int _udevcomplete_all(CMD_ARGS
)
996 log_error(_cmd_not_supported
);
1001 static int _udevcookies(CMD_ARGS
)
1003 log_error(_cmd_not_supported
);
1008 #else /* UDEV_SYNC_SUPPORT */
1009 static int _set_up_udev_support(const char *dev_dir
)
1012 const char *udev_dev_dir
;
1013 size_t udev_dev_dir_len
;
1017 if (_switches
[NOUDEVSYNC_ARG
])
1018 dm_udev_set_sync_support(0);
1020 if (!_udev_cookie
) {
1021 env
= getenv(DM_UDEV_COOKIE_ENV_VAR_NAME
);
1022 if (env
&& *env
&& (_udev_cookie
= _get_cookie_value(env
)))
1023 log_debug("Using udev transaction 0x%08" PRIX32
1024 " defined by %s environment variable.",
1026 DM_UDEV_COOKIE_ENV_VAR_NAME
);
1028 else if (_switches
[UDEVCOOKIE_ARG
])
1029 log_debug("Using udev transaction 0x%08" PRIX32
1030 " defined by --udevcookie option.",
1033 if (!(udev
= udev_new()) ||
1034 !(udev_dev_dir
= udev_get_dev_path(udev
)) ||
1036 log_error("Could not get udev dev path.");
1039 udev_dev_dir_len
= strlen(udev_dev_dir
);
1042 * Normally, there's always a fallback action by libdevmapper if udev
1043 * has not done its job correctly, e.g. the nodes were not created.
1044 * If using udev transactions by specifying existing cookie value,
1045 * we need to disable node creation by libdevmapper completely,
1046 * disabling any fallback actions, since any synchronisation happens
1047 * at the end of the transaction only. We need to do this to prevent
1048 * races between udev and libdevmapper but only in case udev "dev path"
1049 * is the same as "dev path" used by libdevmapper.
1052 /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */
1053 if (udev_dev_dir
[udev_dev_dir_len
- 1] != '/')
1054 dirs_diff
= strncmp(dev_dir
, udev_dev_dir
, udev_dev_dir_len
);
1056 dirs_diff
= strcmp(dev_dir
, udev_dev_dir
);
1058 _udev_only
= !dirs_diff
&& (_udev_cookie
|| !_switches
[VERIFYUDEV_ARG
]);
1061 log_debug("The path %s used for creating device nodes that is "
1062 "set via DM_DEV_DIR environment variable differs from "
1063 "the path %s that is used by udev. All warnings "
1064 "about udev not working correctly while processing "
1065 "particular nodes will be suppressed. These nodes "
1066 "and symlinks will be managed in each directory "
1067 "separately.", dev_dir
, udev_dev_dir
);
1068 dm_udev_set_checking(0);
1075 static int _udevcreatecookie(CMD_ARGS
)
1079 if (!dm_udev_create_cookie(&cookie
))
1083 printf("0x%08" PRIX32
"\n", cookie
);
1088 static int _udevreleasecookie(CMD_ARGS
)
1090 if (argv
[1] && !(_udev_cookie
= _get_cookie_value(argv
[1])))
1093 if (!_udev_cookie
) {
1094 log_error("No udev transaction cookie given.");
1098 return dm_udev_wait(_udev_cookie
);
1101 __attribute__((format(printf
, 1, 2)))
1102 static char _yes_no_prompt(const char *prompt
, ...)
1108 if (c
== '\n' || !c
) {
1109 va_start(ap
, prompt
);
1110 vprintf(prompt
, ap
);
1114 if ((c
= getchar()) == EOF
) {
1120 if ((c
== 'y') || (c
== 'n'))
1122 } while (!ret
|| c
!= '\n');
1130 static int _udevcomplete_all(CMD_ARGS
)
1132 int max_id
, id
, sid
;
1133 struct seminfo sinfo
;
1134 struct semid_ds sdata
;
1140 if (argc
== 2 && (sscanf(argv
[1], "%i", &age
) != 1)) {
1141 log_error("Failed to read age_in_minutes parameter.");
1145 if (!_switches
[YES_ARG
]) {
1146 log_warn("This operation will destroy all semaphores %s%.0d%swith keys "
1147 "that have a prefix %" PRIu16
" (0x%" PRIx16
").",
1148 age
? "older than " : "", age
, age
? " minutes " : "",
1149 DM_COOKIE_MAGIC
, DM_COOKIE_MAGIC
);
1151 if (_yes_no_prompt("Do you really want to continue? [y/n]: ") == 'n') {
1152 log_print("Semaphores with keys prefixed by %" PRIu16
1153 " (0x%" PRIx16
") NOT destroyed.",
1154 DM_COOKIE_MAGIC
, DM_COOKIE_MAGIC
);
1159 if ((max_id
= semctl(0, 0, SEM_INFO
, &sinfo
)) < 0) {
1160 log_sys_error("semctl", "SEM_INFO");
1164 for (id
= 0; id
<= max_id
; id
++) {
1165 if ((sid
= semctl(id
, 0, SEM_STAT
, &sdata
)) < 0)
1168 if (sdata
.sem_perm
.__key
>> 16 == DM_COOKIE_MAGIC
) {
1171 if (sdata
.sem_ctime
+ age
* 60 > t
||
1172 sdata
.sem_otime
+ age
* 60 > t
) {
1176 if (semctl(sid
, 0, IPC_RMID
, 0) < 0) {
1177 log_error("Could not cleanup notification semaphore "
1178 "with semid %d and cookie value "
1179 "%" PRIu32
" (0x%" PRIx32
")", sid
,
1180 sdata
.sem_perm
.__key
, sdata
.sem_perm
.__key
);
1188 log_print("%d semaphores with keys prefixed by "
1189 "%" PRIu16
" (0x%" PRIx16
") destroyed. %d skipped.",
1190 counter
, DM_COOKIE_MAGIC
, DM_COOKIE_MAGIC
, skipped
);
1195 static int _udevcookies(CMD_ARGS
)
1197 int max_id
, id
, sid
;
1198 struct seminfo sinfo
;
1199 struct semid_ds sdata
;
1201 char otime_str
[26], ctime_str
[26];
1202 char *otimes
, *ctimes
;
1204 if ((max_id
= semctl(0, 0, SEM_INFO
, &sinfo
)) < 0) {
1205 log_sys_error("sem_ctl", "SEM_INFO");
1209 printf("Cookie Semid Value Last semop time Last change time\n");
1211 for (id
= 0; id
<= max_id
; id
++) {
1212 if ((sid
= semctl(id
, 0, SEM_STAT
, &sdata
)) < 0)
1215 if (sdata
.sem_perm
.__key
>> 16 == DM_COOKIE_MAGIC
) {
1216 if ((val
= semctl(sid
, 0, GETVAL
)) < 0) {
1217 log_error("semid %d: sem_ctl failed for "
1218 "cookie 0x%" PRIx32
": %s",
1219 sid
, sdata
.sem_perm
.__key
,
1224 if ((otimes
= ctime_r((const time_t *) &sdata
.sem_otime
, (char *)&otime_str
)))
1225 otime_str
[strlen(otimes
)-1] = '\0';
1226 if ((ctimes
= ctime_r((const time_t *) &sdata
.sem_ctime
, (char *)&ctime_str
)))
1227 ctime_str
[strlen(ctimes
)-1] = '\0';
1229 printf("0x%-10x %-10d %-10d %s %s\n", sdata
.sem_perm
.__key
,
1230 sid
, val
, otimes
? : "unknown",
1231 ctimes
? : "unknown");
1237 #endif /* UDEV_SYNC_SUPPORT */
1239 static int _version(CMD_ARGS
)
1243 if (dm_get_library_version(version
, sizeof(version
)))
1244 printf("Library version: %s\n", version
);
1246 if (!dm_driver_version(version
, sizeof(version
)))
1249 printf("Driver version: %s\n", version
);
1254 static int _simple(int task
, const char *name
, uint32_t event_nr
, int display
)
1256 uint32_t cookie
= 0;
1257 uint16_t udev_flags
= 0;
1258 int udev_wait_flag
= task
== DM_DEVICE_RESUME
||
1259 task
== DM_DEVICE_REMOVE
;
1262 struct dm_task
*dmt
;
1264 if (!(dmt
= dm_task_create(task
)))
1267 if (!_set_task_device(dmt
, name
, 0))
1270 if (event_nr
&& !dm_task_set_event_nr(dmt
, event_nr
))
1273 if (_switches
[NOFLUSH_ARG
] && !dm_task_no_flush(dmt
))
1276 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1279 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1282 if (_switches
[NOLOCKFS_ARG
] && !dm_task_skip_lockfs(dmt
))
1285 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1288 /* FIXME: needs to coperate with udev */
1289 if (!_set_task_add_node(dmt
))
1292 if (_switches
[READAHEAD_ARG
] &&
1293 !dm_task_set_read_ahead(dmt
, _int_args
[READAHEAD_ARG
],
1297 if (_switches
[NOUDEVRULES_ARG
])
1298 udev_flags
|= DM_UDEV_DISABLE_DM_RULES_FLAG
|
1299 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG
;
1302 cookie
= _udev_cookie
;
1305 udev_flags
|= DM_UDEV_DISABLE_LIBRARY_FALLBACK
;
1307 if (udev_wait_flag
&& !dm_task_set_cookie(dmt
, &cookie
, udev_flags
))
1310 if (_switches
[RETRY_ARG
] && task
== DM_DEVICE_REMOVE
)
1311 dm_task_retry_remove(dmt
);
1313 r
= dm_task_run(dmt
);
1316 if (!_udev_cookie
&& udev_wait_flag
)
1317 (void) dm_udev_wait(cookie
);
1319 if (r
&& display
&& _switches
[VERBOSE_ARG
])
1320 r
= _display_info(dmt
);
1322 dm_task_destroy(dmt
);
1327 static int _suspend(CMD_ARGS
)
1329 return _simple(DM_DEVICE_SUSPEND
, argc
> 1 ? argv
[1] : NULL
, 0, 1);
1332 static int _resume(CMD_ARGS
)
1334 return _simple(DM_DEVICE_RESUME
, argc
> 1 ? argv
[1] : NULL
, 0, 1);
1337 static int _clear(CMD_ARGS
)
1339 return _simple(DM_DEVICE_CLEAR
, argc
> 1 ? argv
[1] : NULL
, 0, 1);
1342 static int _wait(CMD_ARGS
)
1344 const char *name
= NULL
;
1346 if (!_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
]) {
1348 err("No device specified.");
1355 return _simple(DM_DEVICE_WAITEVENT
, name
,
1356 (argc
> 1) ? (uint32_t) atoi(argv
[argc
- 1]) : 0, 1);
1359 static int _process_all(const struct command
*cmd
, int argc
, char **argv
, int silent
,
1360 int (*fn
) (CMD_ARGS
))
1363 struct dm_names
*names
;
1366 struct dm_task
*dmt
;
1368 if (!(dmt
= dm_task_create(DM_DEVICE_LIST
)))
1371 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1374 if (!dm_task_run(dmt
)) {
1379 if (!(names
= dm_task_get_names(dmt
))) {
1386 printf("No devices found\n");
1391 names
= (struct dm_names
*)((char *) names
+ next
);
1392 if (!fn(cmd
, argc
, argv
, names
, 1))
1398 dm_task_destroy(dmt
);
1402 static uint64_t _get_device_size(const char *name
)
1404 uint64_t start
, length
, size
= UINT64_C(0);
1405 struct dm_info info
;
1406 char *target_type
, *params
;
1407 struct dm_task
*dmt
;
1410 if (!(dmt
= dm_task_create(DM_DEVICE_TABLE
)))
1413 if (!_set_task_device(dmt
, name
, 0))
1416 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1419 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1422 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1425 if (!dm_task_run(dmt
))
1428 if (!dm_task_get_info(dmt
, &info
) || !info
.exists
)
1432 next
= dm_get_next_target(dmt
, next
, &start
, &length
,
1433 &target_type
, ¶ms
);
1438 dm_task_destroy(dmt
);
1442 static int _error_device(CMD_ARGS
)
1444 struct dm_task
*dmt
;
1449 name
= names
? names
->name
: argv
[1];
1451 size
= _get_device_size(name
);
1453 if (!(dmt
= dm_task_create(DM_DEVICE_RELOAD
)))
1456 if (!_set_task_device(dmt
, name
, 0))
1459 if (!dm_task_add_target(dmt
, UINT64_C(0), size
, "error", ""))
1462 if (_switches
[READ_ONLY
] && !dm_task_set_ro(dmt
))
1465 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1468 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1471 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1474 if (!dm_task_run(dmt
))
1477 if (!_simple(DM_DEVICE_RESUME
, name
, 0, 0)) {
1478 _simple(DM_DEVICE_CLEAR
, name
, 0, 0);
1485 dm_task_destroy(dmt
);
1489 static int _remove(CMD_ARGS
)
1491 if (_switches
[FORCE_ARG
] && argc
> 1)
1492 (void) _error_device(cmd
, argc
, argv
, NULL
, 0);
1494 return _simple(DM_DEVICE_REMOVE
, argc
> 1 ? argv
[1] : NULL
, 0, 0);
1497 static int _count_devices(CMD_ARGS
)
1504 static int _remove_all(CMD_ARGS
)
1508 /* Remove all closed devices */
1509 r
= _simple(DM_DEVICE_REMOVE_ALL
, "", 0, 0) | dm_mknodes(NULL
);
1511 if (!_switches
[FORCE_ARG
])
1515 r
|= _process_all(cmd
, argc
, argv
, 1, _count_devices
);
1517 /* No devices left? */
1521 r
|= _process_all(cmd
, argc
, argv
, 1, _error_device
);
1522 r
|= _simple(DM_DEVICE_REMOVE_ALL
, "", 0, 0) | dm_mknodes(NULL
);
1525 r
|= _process_all(cmd
, argc
, argv
, 1, _count_devices
);
1529 fprintf(stderr
, "Unable to remove %d device(s).\n", _num_devices
);
1534 static void _display_dev(struct dm_task
*dmt
, const char *name
)
1536 struct dm_info info
;
1538 if (dm_task_get_info(dmt
, &info
))
1539 printf("%s\t(%u, %u)\n", name
, info
.major
, info
.minor
);
1542 static int _mknodes(CMD_ARGS
)
1544 return dm_mknodes(argc
> 1 ? argv
[1] : NULL
);
1547 static int _exec_command(const char *name
)
1550 static char path
[PATH_MAX
];
1551 static char *args
[ARGS_MAX
+ 1];
1552 static int argc
= 0;
1559 if (!dm_mknodes(name
))
1562 n
= snprintf(path
, sizeof(path
), "%s/%s", dm_dir(), name
);
1563 if (n
< 0 || n
> (int) sizeof(path
) - 1)
1568 while (argc
< ARGS_MAX
) {
1569 while (*c
&& isspace(*c
))
1574 while (*c
&& !isspace(*c
))
1585 if (argc
== ARGS_MAX
) {
1586 err("Too many args to --exec\n");
1591 args
[argc
++] = path
;
1595 if (!(pid
= fork())) {
1596 execvp(args
[0], args
);
1598 } else if (pid
< (pid_t
) 0)
1601 TEMP_FAILURE_RETRY(waitpid(pid
, NULL
, 0));
1606 static int _status(CMD_ARGS
)
1609 struct dm_task
*dmt
;
1611 uint64_t start
, length
;
1612 char *target_type
= NULL
;
1615 const char *name
= NULL
;
1618 struct dm_info info
;
1623 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
1624 return _process_all(cmd
, argc
, argv
, 0, _status
);
1628 if (!strcmp(cmd
->name
, "table"))
1629 cmdno
= DM_DEVICE_TABLE
;
1631 cmdno
= DM_DEVICE_STATUS
;
1633 if (!strcmp(cmd
->name
, "ls"))
1636 if (!(dmt
= dm_task_create(cmdno
)))
1639 if (!_set_task_device(dmt
, name
, 0))
1642 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1645 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1648 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1651 if (!dm_task_run(dmt
))
1654 if (!dm_task_get_info(dmt
, &info
) || !info
.exists
)
1658 name
= dm_task_get_name(dmt
);
1660 /* Fetch targets and print 'em */
1662 next
= dm_get_next_target(dmt
, next
, &start
, &length
,
1663 &target_type
, ¶ms
);
1664 /* Skip if target type doesn't match */
1665 if (_switches
[TARGET_ARG
] &&
1666 (!target_type
|| strcmp(target_type
, _target
)))
1669 if (!_switches
[EXEC_ARG
] || !_command
||
1670 _switches
[VERBOSE_ARG
])
1671 _display_dev(dmt
, name
);
1673 } else if (!_switches
[EXEC_ARG
] || !_command
||
1674 _switches
[VERBOSE_ARG
]) {
1675 if (!matched
&& _switches
[VERBOSE_ARG
])
1677 if (multiple_devices
&& !_switches
[VERBOSE_ARG
])
1678 printf("%s: ", name
);
1680 /* Suppress encryption key */
1681 if (!_switches
[SHOWKEYS_ARG
] &&
1682 cmdno
== DM_DEVICE_TABLE
&&
1683 !strcmp(target_type
, "crypt")) {
1685 while (*c
&& *c
!= ' ')
1689 while (*c
&& *c
!= ' ')
1692 printf("%" PRIu64
" %" PRIu64
" %s %s",
1693 start
, length
, target_type
, params
);
1700 if (multiple_devices
&& _switches
[VERBOSE_ARG
] && matched
&& !ls_only
)
1703 if (matched
&& _switches
[EXEC_ARG
] && _command
&& !_exec_command(name
))
1709 dm_task_destroy(dmt
);
1713 /* Show target names and their version numbers */
1714 static int _targets(CMD_ARGS
)
1717 struct dm_task
*dmt
;
1718 struct dm_versions
*target
;
1719 struct dm_versions
*last_target
;
1721 if (!(dmt
= dm_task_create(DM_DEVICE_LIST_VERSIONS
)))
1724 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1727 if (!dm_task_run(dmt
))
1730 target
= dm_task_get_versions(dmt
);
1732 /* Fetch targets and print 'em */
1734 last_target
= target
;
1736 printf("%-16s v%d.%d.%d\n", target
->name
, target
->version
[0],
1737 target
->version
[1], target
->version
[2]);
1739 target
= (struct dm_versions
*)((char *) target
+ target
->next
);
1740 } while (last_target
!= target
);
1745 dm_task_destroy(dmt
);
1749 static int _info(CMD_ARGS
)
1753 struct dm_task
*dmt
;
1759 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
1760 return _process_all(cmd
, argc
, argv
, 0, _info
);
1764 if (!(dmt
= dm_task_create(DM_DEVICE_INFO
)))
1767 if (!_set_task_device(dmt
, name
, 0))
1770 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1773 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1776 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1779 if (!dm_task_run(dmt
))
1782 r
= _display_info(dmt
);
1785 dm_task_destroy(dmt
);
1789 static int _deps(CMD_ARGS
)
1793 struct dm_deps
*deps
;
1794 struct dm_task
*dmt
;
1795 struct dm_info info
;
1797 char dev_name
[PATH_MAX
];
1803 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
1804 return _process_all(cmd
, argc
, argv
, 0, _deps
);
1808 if (!(dmt
= dm_task_create(DM_DEVICE_DEPS
)))
1811 if (!_set_task_device(dmt
, name
, 0))
1814 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1817 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1820 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1823 if (!dm_task_run(dmt
))
1826 if (!dm_task_get_info(dmt
, &info
))
1829 if (!(deps
= dm_task_get_deps(dmt
)))
1833 printf("Device does not exist.\n");
1838 if (_switches
[VERBOSE_ARG
])
1841 if (multiple_devices
&& !_switches
[VERBOSE_ARG
])
1842 printf("%s: ", name
);
1843 printf("%d dependencies\t:", deps
->count
);
1845 for (i
= 0; i
< deps
->count
; i
++) {
1846 major
= (int) MAJOR(deps
->device
[i
]);
1847 minor
= (int) MINOR(deps
->device
[i
]);
1849 if ((_dev_name_type
== DN_BLK
|| _dev_name_type
== DN_MAP
) &&
1850 dm_device_get_name(major
, minor
, _dev_name_type
== DN_BLK
,
1851 dev_name
, PATH_MAX
))
1852 printf(" (%s)", dev_name
);
1854 printf(" (%d, %d)", major
, minor
);
1858 if (multiple_devices
&& _switches
[VERBOSE_ARG
])
1864 dm_task_destroy(dmt
);
1868 static int _display_name(CMD_ARGS
)
1870 char dev_name
[PATH_MAX
];
1875 if ((_dev_name_type
== DN_BLK
|| _dev_name_type
== DN_MAP
) &&
1876 dm_device_get_name((int) MAJOR(names
->dev
), (int) MINOR(names
->dev
),
1877 _dev_name_type
== DN_BLK
, dev_name
, PATH_MAX
))
1878 printf("%s\t(%s)\n", names
->name
, dev_name
);
1880 printf("%s\t(%d:%d)\n", names
->name
,
1881 (int) MAJOR(names
->dev
),
1882 (int) MINOR(names
->dev
));
1892 TR_DEVICE
=0, /* display device major:minor number */
1893 TR_BLKDEVNAME
, /* display device kernel name */
1906 static int _tree_switches
[NUM_TREEMODE
];
1908 #define TR_PRINT_ATTRIBUTE ( _tree_switches[TR_ACTIVE] || \
1909 _tree_switches[TR_RW] || \
1910 _tree_switches[TR_OPENCOUNT] || \
1911 _tree_switches[TR_UUID] )
1913 #define TR_PRINT_TARGETS ( _tree_switches[TR_TABLE] || \
1914 _tree_switches[TR_STATUS] )
1916 /* Compact - fewer newlines */
1917 #define TR_PRINT_COMPACT (_tree_switches[TR_COMPACT] && \
1918 !TR_PRINT_ATTRIBUTE && \
1921 /* FIXME Get rid of this */
1922 #define MAX_DEPTH 100
1924 /* Drawing character definition from pstree */
1925 /* [pstree comment] UTF-8 defines by Johan Myreen, updated by Ben Winslow */
1926 #define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */
1927 #define UTF_VR "\342\224\234" /* U+251C, Vertical and right */
1928 #define UTF_H "\342\224\200" /* U+2500, Horizontal */
1929 #define UTF_UR "\342\224\224" /* U+2514, Up and right */
1930 #define UTF_HD "\342\224\254" /* U+252C, Horizontal and down */
1932 #define VT_BEG "\033(0\017" /* use graphic chars */
1933 #define VT_END "\033(B" /* back to normal char set */
1934 #define VT_V "x" /* see UTF definitions above */
1941 const char *empty_2
; /* */
1942 const char *branch_2
; /* |- */
1943 const char *vert_2
; /* | */
1944 const char *last_2
; /* `- */
1945 const char *single_3
; /* --- */
1946 const char *first_3
; /* -+- */
1966 VT_BEG VT_VR VT_H VT_END
,
1967 VT_BEG VT_V VT_END
" ",
1968 VT_BEG VT_UR VT_H VT_END
,
1969 VT_BEG VT_H VT_H VT_H VT_END
,
1970 VT_BEG VT_H VT_HD VT_H VT_END
1972 *_tsym
= &_tsym_ascii
;
1975 * Tree drawing functions.
1977 /* FIXME Get rid of these statics - use dynamic struct */
1978 /* FIXME Explain what these vars are for */
1979 static int _tree_width
[MAX_DEPTH
], _tree_more
[MAX_DEPTH
];
1980 static int _termwidth
= 80; /* Maximum output width */
1981 static int _cur_x
= 1; /* Current horizontal output position */
1982 static char _last_char
= 0;
1984 static void _out_char(const unsigned c
)
1986 /* Only first UTF-8 char counts */
1987 _cur_x
+= ((c
& 0xc0) != 0x80);
1989 if (!_tree_switches
[TR_TRUNCATE
]) {
1995 if (_cur_x
<= _termwidth
)
1998 if (_cur_x
== _termwidth
+ 1 && ((c
& 0xc0) != 0x80)) {
1999 if (_last_char
|| (c
& 0x80)) {
2010 static void _out_string(const char *str
)
2013 _out_char((unsigned char) *str
++);
2016 /* non-negative integers only */
2017 static unsigned _out_int(unsigned num
)
2019 unsigned digits
= 0;
2028 for (divi
= 1; num
/ divi
; divi
*= 10)
2031 for (divi
/= 10; divi
; divi
/= 10)
2032 _out_char('0' + (num
/ divi
) % 10);
2037 static void _out_newline(void)
2039 if (_last_char
&& _cur_x
== _termwidth
)
2040 putchar(_last_char
);
2046 static void _out_prefix(unsigned depth
)
2050 for (d
= 0; d
< depth
; d
++) {
2051 for (x
= _tree_width
[d
] + 1; x
> 0; x
--)
2054 _out_string(d
== depth
- 1 ?
2055 !_tree_more
[depth
] ? _tsym
->last_2
: _tsym
->branch_2
2056 : _tree_more
[d
+ 1] ?
2057 _tsym
->vert_2
: _tsym
->empty_2
);
2064 static void _display_tree_attributes(struct dm_tree_node
*node
)
2068 const struct dm_info
*info
;
2070 uuid
= dm_tree_node_get_uuid(node
);
2071 info
= dm_tree_node_get_info(node
);
2076 if (_tree_switches
[TR_ACTIVE
]) {
2077 _out_string(attr
++ ? ", " : " [");
2078 _out_string(info
->suspended
? "SUSPENDED" : "ACTIVE");
2081 if (_tree_switches
[TR_RW
]) {
2082 _out_string(attr
++ ? ", " : " [");
2083 _out_string(info
->read_only
? "RO" : "RW");
2086 if (_tree_switches
[TR_OPENCOUNT
]) {
2087 _out_string(attr
++ ? ", " : " [");
2088 (void) _out_int((unsigned) info
->open_count
);
2091 if (_tree_switches
[TR_UUID
]) {
2092 _out_string(attr
++ ? ", " : " [");
2093 _out_string(uuid
&& *uuid
? uuid
: "");
2100 /* FIXME Display table or status line. (Disallow both?) */
2101 static void _display_tree_targets(struct dm_tree_node
*node
, unsigned depth
)
2105 static void _display_tree_node(struct dm_tree_node
*node
, unsigned depth
,
2106 unsigned first_child
__attribute__((unused
)),
2107 unsigned last_child
, unsigned has_children
)
2111 const struct dm_info
*info
;
2112 int first_on_line
= 0;
2113 char dev_name
[PATH_MAX
];
2115 /* Sub-tree for targets has 2 more depth */
2116 if (depth
+ 2 > MAX_DEPTH
)
2119 name
= dm_tree_node_get_name(node
);
2121 if ((!name
|| !*name
) &&
2122 (!_tree_switches
[TR_DEVICE
] && !_tree_switches
[TR_BLKDEVNAME
]))
2125 /* Indicate whether there are more nodes at this depth */
2126 _tree_more
[depth
] = !last_child
;
2127 _tree_width
[depth
] = 0;
2132 if (!TR_PRINT_COMPACT
|| first_on_line
)
2135 /* Remember the starting point for compact */
2138 if (TR_PRINT_COMPACT
&& !first_on_line
)
2139 _out_string(_tree_more
[depth
] ? _tsym
->first_3
: _tsym
->single_3
);
2145 info
= dm_tree_node_get_info(node
);
2147 if (_tree_switches
[TR_BLKDEVNAME
] &&
2148 dm_device_get_name(info
->major
, info
->minor
, 1, dev_name
, PATH_MAX
)) {
2149 _out_string(name
? " <" : "<");
2150 _out_string(dev_name
);
2154 if (_tree_switches
[TR_DEVICE
]) {
2155 _out_string(name
? " (" : "(");
2156 (void) _out_int(info
->major
);
2158 (void) _out_int(info
->minor
);
2162 /* display additional info */
2163 if (TR_PRINT_ATTRIBUTE
)
2164 _display_tree_attributes(node
);
2166 if (TR_PRINT_COMPACT
)
2167 _tree_width
[depth
] = _cur_x
- offset
;
2169 if (!TR_PRINT_COMPACT
|| !has_children
)
2172 if (TR_PRINT_TARGETS
) {
2173 _tree_more
[depth
+ 1] = has_children
;
2174 _display_tree_targets(node
, depth
+ 2);
2179 * Walk the dependency tree
2181 static void _display_tree_walk_children(struct dm_tree_node
*node
,
2184 struct dm_tree_node
*child
, *next_child
;
2185 void *handle
= NULL
;
2186 uint32_t inverted
= _tree_switches
[TR_BOTTOMUP
];
2187 unsigned first_child
= 1;
2188 unsigned has_children
;
2190 next_child
= dm_tree_next_child(&handle
, node
, inverted
);
2192 while ((child
= next_child
)) {
2193 next_child
= dm_tree_next_child(&handle
, node
, inverted
);
2195 dm_tree_node_num_children(child
, inverted
) ? 1 : 0;
2197 _display_tree_node(child
, depth
, first_child
,
2198 next_child
? 0U : 1U, has_children
);
2201 _display_tree_walk_children(child
, depth
+ 1);
2207 static int _add_dep(CMD_ARGS
)
2210 !dm_tree_add_dev(_dtree
, (unsigned) MAJOR(names
->dev
), (unsigned) MINOR(names
->dev
)))
2217 * Create and walk dependency tree
2219 static int _build_whole_deptree(const struct command
*cmd
)
2224 if (!(_dtree
= dm_tree_create()))
2227 if (!_process_all(cmd
, 0, NULL
, 0, _add_dep
))
2233 static int _display_tree(CMD_ARGS
)
2235 if (!_build_whole_deptree(cmd
))
2238 _display_tree_walk_children(dm_tree_find_node(_dtree
, 0, 0), 0);
2244 * Report device information
2247 /* dm specific display functions */
2249 static int _int32_disp(struct dm_report
*rh
,
2250 struct dm_pool
*mem
__attribute__((unused
)),
2251 struct dm_report_field
*field
, const void *data
,
2252 void *private __attribute__((unused
)))
2254 const int32_t value
= *(const int32_t *)data
;
2256 return dm_report_field_int32(rh
, field
, &value
);
2259 static int _uint32_disp(struct dm_report
*rh
,
2260 struct dm_pool
*mem
__attribute__((unused
)),
2261 struct dm_report_field
*field
, const void *data
,
2262 void *private __attribute__((unused
)))
2264 const uint32_t value
= *(const int32_t *)data
;
2266 return dm_report_field_uint32(rh
, field
, &value
);
2269 static int _dm_name_disp(struct dm_report
*rh
,
2270 struct dm_pool
*mem
__attribute__((unused
)),
2271 struct dm_report_field
*field
, const void *data
,
2272 void *private __attribute__((unused
)))
2274 const char *name
= dm_task_get_name((const struct dm_task
*) data
);
2276 return dm_report_field_string(rh
, field
, &name
);
2279 static int _dm_mangled_name_disp(struct dm_report
*rh
,
2280 struct dm_pool
*mem
__attribute__((unused
)),
2281 struct dm_report_field
*field
, const void *data
,
2282 void *private __attribute__((unused
)))
2287 if ((name
= dm_task_get_name_mangled((const struct dm_task
*) data
))) {
2288 r
= dm_report_field_string(rh
, field
, (const char **) &name
);
2295 static int _dm_unmangled_name_disp(struct dm_report
*rh
,
2296 struct dm_pool
*mem
__attribute__((unused
)),
2297 struct dm_report_field
*field
, const void *data
,
2298 void *private __attribute__((unused
)))
2303 if ((name
= dm_task_get_name_unmangled((const struct dm_task
*) data
))) {
2304 r
= dm_report_field_string(rh
, field
, (const char **) &name
);
2311 static int _dm_uuid_disp(struct dm_report
*rh
,
2312 struct dm_pool
*mem
__attribute__((unused
)),
2313 struct dm_report_field
*field
,
2314 const void *data
, void *private __attribute__((unused
)))
2316 const char *uuid
= dm_task_get_uuid((const struct dm_task
*) data
);
2318 if (!uuid
|| !*uuid
)
2321 return dm_report_field_string(rh
, field
, &uuid
);
2324 static int _dm_read_ahead_disp(struct dm_report
*rh
,
2325 struct dm_pool
*mem
__attribute__((unused
)),
2326 struct dm_report_field
*field
, const void *data
,
2327 void *private __attribute__((unused
)))
2331 if (!dm_task_get_read_ahead((const struct dm_task
*) data
, &value
))
2334 return dm_report_field_uint32(rh
, field
, &value
);
2337 static int _dm_blk_name_disp(struct dm_report
*rh
,
2338 struct dm_pool
*mem
__attribute__((unused
)),
2339 struct dm_report_field
*field
, const void *data
,
2340 void *private __attribute__((unused
)))
2342 char dev_name
[PATH_MAX
];
2343 const char *s
= dev_name
;
2344 const struct dm_info
*info
= data
;
2346 if (!dm_device_get_name(info
->major
, info
->minor
, 1, dev_name
, PATH_MAX
)) {
2347 log_error("Could not resolve block device name for %d:%d.",
2348 info
->major
, info
->minor
);
2352 return dm_report_field_string(rh
, field
, &s
);
2355 static int _dm_info_status_disp(struct dm_report
*rh
,
2356 struct dm_pool
*mem
__attribute__((unused
)),
2357 struct dm_report_field
*field
, const void *data
,
2358 void *private __attribute__((unused
)))
2361 const char *s
= buf
;
2362 const struct dm_info
*info
= data
;
2364 buf
[0] = info
->live_table
? 'L' : '-';
2365 buf
[1] = info
->inactive_table
? 'I' : '-';
2366 buf
[2] = info
->suspended
? 's' : '-';
2367 buf
[3] = info
->read_only
? 'r' : 'w';
2370 return dm_report_field_string(rh
, field
, &s
);
2373 static int _dm_info_table_loaded_disp(struct dm_report
*rh
,
2374 struct dm_pool
*mem
__attribute__((unused
)),
2375 struct dm_report_field
*field
,
2377 void *private __attribute__((unused
)))
2379 const struct dm_info
*info
= data
;
2381 if (info
->live_table
) {
2382 if (info
->inactive_table
)
2383 dm_report_field_set_value(field
, "Both", NULL
);
2385 dm_report_field_set_value(field
, "Live", NULL
);
2389 if (info
->inactive_table
)
2390 dm_report_field_set_value(field
, "Inactive", NULL
);
2392 dm_report_field_set_value(field
, "None", NULL
);
2397 static int _dm_info_suspended_disp(struct dm_report
*rh
,
2398 struct dm_pool
*mem
__attribute__((unused
)),
2399 struct dm_report_field
*field
,
2401 void *private __attribute__((unused
)))
2403 const struct dm_info
*info
= data
;
2405 if (info
->suspended
)
2406 dm_report_field_set_value(field
, "Suspended", NULL
);
2408 dm_report_field_set_value(field
, "Active", NULL
);
2413 static int _dm_info_read_only_disp(struct dm_report
*rh
,
2414 struct dm_pool
*mem
__attribute__((unused
)),
2415 struct dm_report_field
*field
,
2417 void *private __attribute__((unused
)))
2419 const struct dm_info
*info
= data
;
2421 if (info
->read_only
)
2422 dm_report_field_set_value(field
, "Read-only", NULL
);
2424 dm_report_field_set_value(field
, "Writeable", NULL
);
2430 static int _dm_info_devno_disp(struct dm_report
*rh
, struct dm_pool
*mem
,
2431 struct dm_report_field
*field
, const void *data
,
2434 char buf
[PATH_MAX
], *repstr
;
2435 const struct dm_info
*info
= data
;
2437 if (!dm_pool_begin_object(mem
, 8)) {
2438 log_error("dm_pool_begin_object failed");
2443 if (!dm_device_get_name(info
->major
, info
->minor
,
2448 if (dm_snprintf(buf
, sizeof(buf
), "%d:%d",
2449 info
->major
, info
->minor
) < 0) {
2450 log_error("dm_pool_alloc failed");
2455 if (!dm_pool_grow_object(mem
, buf
, strlen(buf
) + 1)) {
2456 log_error("dm_pool_grow_object failed");
2460 repstr
= dm_pool_end_object(mem
);
2461 dm_report_field_set_value(field
, repstr
, repstr
);
2465 dm_pool_abandon_object(mem
);
2469 static int _dm_tree_names(struct dm_report
*rh
, struct dm_pool
*mem
,
2470 struct dm_report_field
*field
, const void *data
,
2471 void *private, unsigned inverted
)
2473 const struct dm_tree_node
*node
= data
;
2474 struct dm_tree_node
*parent
;
2480 if (!dm_pool_begin_object(mem
, 16)) {
2481 log_error("dm_pool_begin_object failed");
2485 while ((parent
= dm_tree_next_child(&t
, node
, inverted
))) {
2486 name
= dm_tree_node_get_name(parent
);
2487 if (!name
|| !*name
)
2489 if (!first_node
&& !dm_pool_grow_object(mem
, ",", 1)) {
2490 log_error("dm_pool_grow_object failed");
2493 if (!dm_pool_grow_object(mem
, name
, 0)) {
2494 log_error("dm_pool_grow_object failed");
2501 if (!dm_pool_grow_object(mem
, "\0", 1)) {
2502 log_error("dm_pool_grow_object failed");
2506 repstr
= dm_pool_end_object(mem
);
2507 dm_report_field_set_value(field
, repstr
, repstr
);
2511 dm_pool_abandon_object(mem
);
2515 static int _dm_deps_names_disp(struct dm_report
*rh
,
2516 struct dm_pool
*mem
,
2517 struct dm_report_field
*field
,
2518 const void *data
, void *private)
2520 return _dm_tree_names(rh
, mem
, field
, data
, private, 0);
2523 static int _dm_tree_parents_names_disp(struct dm_report
*rh
,
2524 struct dm_pool
*mem
,
2525 struct dm_report_field
*field
,
2526 const void *data
, void *private)
2528 return _dm_tree_names(rh
, mem
, field
, data
, private, 1);
2531 static int _dm_tree_parents_devs_disp(struct dm_report
*rh
, struct dm_pool
*mem
,
2532 struct dm_report_field
*field
,
2533 const void *data
, void *private)
2535 const struct dm_tree_node
*node
= data
;
2536 struct dm_tree_node
*parent
;
2538 const struct dm_info
*info
;
2540 char buf
[DM_MAX_TYPE_NAME
], *repstr
;
2542 if (!dm_pool_begin_object(mem
, 16)) {
2543 log_error("dm_pool_begin_object failed");
2547 while ((parent
= dm_tree_next_child(&t
, node
, 1))) {
2548 info
= dm_tree_node_get_info(parent
);
2549 if (!info
->major
&& !info
->minor
)
2551 if (!first_node
&& !dm_pool_grow_object(mem
, ",", 1)) {
2552 log_error("dm_pool_grow_object failed");
2555 if (dm_snprintf(buf
, sizeof(buf
), "%d:%d",
2556 info
->major
, info
->minor
) < 0) {
2557 log_error("dm_snprintf failed");
2560 if (!dm_pool_grow_object(mem
, buf
, 0)) {
2561 log_error("dm_pool_grow_object failed");
2568 if (!dm_pool_grow_object(mem
, "\0", 1)) {
2569 log_error("dm_pool_grow_object failed");
2573 repstr
= dm_pool_end_object(mem
);
2574 dm_report_field_set_value(field
, repstr
, repstr
);
2578 dm_pool_abandon_object(mem
);
2582 static int _dm_tree_parents_count_disp(struct dm_report
*rh
,
2583 struct dm_pool
*mem
,
2584 struct dm_report_field
*field
,
2585 const void *data
, void *private)
2587 const struct dm_tree_node
*node
= data
;
2588 int num_parent
= dm_tree_node_num_children(node
, 1);
2590 return dm_report_field_int(rh
, field
, &num_parent
);
2593 static int _dm_deps_disp_common(struct dm_report
*rh
, struct dm_pool
*mem
,
2594 struct dm_report_field
*field
, const void *data
,
2595 void *private, int disp_blk_dev_names
)
2597 const struct dm_deps
*deps
= data
;
2598 char buf
[PATH_MAX
], *repstr
;
2602 if (!dm_pool_begin_object(mem
, 16)) {
2603 log_error("dm_pool_begin_object failed");
2607 for (i
= 0; i
< deps
->count
; i
++) {
2608 major
= (int) MAJOR(deps
->device
[i
]);
2609 minor
= (int) MINOR(deps
->device
[i
]);
2611 if (disp_blk_dev_names
) {
2612 if (!dm_device_get_name(major
, minor
, 1, buf
, PATH_MAX
)) {
2613 log_error("Could not resolve block device "
2614 "name for %d:%d.", major
, minor
);
2618 else if (dm_snprintf(buf
, sizeof(buf
), "%d:%d",
2619 major
, minor
) < 0) {
2620 log_error("dm_snprintf failed");
2624 if (!dm_pool_grow_object(mem
, buf
, 0)) {
2625 log_error("dm_pool_grow_object failed");
2629 if (i
+ 1 < deps
->count
&& !dm_pool_grow_object(mem
, ",", 1)) {
2630 log_error("dm_pool_grow_object failed");
2635 if (!dm_pool_grow_object(mem
, "\0", 1)) {
2636 log_error("dm_pool_grow_object failed");
2640 repstr
= dm_pool_end_object(mem
);
2641 dm_report_field_set_value(field
, repstr
, repstr
);
2645 dm_pool_abandon_object(mem
);
2649 static int _dm_deps_disp(struct dm_report
*rh
, struct dm_pool
*mem
,
2650 struct dm_report_field
*field
, const void *data
,
2653 return _dm_deps_disp_common(rh
, mem
, field
, data
, private, 0);
2656 static int _dm_deps_blk_names_disp(struct dm_report
*rh
, struct dm_pool
*mem
,
2657 struct dm_report_field
*field
,
2658 const void *data
, void *private)
2660 return _dm_deps_disp_common(rh
, mem
, field
, data
, private, 1);
2663 static int _dm_subsystem_disp(struct dm_report
*rh
,
2664 struct dm_pool
*mem
__attribute__((unused
)),
2665 struct dm_report_field
*field
, const void *data
,
2666 void *private __attribute__((unused
)))
2668 return dm_report_field_string(rh
, field
, (const char *const *) data
);
2671 static int _dm_vg_name_disp(struct dm_report
*rh
,
2672 struct dm_pool
*mem
__attribute__((unused
)),
2673 struct dm_report_field
*field
, const void *data
,
2674 void *private __attribute__((unused
)))
2677 return dm_report_field_string(rh
, field
, (const char *const *) data
);
2680 static int _dm_lv_name_disp(struct dm_report
*rh
,
2681 struct dm_pool
*mem
__attribute__((unused
)),
2682 struct dm_report_field
*field
, const void *data
,
2683 void *private __attribute__((unused
)))
2686 return dm_report_field_string(rh
, field
, (const char *const *) data
);
2689 static int _dm_lv_layer_name_disp(struct dm_report
*rh
,
2690 struct dm_pool
*mem
__attribute__((unused
)),
2691 struct dm_report_field
*field
, const void *data
,
2692 void *private __attribute__((unused
)))
2695 return dm_report_field_string(rh
, field
, (const char *const *) data
);
2698 static void *_task_get_obj(void *obj
)
2700 return ((struct dmsetup_report_obj
*)obj
)->task
;
2703 static void *_info_get_obj(void *obj
)
2705 return ((struct dmsetup_report_obj
*)obj
)->info
;
2708 static void *_deps_get_obj(void *obj
)
2710 return dm_task_get_deps(((struct dmsetup_report_obj
*)obj
)->deps_task
);
2713 static void *_tree_get_obj(void *obj
)
2715 return ((struct dmsetup_report_obj
*)obj
)->tree_node
;
2718 static void *_split_name_get_obj(void *obj
)
2720 return ((struct dmsetup_report_obj
*)obj
)->split_name
;
2723 static const struct dm_report_object_type _report_types
[] = {
2724 { DR_TASK
, "Mapped Device Name", "", _task_get_obj
},
2725 { DR_INFO
, "Mapped Device Information", "", _info_get_obj
},
2726 { DR_DEPS
, "Mapped Device Relationship Information", "", _deps_get_obj
},
2727 { DR_TREE
, "Mapped Device Relationship Information", "", _tree_get_obj
},
2728 { DR_NAME
, "Mapped Device Name Components", "", _split_name_get_obj
},
2729 { 0, "", "", NULL
},
2732 /* Column definitions */
2733 #define OFFSET_OF(strct, field) (((char*)&((struct strct*)0)->field) - (char*)0)
2734 #define STR (DM_REPORT_FIELD_TYPE_STRING)
2735 #define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
2736 #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},
2737 #define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},
2739 static const struct dm_report_field_type _report_fields
[] = {
2741 FIELD_F(TASK
, STR
, "Name", 16, dm_name
, "name", "Name of mapped device.")
2742 FIELD_F(TASK
, STR
, "MangledName", 16, dm_mangled_name
, "mangled_name", "Mangled name of mapped device.")
2743 FIELD_F(TASK
, STR
, "UnmangledName", 16, dm_unmangled_name
, "unmangled_name", "Unmangled name of mapped device.")
2744 FIELD_F(TASK
, STR
, "UUID", 32, dm_uuid
, "uuid", "Unique (optional) identifier for mapped device.")
2746 /* FIXME Next one should be INFO */
2747 FIELD_F(TASK
, NUM
, "RAhead", 6, dm_read_ahead
, "read_ahead", "Read ahead in sectors.")
2749 FIELD_F(INFO
, STR
, "BlkDevName", 16, dm_blk_name
, "blkdevname", "Name of block device.")
2750 FIELD_F(INFO
, STR
, "Stat", 4, dm_info_status
, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
2751 FIELD_F(INFO
, STR
, "Tables", 6, dm_info_table_loaded
, "tables_loaded", "Which of the live and inactive table slots are filled.")
2752 FIELD_F(INFO
, STR
, "Suspended", 9, dm_info_suspended
, "suspended", "Whether the device is suspended.")
2753 FIELD_F(INFO
, STR
, "Read-only", 9, dm_info_read_only
, "readonly", "Whether the device is read-only or writeable.")
2754 FIELD_F(INFO
, STR
, "DevNo", 5, dm_info_devno
, "devno", "Device major and minor numbers")
2755 FIELD_O(INFO
, dm_info
, NUM
, "Maj", major
, 3, int32
, "major", "Block device major number.")
2756 FIELD_O(INFO
, dm_info
, NUM
, "Min", minor
, 3, int32
, "minor", "Block device minor number.")
2757 FIELD_O(INFO
, dm_info
, NUM
, "Open", open_count
, 4, int32
, "open", "Number of references to open device, if requested.")
2758 FIELD_O(INFO
, dm_info
, NUM
, "Targ", target_count
, 4, int32
, "segments", "Number of segments in live table, if present.")
2759 FIELD_O(INFO
, dm_info
, NUM
, "Event", event_nr
, 6, uint32
, "events", "Number of most recent event.")
2761 FIELD_O(DEPS
, dm_deps
, NUM
, "#Devs", count
, 5, int32
, "device_count", "Number of devices used by this one.")
2762 FIELD_F(TREE
, STR
, "DevNames", 8, dm_deps_names
, "devs_used", "List of names of mapped devices used by this one.")
2763 FIELD_F(DEPS
, STR
, "DevNos", 6, dm_deps
, "devnos_used", "List of device numbers of devices used by this one.")
2764 FIELD_F(DEPS
, STR
, "BlkDevNames", 16, dm_deps_blk_names
, "blkdevs_used", "List of names of block devices used by this one.")
2766 FIELD_F(TREE
, NUM
, "#Refs", 5, dm_tree_parents_count
, "device_ref_count", "Number of mapped devices referencing this one.")
2767 FIELD_F(TREE
, STR
, "RefNames", 8, dm_tree_parents_names
, "names_using_dev", "List of names of mapped devices using this one.")
2768 FIELD_F(TREE
, STR
, "RefDevNos", 9, dm_tree_parents_devs
, "devnos_using_dev", "List of device numbers of mapped devices using this one.")
2770 FIELD_O(NAME
, dm_split_name
, STR
, "Subsys", subsystem
, 6, dm_subsystem
, "subsystem", "Userspace subsystem responsible for this device.")
2771 FIELD_O(NAME
, dm_split_name
, STR
, "VG", vg_name
, 4, dm_vg_name
, "vg_name", "LVM Volume Group name.")
2772 FIELD_O(NAME
, dm_split_name
, STR
, "LV", lv_name
, 4, dm_lv_name
, "lv_name", "LVM Logical Volume name.")
2773 FIELD_O(NAME
, dm_split_name
, STR
, "LVLayer", lv_layer
, 7, dm_lv_layer_name
, "lv_layer", "LVM device layer.")
2775 {0, 0, 0, 0, "", "", NULL
, NULL
},
2784 static const char *default_report_options
= "name,major,minor,attr,open,segments,events,uuid";
2785 static const char *splitname_report_options
= "vg_name,lv_name,lv_layer";
2787 static int _report_init(const struct command
*cmd
)
2789 char *options
= (char *) default_report_options
;
2790 const char *keys
= "";
2791 const char *separator
= " ";
2792 int aligned
= 1, headings
= 1, buffered
= 1, field_prefixes
= 0;
2793 int quoted
= 1, columns_as_rows
= 0;
2798 if (cmd
&& !strcmp(cmd
->name
, "splitname"))
2799 options
= (char *) splitname_report_options
;
2801 /* emulate old dmsetup behaviour */
2802 if (_switches
[NOHEADINGS_ARG
]) {
2808 if (_switches
[UNBUFFERED_ARG
])
2811 if (_switches
[ROWS_ARG
])
2812 columns_as_rows
= 1;
2814 if (_switches
[UNQUOTED_ARG
])
2817 if (_switches
[NAMEPREFIXES_ARG
]) {
2822 if (_switches
[OPTIONS_ARG
] && _string_args
[OPTIONS_ARG
]) {
2823 if (*_string_args
[OPTIONS_ARG
] != '+')
2824 options
= _string_args
[OPTIONS_ARG
];
2826 len
= strlen(default_report_options
) +
2827 strlen(_string_args
[OPTIONS_ARG
]) + 1;
2828 if (!(options
= dm_malloc(len
))) {
2829 err("Failed to allocate option string.");
2832 if (dm_snprintf(options
, len
, "%s,%s",
2833 default_report_options
,
2834 &_string_args
[OPTIONS_ARG
][1]) < 0) {
2835 err("snprintf failed");
2841 if (_switches
[SORT_ARG
] && _string_args
[SORT_ARG
]) {
2842 keys
= _string_args
[SORT_ARG
];
2844 if (cmd
&& (!strcmp(cmd
->name
, "status") || !strcmp(cmd
->name
, "table"))) {
2845 err("--sort is not yet supported with status and table");
2850 if (_switches
[SEPARATOR_ARG
] && _string_args
[SEPARATOR_ARG
]) {
2851 separator
= _string_args
[SEPARATOR_ARG
];
2856 flags
|= DM_REPORT_OUTPUT_ALIGNED
;
2859 flags
|= DM_REPORT_OUTPUT_BUFFERED
;
2862 flags
|= DM_REPORT_OUTPUT_HEADINGS
;
2865 flags
|= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX
;
2868 flags
|= DM_REPORT_OUTPUT_FIELD_UNQUOTED
;
2870 if (columns_as_rows
)
2871 flags
|= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS
;
2873 if (!(_report
= dm_report_init(&_report_type
,
2874 _report_types
, _report_fields
,
2875 options
, separator
, flags
, keys
, NULL
)))
2878 if ((_report_type
& DR_TREE
) && !_build_whole_deptree(cmd
)) {
2879 err("Internal device dependency tree creation failed.");
2884 dm_report_set_output_field_name_prefix(_report
, "dm_");
2889 if (!strcasecmp(options
, "help") || !strcmp(options
, "?"))
2901 static int _ls(CMD_ARGS
)
2903 if ((_switches
[TARGET_ARG
] && _target
) ||
2904 (_switches
[EXEC_ARG
] && _command
))
2905 return _status(cmd
, argc
, argv
, NULL
, 0);
2906 else if ((_switches
[TREE_ARG
]))
2907 return _display_tree(cmd
, 0, NULL
, NULL
, 0);
2909 return _process_all(cmd
, argc
, argv
, 0, _display_name
);
2912 static int _mangle(CMD_ARGS
)
2915 char *new_name
= NULL
;
2916 struct dm_task
*dmt
;
2917 struct dm_info info
;
2924 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
2925 return _process_all(cmd
, argc
, argv
, 0, _mangle
);
2929 if (!(dmt
= dm_task_create(DM_DEVICE_STATUS
)))
2932 if (!(_set_task_device(dmt
, name
, 0)))
2935 if (!_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
2938 if (!dm_task_run(dmt
))
2941 if (!dm_task_get_info(dmt
, &info
) || !info
.exists
)
2944 target_format
= _switches
[MANGLENAME_ARG
] ? _int_args
[MANGLENAME_ARG
]
2945 : DEFAULT_DM_NAME_MANGLING
;
2947 if (target_format
== DM_STRING_MANGLING_AUTO
&& strstr(name
, "\\x5cx")) {
2948 log_error("The name \"%s\" seems to be mangled more than once. "
2949 "Manual intervention required to rename the device.", name
);
2953 if (target_format
== DM_STRING_MANGLING_NONE
) {
2954 if (!(new_name
= dm_task_get_name_unmangled(dmt
)))
2957 else if (!(new_name
= dm_task_get_name_mangled(dmt
)))
2960 /* Nothing to do if the name is in correct form already. */
2961 if (!strcmp(name
, new_name
)) {
2962 log_print("%s: name already in correct form", name
);
2967 log_print("%s: renaming to %s", name
, new_name
);
2969 /* Rename to correct form of the name. */
2970 r
= _do_rename(name
, new_name
, NULL
);
2974 dm_task_destroy(dmt
);
2978 static int _help(CMD_ARGS
);
2983 static struct command _commands
[] = {
2984 {"help", "[-c|-C|--columns]", 0, 0, 0, _help
},
2985 {"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
2986 "\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
2987 "\t [-u|uuid <uuid>] [{--addnodeonresume|--addnodeoncreate}]\n"
2988 "\t [--notable | --table <table> | <table_file>]",
2990 {"remove", "[-f|--force] <device>", 0, -1, 1, _remove
},
2991 {"remove_all", "[-f|--force]", 0, 0, 0, _remove_all
},
2992 {"suspend", "[--noflush] <device>", 0, -1, 1, _suspend
},
2993 {"resume", "<device> [{--addnodeonresume|--addnodeoncreate}]", 0, -1, 1, _resume
},
2994 {"load", "<device> [<table_file>]", 0, 2, 0, _load
},
2995 {"clear", "<device>", 0, -1, 1, _clear
},
2996 {"reload", "<device> [<table_file>]", 0, 2, 0, _load
},
2997 {"wipe_table", "<device>", 0, -1, 1, _error_device
},
2998 {"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, 0, _rename
},
2999 {"message", "<device> <sector> <message>", 2, -1, 0, _message
},
3000 {"ls", "[--target <target_type>] [--exec <command>] [-o options] [--tree]", 0, 0, 0, _ls
},
3001 {"info", "[<device>]", 0, -1, 1, _info
},
3002 {"deps", "[-o options] [<device>]", 0, -1, 1, _deps
},
3003 {"status", "[<device>] [--target <target_type>]", 0, -1, 1, _status
},
3004 {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, -1, 1, _status
},
3005 {"wait", "<device> [<event_nr>]", 0, 2, 0, _wait
},
3006 {"mknodes", "[<device>]", 0, -1, 1, _mknodes
},
3007 {"mangle", "[<device>]", 0, -1, 1, _mangle
},
3008 {"udevcreatecookie", "", 0, 0, 0, _udevcreatecookie
},
3009 {"udevreleasecookie", "[<cookie>]", 0, 1, 0, _udevreleasecookie
},
3010 {"udevflags", "<cookie>", 1, 1, 0, _udevflags
},
3011 {"udevcomplete", "<cookie>", 1, 1, 0, _udevcomplete
},
3012 {"udevcomplete_all", "<age_in_minutes>", 0, 1, 0, _udevcomplete_all
},
3013 {"udevcookies", "", 0, 0, 0, _udevcookies
},
3014 {"targets", "", 0, 0, 0, _targets
},
3015 {"version", "", 0, 0, 0, _version
},
3016 {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, 0, _setgeometry
},
3017 {"splitname", "<device> [<subsystem>]", 1, 2, 0, _splitname
},
3018 {NULL
, NULL
, 0, 0, 0, NULL
}
3021 static void _usage(FILE *out
)
3025 fprintf(out
, "Usage:\n\n");
3026 fprintf(out
, "dmsetup [--version] [-h|--help [-c|-C|--columns]]\n"
3027 " [--checks] [--manglename <mangling_mode>] [-v|--verbose [-v|--verbose ...]]\n"
3028 " [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n"
3029 " [--udevcookie [cookie]] [--noudevrules] [--noudevsync] [--verifyudev]\n"
3030 " [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n"
3031 " [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
3032 " [--nameprefixes] [--noheadings] [--separator <separator>]\n\n");
3033 for (i
= 0; _commands
[i
].name
; i
++)
3034 fprintf(out
, "\t%s %s\n", _commands
[i
].name
, _commands
[i
].help
);
3035 fprintf(out
, "\n<device> may be device name or -u <uuid> or "
3036 "-j <major> -m <minor>\n");
3037 fprintf(out
, "<mangling_mode> is one of 'none', 'auto' and 'hex'.\n");
3038 fprintf(out
, "<fields> are comma-separated. Use 'help -c' for list.\n");
3039 fprintf(out
, "Table_file contents may be supplied on stdin.\n");
3040 fprintf(out
, "Options are: devno, devname, blkdevname.\n");
3041 fprintf(out
, "Tree specific options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
3042 " blkdevname, [no]device, active, open, rw and uuid.\n");
3046 static void _losetup_usage(FILE *out
)
3048 fprintf(out
, "Usage:\n\n");
3049 fprintf(out
, "losetup [-d|-a] [-e encryption] "
3050 "[-o offset] [-f|loop_device] [file]\n\n");
3053 static int _help(CMD_ARGS
)
3057 if (_switches
[COLS_ARG
]) {
3058 _switches
[OPTIONS_ARG
] = 1;
3059 _string_args
[OPTIONS_ARG
] = (char *) "help";
3060 _switches
[SORT_ARG
] = 0;
3063 dm_report_free(_report
);
3066 (void) _report_init(cmd
);
3072 static struct command
*_find_command(const char *name
)
3076 for (i
= 0; _commands
[i
].name
; i
++)
3077 if (!strcmp(_commands
[i
].name
, name
))
3078 return _commands
+ i
;
3083 static int _process_tree_options(const char *options
)
3085 const char *s
, *end
;
3086 struct winsize winsz
;
3089 /* Symbol set default */
3090 if (!strcmp(nl_langinfo(CODESET
), "UTF-8"))
3093 _tsym
= &_tsym_ascii
;
3096 _tree_switches
[TR_DEVICE
] = 1;
3097 _tree_switches
[TR_TRUNCATE
] = 1;
3100 for (s
= options
; s
&& *s
; s
++) {
3102 for (end
= s
; *end
&& *end
!= ','; end
++, len
++)
3104 if (!strncmp(s
, "device", len
))
3105 _tree_switches
[TR_DEVICE
] = 1;
3106 else if (!strncmp(s
, "blkdevname", len
))
3107 _tree_switches
[TR_BLKDEVNAME
] = 1;
3108 else if (!strncmp(s
, "nodevice", len
))
3109 _tree_switches
[TR_DEVICE
] = 0;
3110 else if (!strncmp(s
, "status", len
))
3111 _tree_switches
[TR_STATUS
] = 1;
3112 else if (!strncmp(s
, "table", len
))
3113 _tree_switches
[TR_TABLE
] = 1;
3114 else if (!strncmp(s
, "active", len
))
3115 _tree_switches
[TR_ACTIVE
] = 1;
3116 else if (!strncmp(s
, "open", len
))
3117 _tree_switches
[TR_OPENCOUNT
] = 1;
3118 else if (!strncmp(s
, "uuid", len
))
3119 _tree_switches
[TR_UUID
] = 1;
3120 else if (!strncmp(s
, "rw", len
))
3121 _tree_switches
[TR_RW
] = 1;
3122 else if (!strncmp(s
, "utf", len
))
3124 else if (!strncmp(s
, "vt100", len
))
3125 _tsym
= &_tsym_vt100
;
3126 else if (!strncmp(s
, "ascii", len
))
3127 _tsym
= &_tsym_ascii
;
3128 else if (!strncmp(s
, "inverted", len
))
3129 _tree_switches
[TR_BOTTOMUP
] = 1;
3130 else if (!strncmp(s
, "compact", len
))
3131 _tree_switches
[TR_COMPACT
] = 1;
3132 else if (!strncmp(s
, "notrunc", len
))
3133 _tree_switches
[TR_TRUNCATE
] = 0;
3135 fprintf(stderr
, "Tree options not recognised: %s\n", s
);
3143 /* Truncation doesn't work well with vt100 drawing char */
3144 if (_tsym
!= &_tsym_vt100
)
3145 if (ioctl(1, (unsigned long) TIOCGWINSZ
, &winsz
) >= 0 && winsz
.ws_col
> 3)
3146 _termwidth
= winsz
.ws_col
- 3;
3152 * Returns the full absolute path, or NULL if the path could
3155 static char *_get_abspath(const char *path
)
3159 #ifdef HAVE_CANONICALIZE_FILE_NAME
3160 _path
= canonicalize_file_name(path
);
3162 /* FIXME Provide alternative */
3163 log_error(INTERNAL_ERROR
"Unimplemented _get_abspath.");
3169 static char *parse_loop_device_name(const char *dev
, const char *dev_dir
)
3172 char *device
= NULL
;
3174 if (!(buf
= dm_malloc(PATH_MAX
)))
3177 if (dev
[0] == '/') {
3178 if (!(device
= _get_abspath(dev
)))
3181 if (strncmp(device
, dev_dir
, strlen(dev_dir
)))
3184 /* If dev_dir does not end in a slash, ensure that the
3185 following byte in the device string is "/". */
3186 if (dev_dir
[strlen(dev_dir
) - 1] != '/' &&
3187 device
[strlen(dev_dir
)] != '/')
3190 strncpy(buf
, strrchr(device
, '/') + 1, PATH_MAX
- 1);
3191 buf
[PATH_MAX
- 1] = '\0';
3195 /* check for device number */
3196 if (!strncmp(dev
, "loop", strlen("loop")))
3197 strncpy(buf
, dev
, (size_t) PATH_MAX
);
3212 * create a table for a mapped device using the loop target.
3214 static int _loop_table(char *table
, size_t tlen
, char *file
,
3215 char *dev
__attribute__((unused
)), off_t off
)
3218 off_t size
, sectors
;
3220 #ifdef HAVE_SYS_STATVFS_H
3221 struct statvfs fsbuf
;
3225 if (!_switches
[READ_ONLY
])
3226 fd
= open(file
, O_RDWR
);
3229 _switches
[READ_ONLY
]++;
3230 fd
= open(file
, O_RDONLY
);
3236 if (fstat(fd
, &fbuf
))
3239 size
= (fbuf
.st_size
- off
);
3240 sectors
= size
>> SECTOR_SHIFT
;
3242 if (_switches
[VERBOSE_ARG
])
3243 fprintf(stderr
, "losetup: set loop size to %llukB "
3244 "(%llu sectors)\n", (long long unsigned) sectors
>> 1,
3245 (long long unsigned) sectors
);
3247 #ifdef HAVE_SYS_STATVFS_H
3248 if (fstatvfs(fd
, &fsbuf
))
3251 /* FIXME Fragment size currently unused */
3252 blksize
= fsbuf
.f_frsize
;
3256 log_sys_error("close", file
);
3258 if (dm_snprintf(table
, tlen
, "%llu %llu loop %s %llu\n", 0ULL,
3259 (long long unsigned)sectors
, file
, (long long unsigned)off
) < 0)
3262 if (_switches
[VERBOSE_ARG
] > 1)
3263 fprintf(stderr
, "Table: %s\n", table
);
3268 if (fd
> -1 && close(fd
))
3269 log_sys_error("close", file
);
3274 static int _process_losetup_switches(const char *base
, int *argc
, char ***argv
,
3275 const char *dev_dir
)
3278 int encrypt_loop
= 0, delete = 0, find
= 0, show_all
= 0;
3279 char *device_name
= NULL
;
3280 char *loop_file
= NULL
;
3283 #ifdef HAVE_GETOPTLONG
3284 static struct option long_options
[] = {
3290 optind
= OPTIND_INIT
;
3291 while ((c
= GETOPTLONG_FN(*argc
, *argv
, "ade:fo:v",
3292 long_options
, NULL
)) != -1 ) {
3293 if (c
== ':' || c
== '?')
3304 offset
= atoi(optarg
);
3306 _switches
[VERBOSE_ARG
]++;
3313 fprintf(stderr
, "%s: Sorry, cryptoloop is not yet implemented "
3314 "in this version.\n", base
);
3319 fprintf(stderr
, "%s: Sorry, show all is not yet implemented "
3320 "in this version.\n", base
);
3325 fprintf(stderr
, "%s: Sorry, find is not yet implemented "
3326 "in this version.\n", base
);
3332 fprintf(stderr
, "%s: Please specify loop_device.\n", base
);
3333 _losetup_usage(stderr
);
3337 if (!(device_name
= parse_loop_device_name((*argv
)[0], dev_dir
))) {
3338 fprintf(stderr
, "%s: Could not parse loop_device %s\n",
3340 _losetup_usage(stderr
);
3347 (*argv
)[1] = device_name
;
3348 (*argv
)[0] = (char *) "remove";
3354 fprintf(stderr
, "%s: Too few arguments\n", base
);
3355 _losetup_usage(stderr
);
3356 dm_free(device_name
);
3360 /* FIXME move these to make them available to native dmsetup */
3361 if (!(loop_file
= _get_abspath((*argv
)[(find
) ? 0 : 1]))) {
3362 fprintf(stderr
, "%s: Could not parse loop file name %s\n",
3364 _losetup_usage(stderr
);
3365 dm_free(device_name
);
3369 _table
= dm_malloc(LOOP_TABLE_SIZE
);
3371 !_loop_table(_table
, (size_t) LOOP_TABLE_SIZE
, loop_file
, device_name
, offset
)) {
3372 fprintf(stderr
, "Could not build device-mapper table for %s\n", (*argv
)[0]);
3373 dm_free(device_name
);
3376 _switches
[TABLE_ARG
]++;
3378 (*argv
)[0] = (char *) "create";
3379 (*argv
)[1] = device_name
;
3384 static int _process_options(const char *options
)
3386 const char *s
, *end
;
3389 /* Tree options are processed separately. */
3390 if (_switches
[TREE_ARG
])
3391 return _process_tree_options(_string_args
[OPTIONS_ARG
]);
3393 /* Column options are processed separately by _report_init (called later). */
3394 if (_switches
[COLS_ARG
])
3397 /* No options specified. */
3398 if (!_switches
[OPTIONS_ARG
])
3402 _dev_name_type
= DN_DEVNO
;
3405 for (s
= options
; s
&& *s
; s
++) {
3407 for (end
= s
; *end
&& *end
!= ','; end
++, len
++)
3409 if (!strncmp(s
, "devno", len
))
3410 _dev_name_type
= DN_DEVNO
;
3411 else if (!strncmp(s
, "blkdevname", len
))
3412 _dev_name_type
= DN_BLK
;
3413 else if (!strncmp(s
, "devname", len
))
3414 _dev_name_type
= DN_MAP
;
3416 fprintf(stderr
, "Option not recognised: %s\n", s
);
3428 static int _process_switches(int *argc
, char ***argv
, const char *dev_dir
)
3435 #ifdef HAVE_GETOPTLONG
3436 static struct option long_options
[] = {
3437 {"readonly", 0, &ind
, READ_ONLY
},
3438 {"checks", 0, &ind
, CHECKS_ARG
},
3439 {"columns", 0, &ind
, COLS_ARG
},
3440 {"exec", 1, &ind
, EXEC_ARG
},
3441 {"force", 0, &ind
, FORCE_ARG
},
3442 {"gid", 1, &ind
, GID_ARG
},
3443 {"help", 0, &ind
, HELP_ARG
},
3444 {"inactive", 0, &ind
, INACTIVE_ARG
},
3445 {"manglename", 1, &ind
, MANGLENAME_ARG
},
3446 {"major", 1, &ind
, MAJOR_ARG
},
3447 {"minor", 1, &ind
, MINOR_ARG
},
3448 {"mode", 1, &ind
, MODE_ARG
},
3449 {"nameprefixes", 0, &ind
, NAMEPREFIXES_ARG
},
3450 {"noflush", 0, &ind
, NOFLUSH_ARG
},
3451 {"noheadings", 0, &ind
, NOHEADINGS_ARG
},
3452 {"nolockfs", 0, &ind
, NOLOCKFS_ARG
},
3453 {"noopencount", 0, &ind
, NOOPENCOUNT_ARG
},
3454 {"notable", 0, &ind
, NOTABLE_ARG
},
3455 {"udevcookie", 1, &ind
, UDEVCOOKIE_ARG
},
3456 {"noudevrules", 0, &ind
, NOUDEVRULES_ARG
},
3457 {"noudevsync", 0, &ind
, NOUDEVSYNC_ARG
},
3458 {"options", 1, &ind
, OPTIONS_ARG
},
3459 {"readahead", 1, &ind
, READAHEAD_ARG
},
3460 {"retry", 0, &ind
, RETRY_ARG
},
3461 {"rows", 0, &ind
, ROWS_ARG
},
3462 {"separator", 1, &ind
, SEPARATOR_ARG
},
3463 {"setuuid", 0, &ind
, SETUUID_ARG
},
3464 {"showkeys", 0, &ind
, SHOWKEYS_ARG
},
3465 {"sort", 1, &ind
, SORT_ARG
},
3466 {"table", 1, &ind
, TABLE_ARG
},
3467 {"target", 1, &ind
, TARGET_ARG
},
3468 {"tree", 0, &ind
, TREE_ARG
},
3469 {"uid", 1, &ind
, UID_ARG
},
3470 {"uuid", 1, &ind
, UUID_ARG
},
3471 {"unbuffered", 0, &ind
, UNBUFFERED_ARG
},
3472 {"unquoted", 0, &ind
, UNQUOTED_ARG
},
3473 {"verbose", 1, &ind
, VERBOSE_ARG
},
3474 {"verifyudev", 0, &ind
, VERIFYUDEV_ARG
},
3475 {"version", 0, &ind
, VERSION_ARG
},
3476 {"yes", 0, &ind
, YES_ARG
},
3477 {"addnodeonresume", 0, &ind
, ADD_NODE_ON_RESUME_ARG
},
3478 {"addnodeoncreate", 0, &ind
, ADD_NODE_ON_CREATE_ARG
},
3482 struct option long_options
;
3486 * Zero all the index counts.
3488 memset(&_switches
, 0, sizeof(_switches
));
3489 memset(&_int_args
, 0, sizeof(_int_args
));
3490 _read_ahead_flags
= 0;
3492 if (!(namebase
= strdup((*argv
)[0]))) {
3493 fprintf(stderr
, "Failed to duplicate name.\n");
3496 base
= dm_basename(namebase
);
3498 if (!strcmp(base
, "devmap_name")) {
3500 _switches
[COLS_ARG
]++;
3501 _switches
[NOHEADINGS_ARG
]++;
3502 _switches
[OPTIONS_ARG
]++;
3503 _switches
[MAJOR_ARG
]++;
3504 _switches
[MINOR_ARG
]++;
3505 _string_args
[OPTIONS_ARG
] = (char *) "name";
3508 _int_args
[MAJOR_ARG
] = atoi((*argv
)[1]);
3509 _int_args
[MINOR_ARG
] = atoi((*argv
)[2]);
3512 } else if ((*argc
== 2) &&
3513 (2 == sscanf((*argv
)[1], "%i:%i",
3514 &_int_args
[MAJOR_ARG
],
3515 &_int_args
[MINOR_ARG
]))) {
3519 fprintf(stderr
, "Usage: devmap_name <major> <minor>\n");
3523 (*argv
)[0] = (char *) "info";
3527 if (!strcmp(base
, "losetup") || !strcmp(base
, "dmlosetup")){
3528 r
= _process_losetup_switches(base
, argc
, argv
, dev_dir
);
3536 optind
= OPTIND_INIT
;
3537 while ((ind
= -1, c
= GETOPTLONG_FN(*argc
, *argv
, "cCfG:hj:m:M:no:O:ru:U:vy",
3538 long_options
, NULL
)) != -1) {
3539 if (c
== ':' || c
== '?')
3541 if (c
== 'h' || ind
== HELP_ARG
)
3542 _switches
[HELP_ARG
]++;
3543 if (c
== 'c' || c
== 'C' || ind
== COLS_ARG
)
3544 _switches
[COLS_ARG
]++;
3545 if (c
== 'f' || ind
== FORCE_ARG
)
3546 _switches
[FORCE_ARG
]++;
3547 if (c
== 'r' || ind
== READ_ONLY
)
3548 _switches
[READ_ONLY
]++;
3549 if (c
== 'j' || ind
== MAJOR_ARG
) {
3550 _switches
[MAJOR_ARG
]++;
3551 _int_args
[MAJOR_ARG
] = atoi(optarg
);
3553 if (c
== 'm' || ind
== MINOR_ARG
) {
3554 _switches
[MINOR_ARG
]++;
3555 _int_args
[MINOR_ARG
] = atoi(optarg
);
3557 if (c
== 'n' || ind
== NOTABLE_ARG
)
3558 _switches
[NOTABLE_ARG
]++;
3559 if (c
== 'o' || ind
== OPTIONS_ARG
) {
3560 _switches
[OPTIONS_ARG
]++;
3561 _string_args
[OPTIONS_ARG
] = optarg
;
3563 if (ind
== SEPARATOR_ARG
) {
3564 _switches
[SEPARATOR_ARG
]++;
3565 _string_args
[SEPARATOR_ARG
] = optarg
;
3567 if (c
== 'O' || ind
== SORT_ARG
) {
3568 _switches
[SORT_ARG
]++;
3569 _string_args
[SORT_ARG
] = optarg
;
3571 if (c
== 'v' || ind
== VERBOSE_ARG
)
3572 _switches
[VERBOSE_ARG
]++;
3573 if (c
== 'u' || ind
== UUID_ARG
) {
3574 _switches
[UUID_ARG
]++;
3577 if (c
== 'y' || ind
== YES_ARG
)
3578 _switches
[YES_ARG
]++;
3579 if (ind
== ADD_NODE_ON_RESUME_ARG
)
3580 _switches
[ADD_NODE_ON_RESUME_ARG
]++;
3581 if (ind
== ADD_NODE_ON_CREATE_ARG
)
3582 _switches
[ADD_NODE_ON_CREATE_ARG
]++;
3583 if (ind
== CHECKS_ARG
)
3584 _switches
[CHECKS_ARG
]++;
3585 if (ind
== UDEVCOOKIE_ARG
) {
3586 _switches
[UDEVCOOKIE_ARG
]++;
3587 _udev_cookie
= _get_cookie_value(optarg
);
3589 if (ind
== NOUDEVRULES_ARG
)
3590 _switches
[NOUDEVRULES_ARG
]++;
3591 if (ind
== NOUDEVSYNC_ARG
)
3592 _switches
[NOUDEVSYNC_ARG
]++;
3593 if (ind
== VERIFYUDEV_ARG
)
3594 _switches
[VERIFYUDEV_ARG
]++;
3595 if (c
== 'G' || ind
== GID_ARG
) {
3596 _switches
[GID_ARG
]++;
3597 _int_args
[GID_ARG
] = atoi(optarg
);
3599 if (c
== 'U' || ind
== UID_ARG
) {
3600 _switches
[UID_ARG
]++;
3601 _int_args
[UID_ARG
] = atoi(optarg
);
3603 if (c
== 'M' || ind
== MODE_ARG
) {
3604 _switches
[MODE_ARG
]++;
3605 /* FIXME Accept modes as per chmod */
3606 _int_args
[MODE_ARG
] = (int) strtol(optarg
, NULL
, 8);
3608 if (ind
== EXEC_ARG
) {
3609 _switches
[EXEC_ARG
]++;
3612 if (ind
== TARGET_ARG
) {
3613 _switches
[TARGET_ARG
]++;
3616 if (ind
== INACTIVE_ARG
)
3617 _switches
[INACTIVE_ARG
]++;
3618 if ((ind
== MANGLENAME_ARG
)) {
3619 _switches
[MANGLENAME_ARG
]++;
3620 if (!strcasecmp(optarg
, "none"))
3621 _int_args
[MANGLENAME_ARG
] = DM_STRING_MANGLING_NONE
;
3622 else if (!strcasecmp(optarg
, "auto"))
3623 _int_args
[MANGLENAME_ARG
] = DM_STRING_MANGLING_AUTO
;
3624 else if (!strcasecmp(optarg
, "hex"))
3625 _int_args
[MANGLENAME_ARG
] = DM_STRING_MANGLING_HEX
;
3627 log_error("Unknown name mangling mode");
3630 dm_set_name_mangling_mode((dm_string_mangling_t
) _int_args
[MANGLENAME_ARG
]);
3632 if (ind
== NAMEPREFIXES_ARG
)
3633 _switches
[NAMEPREFIXES_ARG
]++;
3634 if (ind
== NOFLUSH_ARG
)
3635 _switches
[NOFLUSH_ARG
]++;
3636 if (ind
== NOHEADINGS_ARG
)
3637 _switches
[NOHEADINGS_ARG
]++;
3638 if (ind
== NOLOCKFS_ARG
)
3639 _switches
[NOLOCKFS_ARG
]++;
3640 if (ind
== NOOPENCOUNT_ARG
)
3641 _switches
[NOOPENCOUNT_ARG
]++;
3642 if (ind
== READAHEAD_ARG
) {
3643 _switches
[READAHEAD_ARG
]++;
3644 if (!strcasecmp(optarg
, "auto"))
3645 _int_args
[READAHEAD_ARG
] = DM_READ_AHEAD_AUTO
;
3646 else if (!strcasecmp(optarg
, "none"))
3647 _int_args
[READAHEAD_ARG
] = DM_READ_AHEAD_NONE
;
3649 for (s
= optarg
; isspace(*s
); s
++)
3652 _read_ahead_flags
= DM_READ_AHEAD_MINIMUM_FLAG
;
3653 _int_args
[READAHEAD_ARG
] = atoi(optarg
);
3654 if (_int_args
[READAHEAD_ARG
] < -1) {
3655 log_error("Negative read ahead value "
3656 "(%d) is not understood.",
3657 _int_args
[READAHEAD_ARG
]);
3662 if (ind
== RETRY_ARG
)
3663 _switches
[RETRY_ARG
]++;
3664 if (ind
== ROWS_ARG
)
3665 _switches
[ROWS_ARG
]++;
3666 if (ind
== SETUUID_ARG
)
3667 _switches
[SETUUID_ARG
]++;
3668 if (ind
== SHOWKEYS_ARG
)
3669 _switches
[SHOWKEYS_ARG
]++;
3670 if (ind
== TABLE_ARG
) {
3671 _switches
[TABLE_ARG
]++;
3672 if (!(_table
= dm_strdup(optarg
))) {
3673 log_error("Could not allocate memory for table string.");
3677 if (ind
== TREE_ARG
)
3678 _switches
[TREE_ARG
]++;
3679 if (ind
== UNQUOTED_ARG
)
3680 _switches
[UNQUOTED_ARG
]++;
3681 if (ind
== VERSION_ARG
)
3682 _switches
[VERSION_ARG
]++;
3685 if (_switches
[VERBOSE_ARG
] > 1)
3686 dm_log_init_verbose(_switches
[VERBOSE_ARG
] - 1);
3688 if ((_switches
[MAJOR_ARG
] && !_switches
[MINOR_ARG
]) ||
3689 (!_switches
[MAJOR_ARG
] && _switches
[MINOR_ARG
])) {
3690 fprintf(stderr
, "Please specify both major number and "
3695 if (!_process_options(_string_args
[OPTIONS_ARG
]))
3698 if (_switches
[TABLE_ARG
] && _switches
[NOTABLE_ARG
]) {
3699 fprintf(stderr
, "--table and --notable are incompatible.\n");
3703 if (_switches
[ADD_NODE_ON_RESUME_ARG
] && _switches
[ADD_NODE_ON_CREATE_ARG
]) {
3704 fprintf(stderr
, "--addnodeonresume and --addnodeoncreate are incompatible.\n");
3713 int main(int argc
, char **argv
)
3716 const char *dev_dir
;
3717 const struct command
*cmd
;
3718 int multiple_devices
;
3720 (void) setlocale(LC_ALL
, "");
3722 dev_dir
= getenv (DM_DEV_DIR_ENV_VAR_NAME
);
3723 if (dev_dir
&& *dev_dir
) {
3724 if (!dm_set_dev_dir(dev_dir
)) {
3725 fprintf(stderr
, "Invalid DM_DEV_DIR environment variable value.\n");
3729 dev_dir
= DEFAULT_DM_DEV_DIR
;
3731 if (!_process_switches(&argc
, &argv
, dev_dir
)) {
3732 fprintf(stderr
, "Couldn't process command line.\n");
3736 if (_switches
[HELP_ARG
]) {
3737 cmd
= _find_command("help");
3741 if (_switches
[VERSION_ARG
]) {
3742 cmd
= _find_command("version");
3751 if (!(cmd
= _find_command(argv
[0]))) {
3752 fprintf(stderr
, "Unknown command\n");
3757 if (argc
< cmd
->min_args
+ 1 ||
3758 (cmd
->max_args
>= 0 && argc
> cmd
->max_args
+ 1)) {
3759 fprintf(stderr
, "Incorrect number of arguments\n");
3764 if (!_switches
[COLS_ARG
] && !strcmp(cmd
->name
, "splitname"))
3765 _switches
[COLS_ARG
]++;
3767 if (!strcmp(cmd
->name
, "mangle"))
3768 dm_set_name_mangling_mode(DM_STRING_MANGLING_NONE
);
3770 if (_switches
[COLS_ARG
]) {
3771 if (!_report_init(cmd
))
3774 if (!strcmp(cmd
->name
, "info"))
3775 r
= 0; /* info -c -o help */
3780 #ifdef UDEV_SYNC_SUPPORT
3781 if (!_set_up_udev_support(dev_dir
))
3786 multiple_devices
= (cmd
->repeatable_cmd
&& argc
!= 2 &&
3787 (argc
!= 1 || (!_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])));
3789 if (!cmd
->fn(cmd
, argc
--, argv
++, NULL
, multiple_devices
)) {
3790 fprintf(stderr
, "Command failed\n");
3793 } while (cmd
->repeatable_cmd
&& argc
> 1);
3799 dm_report_output(_report
);
3800 dm_report_free(_report
);
3804 dm_tree_free(_dtree
);