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
)
1013 size_t len
= strlen(dev_dir
), udev_dir_len
= strlen(DM_UDEV_DEV_DIR
);
1015 if (_switches
[NOUDEVSYNC_ARG
])
1016 dm_udev_set_sync_support(0);
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.",
1024 DM_UDEV_COOKIE_ENV_VAR_NAME
);
1026 else if (_switches
[UDEVCOOKIE_ARG
])
1027 log_debug("Using udev transaction 0x%08" PRIX32
1028 " defined by --udevcookie option.",
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.
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!
1048 if (dev_dir
[len
- 1] != '/')
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
]);
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);
1069 static int _udevcreatecookie(CMD_ARGS
)
1073 if (!dm_udev_create_cookie(&cookie
))
1077 printf("0x%08" PRIX32
"\n", cookie
);
1082 static int _udevreleasecookie(CMD_ARGS
)
1084 if (argv
[1] && !(_udev_cookie
= _get_cookie_value(argv
[1])))
1087 if (!_udev_cookie
) {
1088 log_error("No udev transaction cookie given.");
1092 return dm_udev_wait(_udev_cookie
);
1095 __attribute__((format(printf
, 1, 2)))
1096 static char _yes_no_prompt(const char *prompt
, ...)
1102 if (c
== '\n' || !c
) {
1103 va_start(ap
, prompt
);
1104 vprintf(prompt
, ap
);
1108 if ((c
= getchar()) == EOF
) {
1114 if ((c
== 'y') || (c
== 'n'))
1116 } while (!ret
|| c
!= '\n');
1124 static int _udevcomplete_all(CMD_ARGS
)
1126 int max_id
, id
, sid
;
1127 struct seminfo sinfo
;
1128 struct semid_ds sdata
;
1134 if (argc
== 2 && (sscanf(argv
[1], "%i", &age
) != 1)) {
1135 log_error("Failed to read age_in_minutes parameter.");
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
);
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
);
1153 if ((max_id
= semctl(0, 0, SEM_INFO
, &sinfo
)) < 0) {
1154 log_sys_error("semctl", "SEM_INFO");
1158 for (id
= 0; id
<= max_id
; id
++) {
1159 if ((sid
= semctl(id
, 0, SEM_STAT
, &sdata
)) < 0)
1162 if (sdata
.sem_perm
.__key
>> 16 == DM_COOKIE_MAGIC
) {
1165 if (sdata
.sem_ctime
+ age
* 60 > t
||
1166 sdata
.sem_otime
+ age
* 60 > t
) {
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
);
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
);
1189 static int _udevcookies(CMD_ARGS
)
1191 int max_id
, id
, sid
;
1192 struct seminfo sinfo
;
1193 struct semid_ds sdata
;
1195 char otime_str
[26], ctime_str
[26];
1196 char *otimes
, *ctimes
;
1198 if ((max_id
= semctl(0, 0, SEM_INFO
, &sinfo
)) < 0) {
1199 log_sys_error("sem_ctl", "SEM_INFO");
1203 printf("Cookie Semid Value Last semop time Last change time\n");
1205 for (id
= 0; id
<= max_id
; id
++) {
1206 if ((sid
= semctl(id
, 0, SEM_STAT
, &sdata
)) < 0)
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
,
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';
1223 printf("0x%-10x %-10d %-10d %s %s\n", sdata
.sem_perm
.__key
,
1224 sid
, val
, otimes
? : "unknown",
1225 ctimes
? : "unknown");
1231 #endif /* UDEV_SYNC_SUPPORT */
1233 static int _version(CMD_ARGS
)
1237 if (dm_get_library_version(version
, sizeof(version
)))
1238 printf("Library version: %s\n", version
);
1240 if (!dm_driver_version(version
, sizeof(version
)))
1243 printf("Driver version: %s\n", version
);
1248 static int _simple(int task
, const char *name
, uint32_t event_nr
, int display
)
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
;
1256 struct dm_task
*dmt
;
1258 if (!(dmt
= dm_task_create(task
)))
1261 if (!_set_task_device(dmt
, name
, 0))
1264 if (event_nr
&& !dm_task_set_event_nr(dmt
, event_nr
))
1267 if (_switches
[NOFLUSH_ARG
] && !dm_task_no_flush(dmt
))
1270 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1273 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1276 if (_switches
[NOLOCKFS_ARG
] && !dm_task_skip_lockfs(dmt
))
1279 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1282 /* FIXME: needs to coperate with udev */
1283 if (!_set_task_add_node(dmt
))
1286 if (_switches
[READAHEAD_ARG
] &&
1287 !dm_task_set_read_ahead(dmt
, _int_args
[READAHEAD_ARG
],
1291 if (_switches
[NOUDEVRULES_ARG
])
1292 udev_flags
|= DM_UDEV_DISABLE_DM_RULES_FLAG
|
1293 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG
;
1296 cookie
= _udev_cookie
;
1299 udev_flags
|= DM_UDEV_DISABLE_LIBRARY_FALLBACK
;
1301 if (udev_wait_flag
&& !dm_task_set_cookie(dmt
, &cookie
, udev_flags
))
1304 if (_switches
[RETRY_ARG
] && task
== DM_DEVICE_REMOVE
)
1305 dm_task_retry_remove(dmt
);
1307 r
= dm_task_run(dmt
);
1310 if (!_udev_cookie
&& udev_wait_flag
)
1311 (void) dm_udev_wait(cookie
);
1313 if (r
&& display
&& _switches
[VERBOSE_ARG
])
1314 r
= _display_info(dmt
);
1316 dm_task_destroy(dmt
);
1321 static int _suspend(CMD_ARGS
)
1323 return _simple(DM_DEVICE_SUSPEND
, argc
> 1 ? argv
[1] : NULL
, 0, 1);
1326 static int _resume(CMD_ARGS
)
1328 return _simple(DM_DEVICE_RESUME
, argc
> 1 ? argv
[1] : NULL
, 0, 1);
1331 static int _clear(CMD_ARGS
)
1333 return _simple(DM_DEVICE_CLEAR
, argc
> 1 ? argv
[1] : NULL
, 0, 1);
1336 static int _wait(CMD_ARGS
)
1338 const char *name
= NULL
;
1340 if (!_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
]) {
1342 err("No device specified.");
1349 return _simple(DM_DEVICE_WAITEVENT
, name
,
1350 (argc
> 1) ? (uint32_t) atoi(argv
[argc
- 1]) : 0, 1);
1353 static int _process_all(const struct command
*cmd
, int argc
, char **argv
, int silent
,
1354 int (*fn
) (CMD_ARGS
))
1357 struct dm_names
*names
;
1360 struct dm_task
*dmt
;
1362 if (!(dmt
= dm_task_create(DM_DEVICE_LIST
)))
1365 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1368 if (!dm_task_run(dmt
)) {
1373 if (!(names
= dm_task_get_names(dmt
))) {
1380 printf("No devices found\n");
1385 names
= (struct dm_names
*)((char *) names
+ next
);
1386 if (!fn(cmd
, argc
, argv
, names
, 1))
1392 dm_task_destroy(dmt
);
1396 static uint64_t _get_device_size(const char *name
)
1398 uint64_t start
, length
, size
= UINT64_C(0);
1399 struct dm_info info
;
1400 char *target_type
, *params
;
1401 struct dm_task
*dmt
;
1404 if (!(dmt
= dm_task_create(DM_DEVICE_TABLE
)))
1407 if (!_set_task_device(dmt
, name
, 0))
1410 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1413 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1416 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1419 if (!dm_task_run(dmt
))
1422 if (!dm_task_get_info(dmt
, &info
) || !info
.exists
)
1426 next
= dm_get_next_target(dmt
, next
, &start
, &length
,
1427 &target_type
, ¶ms
);
1432 dm_task_destroy(dmt
);
1436 static int _error_device(CMD_ARGS
)
1438 struct dm_task
*dmt
;
1443 name
= names
? names
->name
: argv
[1];
1445 size
= _get_device_size(name
);
1447 if (!(dmt
= dm_task_create(DM_DEVICE_RELOAD
)))
1450 if (!_set_task_device(dmt
, name
, 0))
1453 if (!dm_task_add_target(dmt
, UINT64_C(0), size
, "error", ""))
1456 if (_switches
[READ_ONLY
] && !dm_task_set_ro(dmt
))
1459 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1462 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1465 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1468 if (!dm_task_run(dmt
))
1471 if (!_simple(DM_DEVICE_RESUME
, name
, 0, 0)) {
1472 _simple(DM_DEVICE_CLEAR
, name
, 0, 0);
1479 dm_task_destroy(dmt
);
1483 static int _remove(CMD_ARGS
)
1485 if (_switches
[FORCE_ARG
] && argc
> 1)
1486 (void) _error_device(cmd
, argc
, argv
, NULL
, 0);
1488 return _simple(DM_DEVICE_REMOVE
, argc
> 1 ? argv
[1] : NULL
, 0, 0);
1491 static int _count_devices(CMD_ARGS
)
1498 static int _remove_all(CMD_ARGS
)
1502 /* Remove all closed devices */
1503 r
= _simple(DM_DEVICE_REMOVE_ALL
, "", 0, 0) | dm_mknodes(NULL
);
1505 if (!_switches
[FORCE_ARG
])
1509 r
|= _process_all(cmd
, argc
, argv
, 1, _count_devices
);
1511 /* No devices left? */
1515 r
|= _process_all(cmd
, argc
, argv
, 1, _error_device
);
1516 r
|= _simple(DM_DEVICE_REMOVE_ALL
, "", 0, 0) | dm_mknodes(NULL
);
1519 r
|= _process_all(cmd
, argc
, argv
, 1, _count_devices
);
1523 fprintf(stderr
, "Unable to remove %d device(s).\n", _num_devices
);
1528 static void _display_dev(struct dm_task
*dmt
, const char *name
)
1530 struct dm_info info
;
1532 if (dm_task_get_info(dmt
, &info
))
1533 printf("%s\t(%u, %u)\n", name
, info
.major
, info
.minor
);
1536 static int _mknodes(CMD_ARGS
)
1538 return dm_mknodes(argc
> 1 ? argv
[1] : NULL
);
1541 static int _exec_command(const char *name
)
1544 static char path
[PATH_MAX
];
1545 static char *args
[ARGS_MAX
+ 1];
1546 static int argc
= 0;
1553 if (!dm_mknodes(name
))
1556 n
= snprintf(path
, sizeof(path
), "%s/%s", dm_dir(), name
);
1557 if (n
< 0 || n
> (int) sizeof(path
) - 1)
1562 while (argc
< ARGS_MAX
) {
1563 while (*c
&& isspace(*c
))
1568 while (*c
&& !isspace(*c
))
1579 if (argc
== ARGS_MAX
) {
1580 err("Too many args to --exec\n");
1585 args
[argc
++] = path
;
1589 if (!(pid
= fork())) {
1590 execvp(args
[0], args
);
1592 } else if (pid
< (pid_t
) 0)
1595 TEMP_FAILURE_RETRY(waitpid(pid
, NULL
, 0));
1600 static int _status(CMD_ARGS
)
1603 struct dm_task
*dmt
;
1605 uint64_t start
, length
;
1606 char *target_type
= NULL
;
1609 const char *name
= NULL
;
1612 struct dm_info info
;
1617 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
1618 return _process_all(cmd
, argc
, argv
, 0, _status
);
1622 if (!strcmp(cmd
->name
, "table"))
1623 cmdno
= DM_DEVICE_TABLE
;
1625 cmdno
= DM_DEVICE_STATUS
;
1627 if (!strcmp(cmd
->name
, "ls"))
1630 if (!(dmt
= dm_task_create(cmdno
)))
1633 if (!_set_task_device(dmt
, name
, 0))
1636 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1639 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1642 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1645 if (_switches
[NOFLUSH_ARG
] && !dm_task_no_flush(dmt
))
1648 if (!dm_task_run(dmt
))
1651 if (!dm_task_get_info(dmt
, &info
) || !info
.exists
)
1655 name
= dm_task_get_name(dmt
);
1657 /* Fetch targets and print 'em */
1659 next
= dm_get_next_target(dmt
, next
, &start
, &length
,
1660 &target_type
, ¶ms
);
1661 /* Skip if target type doesn't match */
1662 if (_switches
[TARGET_ARG
] &&
1663 (!target_type
|| strcmp(target_type
, _target
)))
1666 if (!_switches
[EXEC_ARG
] || !_command
||
1667 _switches
[VERBOSE_ARG
])
1668 _display_dev(dmt
, name
);
1670 } else if (!_switches
[EXEC_ARG
] || !_command
||
1671 _switches
[VERBOSE_ARG
]) {
1672 if (!matched
&& _switches
[VERBOSE_ARG
])
1674 if (multiple_devices
&& !_switches
[VERBOSE_ARG
])
1675 printf("%s: ", name
);
1677 /* Suppress encryption key */
1678 if (!_switches
[SHOWKEYS_ARG
] &&
1679 cmdno
== DM_DEVICE_TABLE
&&
1680 !strcmp(target_type
, "crypt")) {
1682 while (*c
&& *c
!= ' ')
1686 while (*c
&& *c
!= ' ')
1689 printf("%" PRIu64
" %" PRIu64
" %s %s",
1690 start
, length
, target_type
, params
);
1697 if (multiple_devices
&& _switches
[VERBOSE_ARG
] && matched
&& !ls_only
)
1700 if (matched
&& _switches
[EXEC_ARG
] && _command
&& !_exec_command(name
))
1706 dm_task_destroy(dmt
);
1710 /* Show target names and their version numbers */
1711 static int _targets(CMD_ARGS
)
1714 struct dm_task
*dmt
;
1715 struct dm_versions
*target
;
1716 struct dm_versions
*last_target
;
1718 if (!(dmt
= dm_task_create(DM_DEVICE_LIST_VERSIONS
)))
1721 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1724 if (!dm_task_run(dmt
))
1727 target
= dm_task_get_versions(dmt
);
1729 /* Fetch targets and print 'em */
1731 last_target
= target
;
1733 printf("%-16s v%d.%d.%d\n", target
->name
, target
->version
[0],
1734 target
->version
[1], target
->version
[2]);
1736 target
= (struct dm_versions
*)((char *) target
+ target
->next
);
1737 } while (last_target
!= target
);
1742 dm_task_destroy(dmt
);
1746 static int _info(CMD_ARGS
)
1750 struct dm_task
*dmt
;
1756 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
1757 return _process_all(cmd
, argc
, argv
, 0, _info
);
1761 if (!(dmt
= dm_task_create(DM_DEVICE_INFO
)))
1764 if (!_set_task_device(dmt
, name
, 0))
1767 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1770 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1773 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1776 if (!dm_task_run(dmt
))
1779 r
= _display_info(dmt
);
1782 dm_task_destroy(dmt
);
1786 static int _deps(CMD_ARGS
)
1790 struct dm_deps
*deps
;
1791 struct dm_task
*dmt
;
1792 struct dm_info info
;
1794 char dev_name
[PATH_MAX
];
1800 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
1801 return _process_all(cmd
, argc
, argv
, 0, _deps
);
1805 if (!(dmt
= dm_task_create(DM_DEVICE_DEPS
)))
1808 if (!_set_task_device(dmt
, name
, 0))
1811 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1814 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1817 if (_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
1820 if (!dm_task_run(dmt
))
1823 if (!dm_task_get_info(dmt
, &info
))
1826 if (!(deps
= dm_task_get_deps(dmt
)))
1830 printf("Device does not exist.\n");
1835 if (_switches
[VERBOSE_ARG
])
1838 if (multiple_devices
&& !_switches
[VERBOSE_ARG
])
1839 printf("%s: ", name
);
1840 printf("%d dependencies\t:", deps
->count
);
1842 for (i
= 0; i
< deps
->count
; i
++) {
1843 major
= (int) MAJOR(deps
->device
[i
]);
1844 minor
= (int) MINOR(deps
->device
[i
]);
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
);
1851 printf(" (%d, %d)", major
, minor
);
1855 if (multiple_devices
&& _switches
[VERBOSE_ARG
])
1861 dm_task_destroy(dmt
);
1865 static int _display_name(CMD_ARGS
)
1867 char dev_name
[PATH_MAX
];
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
);
1877 printf("%s\t(%d:%d)\n", names
->name
,
1878 (int) MAJOR(names
->dev
),
1879 (int) MINOR(names
->dev
));
1889 TR_DEVICE
=0, /* display device major:minor number */
1890 TR_BLKDEVNAME
, /* display device kernel name */
1903 static int _tree_switches
[NUM_TREEMODE
];
1905 #define TR_PRINT_ATTRIBUTE ( _tree_switches[TR_ACTIVE] || \
1906 _tree_switches[TR_RW] || \
1907 _tree_switches[TR_OPENCOUNT] || \
1908 _tree_switches[TR_UUID] )
1910 #define TR_PRINT_TARGETS ( _tree_switches[TR_TABLE] || \
1911 _tree_switches[TR_STATUS] )
1913 /* Compact - fewer newlines */
1914 #define TR_PRINT_COMPACT (_tree_switches[TR_COMPACT] && \
1915 !TR_PRINT_ATTRIBUTE && \
1918 /* FIXME Get rid of this */
1919 #define MAX_DEPTH 100
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 */
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 */
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
; /* -+- */
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
1969 *_tsym
= &_tsym_ascii
;
1972 * Tree drawing functions.
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;
1981 static void _out_char(const unsigned c
)
1983 /* Only first UTF-8 char counts */
1984 _cur_x
+= ((c
& 0xc0) != 0x80);
1986 if (!_tree_switches
[TR_TRUNCATE
]) {
1992 if (_cur_x
<= _termwidth
)
1995 if (_cur_x
== _termwidth
+ 1 && ((c
& 0xc0) != 0x80)) {
1996 if (_last_char
|| (c
& 0x80)) {
2007 static void _out_string(const char *str
)
2010 _out_char((unsigned char) *str
++);
2013 /* non-negative integers only */
2014 static unsigned _out_int(unsigned num
)
2016 unsigned digits
= 0;
2025 for (divi
= 1; num
/ divi
; divi
*= 10)
2028 for (divi
/= 10; divi
; divi
/= 10)
2029 _out_char('0' + (num
/ divi
) % 10);
2034 static void _out_newline(void)
2036 if (_last_char
&& _cur_x
== _termwidth
)
2037 putchar(_last_char
);
2043 static void _out_prefix(unsigned depth
)
2047 for (d
= 0; d
< depth
; d
++) {
2048 for (x
= _tree_width
[d
] + 1; x
> 0; x
--)
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
);
2061 static void _display_tree_attributes(struct dm_tree_node
*node
)
2065 const struct dm_info
*info
;
2067 uuid
= dm_tree_node_get_uuid(node
);
2068 info
= dm_tree_node_get_info(node
);
2073 if (_tree_switches
[TR_ACTIVE
]) {
2074 _out_string(attr
++ ? ", " : " [");
2075 _out_string(info
->suspended
? "SUSPENDED" : "ACTIVE");
2078 if (_tree_switches
[TR_RW
]) {
2079 _out_string(attr
++ ? ", " : " [");
2080 _out_string(info
->read_only
? "RO" : "RW");
2083 if (_tree_switches
[TR_OPENCOUNT
]) {
2084 _out_string(attr
++ ? ", " : " [");
2085 (void) _out_int((unsigned) info
->open_count
);
2088 if (_tree_switches
[TR_UUID
]) {
2089 _out_string(attr
++ ? ", " : " [");
2090 _out_string(uuid
&& *uuid
? uuid
: "");
2097 /* FIXME Display table or status line. (Disallow both?) */
2098 static void _display_tree_targets(struct dm_tree_node
*node
, unsigned depth
)
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
)
2108 const struct dm_info
*info
;
2109 int first_on_line
= 0;
2110 char dev_name
[PATH_MAX
];
2112 /* Sub-tree for targets has 2 more depth */
2113 if (depth
+ 2 > MAX_DEPTH
)
2116 name
= dm_tree_node_get_name(node
);
2118 if ((!name
|| !*name
) &&
2119 (!_tree_switches
[TR_DEVICE
] && !_tree_switches
[TR_BLKDEVNAME
]))
2122 /* Indicate whether there are more nodes at this depth */
2123 _tree_more
[depth
] = !last_child
;
2124 _tree_width
[depth
] = 0;
2129 if (!TR_PRINT_COMPACT
|| first_on_line
)
2132 /* Remember the starting point for compact */
2135 if (TR_PRINT_COMPACT
&& !first_on_line
)
2136 _out_string(_tree_more
[depth
] ? _tsym
->first_3
: _tsym
->single_3
);
2142 info
= dm_tree_node_get_info(node
);
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
);
2151 if (_tree_switches
[TR_DEVICE
]) {
2152 _out_string(name
? " (" : "(");
2153 (void) _out_int(info
->major
);
2155 (void) _out_int(info
->minor
);
2159 /* display additional info */
2160 if (TR_PRINT_ATTRIBUTE
)
2161 _display_tree_attributes(node
);
2163 if (TR_PRINT_COMPACT
)
2164 _tree_width
[depth
] = _cur_x
- offset
;
2166 if (!TR_PRINT_COMPACT
|| !has_children
)
2169 if (TR_PRINT_TARGETS
) {
2170 _tree_more
[depth
+ 1] = has_children
;
2171 _display_tree_targets(node
, depth
+ 2);
2176 * Walk the dependency tree
2178 static void _display_tree_walk_children(struct dm_tree_node
*node
,
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
;
2187 next_child
= dm_tree_next_child(&handle
, node
, inverted
);
2189 while ((child
= next_child
)) {
2190 next_child
= dm_tree_next_child(&handle
, node
, inverted
);
2192 dm_tree_node_num_children(child
, inverted
) ? 1 : 0;
2194 _display_tree_node(child
, depth
, first_child
,
2195 next_child
? 0U : 1U, has_children
);
2198 _display_tree_walk_children(child
, depth
+ 1);
2204 static int _add_dep(CMD_ARGS
)
2207 !dm_tree_add_dev(_dtree
, (unsigned) MAJOR(names
->dev
), (unsigned) MINOR(names
->dev
)))
2214 * Create and walk dependency tree
2216 static int _build_whole_deptree(const struct command
*cmd
)
2221 if (!(_dtree
= dm_tree_create()))
2224 if (!_process_all(cmd
, 0, NULL
, 0, _add_dep
))
2230 static int _display_tree(CMD_ARGS
)
2232 if (!_build_whole_deptree(cmd
))
2235 _display_tree_walk_children(dm_tree_find_node(_dtree
, 0, 0), 0);
2241 * Report device information
2244 /* dm specific display functions */
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
)))
2251 const int32_t value
= *(const int32_t *)data
;
2253 return dm_report_field_int32(rh
, field
, &value
);
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
)))
2261 const uint32_t value
= *(const int32_t *)data
;
2263 return dm_report_field_uint32(rh
, field
, &value
);
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
)))
2271 const char *name
= dm_task_get_name((const struct dm_task
*) data
);
2273 return dm_report_field_string(rh
, field
, &name
);
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
)))
2284 if ((name
= dm_task_get_name_mangled((const struct dm_task
*) data
))) {
2285 r
= dm_report_field_string(rh
, field
, (const char **) &name
);
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
)))
2300 if ((name
= dm_task_get_name_unmangled((const struct dm_task
*) data
))) {
2301 r
= dm_report_field_string(rh
, field
, (const char **) &name
);
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
)))
2313 const char *uuid
= dm_task_get_uuid((const struct dm_task
*) data
);
2315 if (!uuid
|| !*uuid
)
2318 return dm_report_field_string(rh
, field
, &uuid
);
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
)))
2328 if (!dm_task_get_read_ahead((const struct dm_task
*) data
, &value
))
2331 return dm_report_field_uint32(rh
, field
, &value
);
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
)))
2339 char dev_name
[PATH_MAX
];
2340 const char *s
= dev_name
;
2341 const struct dm_info
*info
= data
;
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
);
2349 return dm_report_field_string(rh
, field
, &s
);
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
)))
2358 const char *s
= buf
;
2359 const struct dm_info
*info
= data
;
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';
2367 return dm_report_field_string(rh
, field
, &s
);
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
,
2374 void *private __attribute__((unused
)))
2376 const struct dm_info
*info
= data
;
2378 if (info
->live_table
) {
2379 if (info
->inactive_table
)
2380 dm_report_field_set_value(field
, "Both", NULL
);
2382 dm_report_field_set_value(field
, "Live", NULL
);
2386 if (info
->inactive_table
)
2387 dm_report_field_set_value(field
, "Inactive", NULL
);
2389 dm_report_field_set_value(field
, "None", NULL
);
2394 static int _dm_info_suspended_disp(struct dm_report
*rh
,
2395 struct dm_pool
*mem
__attribute__((unused
)),
2396 struct dm_report_field
*field
,
2398 void *private __attribute__((unused
)))
2400 const struct dm_info
*info
= data
;
2402 if (info
->suspended
)
2403 dm_report_field_set_value(field
, "Suspended", NULL
);
2405 dm_report_field_set_value(field
, "Active", NULL
);
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
,
2414 void *private __attribute__((unused
)))
2416 const struct dm_info
*info
= data
;
2418 if (info
->read_only
)
2419 dm_report_field_set_value(field
, "Read-only", NULL
);
2421 dm_report_field_set_value(field
, "Writeable", NULL
);
2427 static int _dm_info_devno_disp(struct dm_report
*rh
, struct dm_pool
*mem
,
2428 struct dm_report_field
*field
, const void *data
,
2431 char buf
[PATH_MAX
], *repstr
;
2432 const struct dm_info
*info
= data
;
2434 if (!dm_pool_begin_object(mem
, 8)) {
2435 log_error("dm_pool_begin_object failed");
2440 if (!dm_device_get_name(info
->major
, info
->minor
,
2445 if (dm_snprintf(buf
, sizeof(buf
), "%d:%d",
2446 info
->major
, info
->minor
) < 0) {
2447 log_error("dm_pool_alloc failed");
2452 if (!dm_pool_grow_object(mem
, buf
, strlen(buf
) + 1)) {
2453 log_error("dm_pool_grow_object failed");
2457 repstr
= dm_pool_end_object(mem
);
2458 dm_report_field_set_value(field
, repstr
, repstr
);
2462 dm_pool_abandon_object(mem
);
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
)
2470 const struct dm_tree_node
*node
= data
;
2471 struct dm_tree_node
*parent
;
2477 if (!dm_pool_begin_object(mem
, 16)) {
2478 log_error("dm_pool_begin_object failed");
2482 while ((parent
= dm_tree_next_child(&t
, node
, inverted
))) {
2483 name
= dm_tree_node_get_name(parent
);
2484 if (!name
|| !*name
)
2486 if (!first_node
&& !dm_pool_grow_object(mem
, ",", 1)) {
2487 log_error("dm_pool_grow_object failed");
2490 if (!dm_pool_grow_object(mem
, name
, 0)) {
2491 log_error("dm_pool_grow_object failed");
2498 if (!dm_pool_grow_object(mem
, "\0", 1)) {
2499 log_error("dm_pool_grow_object failed");
2503 repstr
= dm_pool_end_object(mem
);
2504 dm_report_field_set_value(field
, repstr
, repstr
);
2508 dm_pool_abandon_object(mem
);
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)
2517 return _dm_tree_names(rh
, mem
, field
, data
, private, 0);
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)
2525 return _dm_tree_names(rh
, mem
, field
, data
, private, 1);
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)
2532 const struct dm_tree_node
*node
= data
;
2533 struct dm_tree_node
*parent
;
2535 const struct dm_info
*info
;
2537 char buf
[DM_MAX_TYPE_NAME
], *repstr
;
2539 if (!dm_pool_begin_object(mem
, 16)) {
2540 log_error("dm_pool_begin_object failed");
2544 while ((parent
= dm_tree_next_child(&t
, node
, 1))) {
2545 info
= dm_tree_node_get_info(parent
);
2546 if (!info
->major
&& !info
->minor
)
2548 if (!first_node
&& !dm_pool_grow_object(mem
, ",", 1)) {
2549 log_error("dm_pool_grow_object failed");
2552 if (dm_snprintf(buf
, sizeof(buf
), "%d:%d",
2553 info
->major
, info
->minor
) < 0) {
2554 log_error("dm_snprintf failed");
2557 if (!dm_pool_grow_object(mem
, buf
, 0)) {
2558 log_error("dm_pool_grow_object failed");
2565 if (!dm_pool_grow_object(mem
, "\0", 1)) {
2566 log_error("dm_pool_grow_object failed");
2570 repstr
= dm_pool_end_object(mem
);
2571 dm_report_field_set_value(field
, repstr
, repstr
);
2575 dm_pool_abandon_object(mem
);
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)
2584 const struct dm_tree_node
*node
= data
;
2585 int num_parent
= dm_tree_node_num_children(node
, 1);
2587 return dm_report_field_int(rh
, field
, &num_parent
);
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
)
2594 const struct dm_deps
*deps
= data
;
2595 char buf
[PATH_MAX
], *repstr
;
2599 if (!dm_pool_begin_object(mem
, 16)) {
2600 log_error("dm_pool_begin_object failed");
2604 for (i
= 0; i
< deps
->count
; i
++) {
2605 major
= (int) MAJOR(deps
->device
[i
]);
2606 minor
= (int) MINOR(deps
->device
[i
]);
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
);
2615 else if (dm_snprintf(buf
, sizeof(buf
), "%d:%d",
2616 major
, minor
) < 0) {
2617 log_error("dm_snprintf failed");
2621 if (!dm_pool_grow_object(mem
, buf
, 0)) {
2622 log_error("dm_pool_grow_object failed");
2626 if (i
+ 1 < deps
->count
&& !dm_pool_grow_object(mem
, ",", 1)) {
2627 log_error("dm_pool_grow_object failed");
2632 if (!dm_pool_grow_object(mem
, "\0", 1)) {
2633 log_error("dm_pool_grow_object failed");
2637 repstr
= dm_pool_end_object(mem
);
2638 dm_report_field_set_value(field
, repstr
, repstr
);
2642 dm_pool_abandon_object(mem
);
2646 static int _dm_deps_disp(struct dm_report
*rh
, struct dm_pool
*mem
,
2647 struct dm_report_field
*field
, const void *data
,
2650 return _dm_deps_disp_common(rh
, mem
, field
, data
, private, 0);
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)
2657 return _dm_deps_disp_common(rh
, mem
, field
, data
, private, 1);
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
)))
2665 return dm_report_field_string(rh
, field
, (const char *const *) data
);
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
)))
2674 return dm_report_field_string(rh
, field
, (const char *const *) data
);
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
)))
2683 return dm_report_field_string(rh
, field
, (const char *const *) data
);
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
)))
2692 return dm_report_field_string(rh
, field
, (const char *const *) data
);
2695 static void *_task_get_obj(void *obj
)
2697 return ((struct dmsetup_report_obj
*)obj
)->task
;
2700 static void *_info_get_obj(void *obj
)
2702 return ((struct dmsetup_report_obj
*)obj
)->info
;
2705 static void *_deps_get_obj(void *obj
)
2707 return dm_task_get_deps(((struct dmsetup_report_obj
*)obj
)->deps_task
);
2710 static void *_tree_get_obj(void *obj
)
2712 return ((struct dmsetup_report_obj
*)obj
)->tree_node
;
2715 static void *_split_name_get_obj(void *obj
)
2717 return ((struct dmsetup_report_obj
*)obj
)->split_name
;
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
},
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},
2736 static const struct dm_report_field_type _report_fields
[] = {
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.")
2743 /* FIXME Next one should be INFO */
2744 FIELD_F(TASK
, NUM
, "RAhead", 6, dm_read_ahead
, "read_ahead", "Read ahead in sectors.")
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.")
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.")
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.")
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.")
2772 {0, 0, 0, 0, "", "", NULL
, NULL
},
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";
2784 static int _report_init(const struct command
*cmd
)
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;
2795 if (cmd
&& !strcmp(cmd
->name
, "splitname"))
2796 options
= (char *) splitname_report_options
;
2798 /* emulate old dmsetup behaviour */
2799 if (_switches
[NOHEADINGS_ARG
]) {
2805 if (_switches
[UNBUFFERED_ARG
])
2808 if (_switches
[ROWS_ARG
])
2809 columns_as_rows
= 1;
2811 if (_switches
[UNQUOTED_ARG
])
2814 if (_switches
[NAMEPREFIXES_ARG
]) {
2819 if (_switches
[OPTIONS_ARG
] && _string_args
[OPTIONS_ARG
]) {
2820 if (*_string_args
[OPTIONS_ARG
] != '+')
2821 options
= _string_args
[OPTIONS_ARG
];
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.");
2829 if (dm_snprintf(options
, len
, "%s,%s",
2830 default_report_options
,
2831 &_string_args
[OPTIONS_ARG
][1]) < 0) {
2832 err("snprintf failed");
2838 if (_switches
[SORT_ARG
] && _string_args
[SORT_ARG
]) {
2839 keys
= _string_args
[SORT_ARG
];
2841 if (cmd
&& (!strcmp(cmd
->name
, "status") || !strcmp(cmd
->name
, "table"))) {
2842 err("--sort is not yet supported with status and table");
2847 if (_switches
[SEPARATOR_ARG
] && _string_args
[SEPARATOR_ARG
]) {
2848 separator
= _string_args
[SEPARATOR_ARG
];
2853 flags
|= DM_REPORT_OUTPUT_ALIGNED
;
2856 flags
|= DM_REPORT_OUTPUT_BUFFERED
;
2859 flags
|= DM_REPORT_OUTPUT_HEADINGS
;
2862 flags
|= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX
;
2865 flags
|= DM_REPORT_OUTPUT_FIELD_UNQUOTED
;
2867 if (columns_as_rows
)
2868 flags
|= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS
;
2870 if (!(_report
= dm_report_init(&_report_type
,
2871 _report_types
, _report_fields
,
2872 options
, separator
, flags
, keys
, NULL
)))
2875 if ((_report_type
& DR_TREE
) && !_build_whole_deptree(cmd
)) {
2876 err("Internal device dependency tree creation failed.");
2881 dm_report_set_output_field_name_prefix(_report
, "dm_");
2886 if (!strcasecmp(options
, "help") || !strcmp(options
, "?"))
2898 static int _ls(CMD_ARGS
)
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);
2906 return _process_all(cmd
, argc
, argv
, 0, _display_name
);
2909 static int _mangle(CMD_ARGS
)
2912 char *new_name
= NULL
;
2913 struct dm_task
*dmt
;
2914 struct dm_info info
;
2921 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
2922 return _process_all(cmd
, argc
, argv
, 0, _mangle
);
2926 if (!(dmt
= dm_task_create(DM_DEVICE_STATUS
)))
2929 if (!(_set_task_device(dmt
, name
, 0)))
2932 if (!_switches
[CHECKS_ARG
] && !dm_task_enable_checks(dmt
))
2935 if (!dm_task_run(dmt
))
2938 if (!dm_task_get_info(dmt
, &info
) || !info
.exists
)
2941 target_format
= _switches
[MANGLENAME_ARG
] ? _int_args
[MANGLENAME_ARG
]
2942 : DEFAULT_DM_NAME_MANGLING
;
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
);
2950 if (target_format
== DM_STRING_MANGLING_NONE
) {
2951 if (!(new_name
= dm_task_get_name_unmangled(dmt
)))
2954 else if (!(new_name
= dm_task_get_name_mangled(dmt
)))
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
);
2964 log_print("%s: renaming to %s", name
, new_name
);
2966 /* Rename to correct form of the name. */
2967 r
= _do_rename(name
, new_name
, NULL
);
2971 dm_task_destroy(dmt
);
2975 static int _help(CMD_ARGS
);
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>]",
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
}
3018 static void _usage(FILE *out
)
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");
3043 static void _losetup_usage(FILE *out
)
3045 fprintf(out
, "Usage:\n\n");
3046 fprintf(out
, "losetup [-d|-a] [-e encryption] "
3047 "[-o offset] [-f|loop_device] [file]\n\n");
3050 static int _help(CMD_ARGS
)
3054 if (_switches
[COLS_ARG
]) {
3055 _switches
[OPTIONS_ARG
] = 1;
3056 _string_args
[OPTIONS_ARG
] = (char *) "help";
3057 _switches
[SORT_ARG
] = 0;
3060 dm_report_free(_report
);
3063 (void) _report_init(cmd
);
3069 static struct command
*_find_command(const char *name
)
3073 for (i
= 0; _commands
[i
].name
; i
++)
3074 if (!strcmp(_commands
[i
].name
, name
))
3075 return _commands
+ i
;
3080 static int _process_tree_options(const char *options
)
3082 const char *s
, *end
;
3083 struct winsize winsz
;
3086 /* Symbol set default */
3087 if (!strcmp(nl_langinfo(CODESET
), "UTF-8"))
3090 _tsym
= &_tsym_ascii
;
3093 _tree_switches
[TR_DEVICE
] = 1;
3094 _tree_switches
[TR_TRUNCATE
] = 1;
3097 for (s
= options
; s
&& *s
; s
++) {
3099 for (end
= s
; *end
&& *end
!= ','; end
++, len
++)
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
))
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;
3132 fprintf(stderr
, "Tree options not recognised: %s\n", s
);
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;
3149 * Returns the full absolute path, or NULL if the path could
3152 static char *_get_abspath(const char *path
)
3156 #ifdef HAVE_CANONICALIZE_FILE_NAME
3157 _path
= canonicalize_file_name(path
);
3159 /* FIXME Provide alternative */
3160 log_error(INTERNAL_ERROR
"Unimplemented _get_abspath.");
3166 static char *parse_loop_device_name(const char *dev
, const char *dev_dir
)
3169 char *device
= NULL
;
3171 if (!(buf
= dm_malloc(PATH_MAX
)))
3174 if (dev
[0] == '/') {
3175 if (!(device
= _get_abspath(dev
)))
3178 if (strncmp(device
, dev_dir
, strlen(dev_dir
)))
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
)] != '/')
3187 strncpy(buf
, strrchr(device
, '/') + 1, PATH_MAX
- 1);
3188 buf
[PATH_MAX
- 1] = '\0';
3192 /* check for device number */
3193 if (!strncmp(dev
, "loop", strlen("loop")))
3194 strncpy(buf
, dev
, (size_t) PATH_MAX
);
3209 * create a table for a mapped device using the loop target.
3211 static int _loop_table(char *table
, size_t tlen
, char *file
,
3212 char *dev
__attribute__((unused
)), off_t off
)
3215 off_t size
, sectors
;
3217 #ifdef HAVE_SYS_STATVFS_H
3218 struct statvfs fsbuf
;
3222 if (!_switches
[READ_ONLY
])
3223 fd
= open(file
, O_RDWR
);
3226 _switches
[READ_ONLY
]++;
3227 fd
= open(file
, O_RDONLY
);
3233 if (fstat(fd
, &fbuf
))
3236 size
= (fbuf
.st_size
- off
);
3237 sectors
= size
>> SECTOR_SHIFT
;
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
);
3244 #ifdef HAVE_SYS_STATVFS_H
3245 if (fstatvfs(fd
, &fsbuf
))
3248 /* FIXME Fragment size currently unused */
3249 blksize
= fsbuf
.f_frsize
;
3253 log_sys_error("close", file
);
3255 if (dm_snprintf(table
, tlen
, "%llu %llu loop %s %llu\n", 0ULL,
3256 (long long unsigned)sectors
, file
, (long long unsigned)off
) < 0)
3259 if (_switches
[VERBOSE_ARG
] > 1)
3260 fprintf(stderr
, "Table: %s\n", table
);
3265 if (fd
> -1 && close(fd
))
3266 log_sys_error("close", file
);
3271 static int _process_losetup_switches(const char *base
, int *argc
, char ***argv
,
3272 const char *dev_dir
)
3275 int encrypt_loop
= 0, delete = 0, find
= 0, show_all
= 0;
3276 char *device_name
= NULL
;
3277 char *loop_file
= NULL
;
3280 #ifdef HAVE_GETOPTLONG
3281 static struct option long_options
[] = {
3287 optind
= OPTIND_INIT
;
3288 while ((c
= GETOPTLONG_FN(*argc
, *argv
, "ade:fo:v",
3289 long_options
, NULL
)) != -1 ) {
3290 if (c
== ':' || c
== '?')
3301 offset
= atoi(optarg
);
3303 _switches
[VERBOSE_ARG
]++;
3310 fprintf(stderr
, "%s: Sorry, cryptoloop is not yet implemented "
3311 "in this version.\n", base
);
3316 fprintf(stderr
, "%s: Sorry, show all is not yet implemented "
3317 "in this version.\n", base
);
3322 fprintf(stderr
, "%s: Sorry, find is not yet implemented "
3323 "in this version.\n", base
);
3329 fprintf(stderr
, "%s: Please specify loop_device.\n", base
);
3330 _losetup_usage(stderr
);
3334 if (!(device_name
= parse_loop_device_name((*argv
)[0], dev_dir
))) {
3335 fprintf(stderr
, "%s: Could not parse loop_device %s\n",
3337 _losetup_usage(stderr
);
3344 (*argv
)[1] = device_name
;
3345 (*argv
)[0] = (char *) "remove";
3351 fprintf(stderr
, "%s: Too few arguments\n", base
);
3352 _losetup_usage(stderr
);
3353 dm_free(device_name
);
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",
3361 _losetup_usage(stderr
);
3362 dm_free(device_name
);
3366 _table
= dm_malloc(LOOP_TABLE_SIZE
);
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
);
3373 _switches
[TABLE_ARG
]++;
3375 (*argv
)[0] = (char *) "create";
3376 (*argv
)[1] = device_name
;
3381 static int _process_options(const char *options
)
3383 const char *s
, *end
;
3386 /* Tree options are processed separately. */
3387 if (_switches
[TREE_ARG
])
3388 return _process_tree_options(_string_args
[OPTIONS_ARG
]);
3390 /* Column options are processed separately by _report_init (called later). */
3391 if (_switches
[COLS_ARG
])
3394 /* No options specified. */
3395 if (!_switches
[OPTIONS_ARG
])
3399 _dev_name_type
= DN_DEVNO
;
3402 for (s
= options
; s
&& *s
; s
++) {
3404 for (end
= s
; *end
&& *end
!= ','; end
++, len
++)
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
;
3413 fprintf(stderr
, "Option not recognised: %s\n", s
);
3425 static int _process_switches(int *argc
, char ***argv
, const char *dev_dir
)
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
},
3479 struct option long_options
;
3483 * Zero all the index counts.
3485 memset(&_switches
, 0, sizeof(_switches
));
3486 memset(&_int_args
, 0, sizeof(_int_args
));
3487 _read_ahead_flags
= 0;
3489 if (!(namebase
= strdup((*argv
)[0]))) {
3490 fprintf(stderr
, "Failed to duplicate name.\n");
3493 base
= dm_basename(namebase
);
3495 if (!strcmp(base
, "devmap_name")) {
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";
3505 _int_args
[MAJOR_ARG
] = atoi((*argv
)[1]);
3506 _int_args
[MINOR_ARG
] = atoi((*argv
)[2]);
3509 } else if ((*argc
== 2) &&
3510 (2 == sscanf((*argv
)[1], "%i:%i",
3511 &_int_args
[MAJOR_ARG
],
3512 &_int_args
[MINOR_ARG
]))) {
3516 fprintf(stderr
, "Usage: devmap_name <major> <minor>\n");
3520 (*argv
)[0] = (char *) "info";
3524 if (!strcmp(base
, "losetup") || !strcmp(base
, "dmlosetup")){
3525 r
= _process_losetup_switches(base
, argc
, argv
, dev_dir
);
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
== '?')
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
);
3550 if (c
== 'm' || ind
== MINOR_ARG
) {
3551 _switches
[MINOR_ARG
]++;
3552 _int_args
[MINOR_ARG
] = atoi(optarg
);
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
;
3560 if (ind
== SEPARATOR_ARG
) {
3561 _switches
[SEPARATOR_ARG
]++;
3562 _string_args
[SEPARATOR_ARG
] = optarg
;
3564 if (c
== 'O' || ind
== SORT_ARG
) {
3565 _switches
[SORT_ARG
]++;
3566 _string_args
[SORT_ARG
] = optarg
;
3568 if (c
== 'v' || ind
== VERBOSE_ARG
)
3569 _switches
[VERBOSE_ARG
]++;
3570 if (c
== 'u' || ind
== UUID_ARG
) {
3571 _switches
[UUID_ARG
]++;
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
);
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
);
3596 if (c
== 'U' || ind
== UID_ARG
) {
3597 _switches
[UID_ARG
]++;
3598 _int_args
[UID_ARG
] = atoi(optarg
);
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);
3605 if (ind
== EXEC_ARG
) {
3606 _switches
[EXEC_ARG
]++;
3609 if (ind
== TARGET_ARG
) {
3610 _switches
[TARGET_ARG
]++;
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
;
3624 log_error("Unknown name mangling mode");
3627 dm_set_name_mangling_mode((dm_string_mangling_t
) _int_args
[MANGLENAME_ARG
]);
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
;
3646 for (s
= optarg
; isspace(*s
); 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
]);
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.");
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
]++;
3682 if (_switches
[VERBOSE_ARG
] > 1)
3683 dm_log_init_verbose(_switches
[VERBOSE_ARG
] - 1);
3685 if ((_switches
[MAJOR_ARG
] && !_switches
[MINOR_ARG
]) ||
3686 (!_switches
[MAJOR_ARG
] && _switches
[MINOR_ARG
])) {
3687 fprintf(stderr
, "Please specify both major number and "
3692 if (!_process_options(_string_args
[OPTIONS_ARG
]))
3695 if (_switches
[TABLE_ARG
] && _switches
[NOTABLE_ARG
]) {
3696 fprintf(stderr
, "--table and --notable are incompatible.\n");
3700 if (_switches
[ADD_NODE_ON_RESUME_ARG
] && _switches
[ADD_NODE_ON_CREATE_ARG
]) {
3701 fprintf(stderr
, "--addnodeonresume and --addnodeoncreate are incompatible.\n");
3710 int main(int argc
, char **argv
)
3713 const char *dev_dir
;
3714 const struct command
*cmd
;
3715 int multiple_devices
;
3717 (void) setlocale(LC_ALL
, "");
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");
3726 dev_dir
= DEFAULT_DM_DEV_DIR
;
3728 if (!_process_switches(&argc
, &argv
, dev_dir
)) {
3729 fprintf(stderr
, "Couldn't process command line.\n");
3733 if (_switches
[HELP_ARG
]) {
3734 cmd
= _find_command("help");
3738 if (_switches
[VERSION_ARG
]) {
3739 cmd
= _find_command("version");
3748 if (!(cmd
= _find_command(argv
[0]))) {
3749 fprintf(stderr
, "Unknown command\n");
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");
3761 if (!_switches
[COLS_ARG
] && !strcmp(cmd
->name
, "splitname"))
3762 _switches
[COLS_ARG
]++;
3764 if (!strcmp(cmd
->name
, "mangle"))
3765 dm_set_name_mangling_mode(DM_STRING_MANGLING_NONE
);
3767 if (_switches
[COLS_ARG
]) {
3768 if (!_report_init(cmd
))
3771 if (!strcmp(cmd
->name
, "info"))
3772 r
= 0; /* info -c -o help */
3777 #ifdef UDEV_SYNC_SUPPORT
3778 if (!_set_up_udev_support(dev_dir
))
3783 multiple_devices
= (cmd
->repeatable_cmd
&& argc
!= 2 &&
3784 (argc
!= 1 || (!_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])));
3786 if (!cmd
->fn(cmd
, argc
--, argv
++, NULL
, multiple_devices
)) {
3787 fprintf(stderr
, "Command failed\n");
3790 } while (cmd
->repeatable_cmd
&& argc
> 1);
3796 dm_report_output(_report
);
3797 dm_report_free(_report
);
3801 dm_tree_free(_dtree
);