2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004-2008 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>
48 # define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
52 /* FIXME Unused so far */
53 #undef HAVE_SYS_STATVFS_H
55 #ifdef HAVE_SYS_STATVFS_H
56 # include <sys/statvfs.h>
59 #ifdef HAVE_SYS_IOCTL_H
60 # include <sys/ioctl.h>
67 #ifdef HAVE_GETOPTLONG
69 # define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
70 # define OPTIND_INIT 0
76 # define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))
77 # define OPTIND_INIT 1
80 #ifndef TEMP_FAILURE_RETRY
81 # define TEMP_FAILURE_RETRY(expression) \
83 ({ long int __result; \
84 do __result = (long int) (expression); \
85 while (__result == -1L && errno == EINTR); \
92 # define MAJOR(x) major((x))
93 # define MINOR(x) minor((x))
94 # define MKDEV(x,y) makedev((x),(y))
97 #define LINE_SIZE 4096
99 #define LOOP_TABLE_SIZE (PATH_MAX + 255)
101 #define DEFAULT_DM_DEV_DIR "/dev/"
103 #define DM_DEV_DIR_ENV_VAR_NAME "DM_DEV_DIR"
104 #define DM_UDEV_COOKIE_ENV_VAR_NAME "DM_UDEV_COOKIE"
106 /* FIXME Should be imported */
107 #ifndef DM_MAX_TYPE_NAME
108 # define DM_MAX_TYPE_NAME 16
111 /* FIXME Should be elsewhere */
112 #define SECTOR_SHIFT 9L
114 #define err(msg, x...) fprintf(stderr, msg "\n", ##x)
117 * We have only very simple switches ATM.
163 DR_TREE = 8, /* Complete dependency tree required */
167 static int _switches[NUM_SWITCHES];
168 static int _int_args[NUM_SWITCHES];
169 static char *_string_args[NUM_SWITCHES];
170 static int _num_devices;
173 static char *_target;
174 static char *_command;
175 static uint32_t _read_ahead_flags;
176 static uint32_t _udev_cookie;
177 static int _udev_only;
178 static struct dm_tree *_dtree;
179 static struct dm_report *_report;
180 static report_type_t _report_type;
186 typedef int (*command_fn) (int argc, char **argv, void *data);
196 static int _parse_line(struct dm_task *dmt, char *buffer, const char *file,
199 char ttype[LINE_SIZE], *ptr, *comment;
200 unsigned long long start, size;
203 /* trim trailing space */
204 for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr--)
205 if (!isspace((int) *ptr))
210 /* trim leading space */
211 for (ptr = buffer; *ptr && isspace((int) *ptr); ptr++)
214 if (!*ptr || *ptr == '#')
217 if (sscanf(ptr, "%llu %llu %s %n",
218 &start, &size, ttype, &n) < 3) {
219 err("Invalid format on line %d of table %s", line, file);
224 if ((comment = strchr(ptr, (int) '#')))
227 if (!dm_task_add_target(dmt, start, size, ttype, ptr))
233 static int _parse_file(struct dm_task *dmt, const char *file)
236 size_t buffer_size = 0;
240 /* one-line table on cmdline */
242 return _parse_line(dmt, _table, "", ++line);
244 /* OK for empty stdin */
246 if (!(fp = fopen(file, "r"))) {
247 err("Couldn't open '%s' for reading", file);
254 buffer_size = LINE_SIZE;
255 if (!(buffer = dm_malloc(buffer_size))) {
256 err("Failed to malloc line buffer.");
260 while (fgets(buffer, (int) buffer_size, fp))
262 while (getline(&buffer, &buffer_size, fp) > 0)
264 if (!_parse_line(dmt, buffer, file ? : "on stdin", ++line))
270 memset(buffer, 0, buffer_size);
276 if (file && fclose(fp))
277 fprintf(stderr, "%s: fclose failed: %s", file, strerror(errno));
282 struct dm_split_name {
289 struct dmsetup_report_obj {
290 struct dm_task *task;
291 struct dm_info *info;
292 struct dm_task *deps_task;
293 struct dm_tree_node *tree_node;
294 struct dm_split_name *split_name;
297 static struct dm_task *_get_deps_task(int major, int minor)
302 if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
305 if (!dm_task_set_major(dmt, major) ||
306 !dm_task_set_minor(dmt, minor))
309 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
312 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
315 if (!dm_task_run(dmt))
318 if (!dm_task_get_info(dmt, &info))
327 dm_task_destroy(dmt);
331 static char *_extract_uuid_prefix(const char *uuid, const int separator)
334 char *uuid_prefix = NULL;
338 ptr = strchr(uuid, separator);
340 len = ptr ? ptr - uuid : 0;
341 if (!(uuid_prefix = dm_malloc(len + 1))) {
342 log_error("Failed to allocate memory to extract uuid prefix.");
347 memcpy(uuid_prefix, uuid, len);
349 uuid_prefix[len] = '\0';
354 static struct dm_split_name *_get_split_name(const char *uuid, const char *name,
357 struct dm_split_name *split_name;
359 if (!(split_name = dm_malloc(sizeof(*split_name)))) {
360 log_error("Failed to allocate memory to split device name "
365 split_name->subsystem = _extract_uuid_prefix(uuid, separator);
366 split_name->vg_name = split_name->lv_name =
367 split_name->lv_layer = (char *) "";
369 if (!strcmp(split_name->subsystem, "LVM") &&
370 (!(split_name->vg_name = dm_strdup(name)) ||
371 !dm_split_lvm_name(NULL, NULL, &split_name->vg_name,
372 &split_name->lv_name, &split_name->lv_layer)))
373 log_error("Failed to allocate memory to split LVM name "
379 static void _destroy_split_name(struct dm_split_name *split_name)
382 * lv_name and lv_layer are allocated within the same block
383 * of memory as vg_name so don't need to be freed separately.
385 if (!strcmp(split_name->subsystem, "LVM"))
386 dm_free(split_name->vg_name);
388 dm_free(split_name->subsystem);
392 static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
394 struct dmsetup_report_obj obj;
398 fprintf(stderr, "Device does not exist.\n");
404 obj.deps_task = NULL;
405 obj.split_name = NULL;
407 if (_report_type & DR_TREE)
408 obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor);
410 if (_report_type & DR_DEPS)
411 obj.deps_task = _get_deps_task(info->major, info->minor);
413 if (_report_type & DR_NAME)
414 obj.split_name = _get_split_name(dm_task_get_uuid(dmt), dm_task_get_name(dmt), '-');
416 if (!dm_report_object(_report, &obj))
423 dm_task_destroy(obj.deps_task);
425 _destroy_split_name(obj.split_name);
429 static void _display_info_long(struct dm_task *dmt, struct dm_info *info)
435 printf("Device does not exist.\n");
439 printf("Name: %s\n", dm_task_get_name(dmt));
441 printf("State: %s%s\n",
442 info->suspended ? "SUSPENDED" : "ACTIVE",
443 info->read_only ? " (READ-ONLY)" : "");
445 /* FIXME Old value is being printed when it's being changed. */
446 if (dm_task_get_read_ahead(dmt, &read_ahead))
447 printf("Read Ahead: %" PRIu32 "\n", read_ahead);
449 if (!info->live_table && !info->inactive_table)
450 printf("Tables present: None\n");
452 printf("Tables present: %s%s%s\n",
453 info->live_table ? "LIVE" : "",
454 info->live_table && info->inactive_table ? " & " : "",
455 info->inactive_table ? "INACTIVE" : "");
457 if (info->open_count != -1)
458 printf("Open count: %d\n", info->open_count);
460 printf("Event number: %" PRIu32 "\n", info->event_nr);
461 printf("Major, minor: %d, %d\n", info->major, info->minor);
463 if (info->target_count != -1)
464 printf("Number of targets: %d\n", info->target_count);
466 if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
467 printf("UUID: %s\n", uuid);
472 static int _display_info(struct dm_task *dmt)
476 if (!dm_task_get_info(dmt, &info))
479 if (!_switches[COLS_ARG])
480 _display_info_long(dmt, &info);
482 /* FIXME return code */
483 _display_info_cols(dmt, &info);
485 return info.exists ? 1 : 0;
488 static int _set_task_device(struct dm_task *dmt, const char *name, int optional)
491 if (!dm_task_set_name(dmt, name))
493 } else if (_switches[UUID_ARG]) {
494 if (!dm_task_set_uuid(dmt, _uuid))
496 } else if (_switches[MAJOR_ARG] && _switches[MINOR_ARG]) {
497 if (!dm_task_set_major(dmt, _int_args[MAJOR_ARG]) ||
498 !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
500 } else if (!optional) {
501 fprintf(stderr, "No device specified.\n");
508 static int _load(int argc, char **argv, void *data __attribute__((unused)))
512 const char *file = NULL;
513 const char *name = NULL;
515 if (_switches[NOTABLE_ARG]) {
516 err("--notable only available when creating new device\n");
520 if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
522 err("Please specify device.\n");
528 } else if (argc > 2) {
529 err("Too many command line arguments.\n");
536 if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
539 if (!_set_task_device(dmt, name, 0))
542 if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file))
545 if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
548 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
551 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
554 if (!dm_task_run(dmt))
559 if (_switches[VERBOSE_ARG])
560 r = _display_info(dmt);
563 dm_task_destroy(dmt);
568 static int _create(int argc, char **argv, void *data __attribute__((unused)))
572 const char *file = NULL;
574 uint16_t udev_flags = 0;
579 if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
582 if (!dm_task_set_name(dmt, argv[1]))
585 if (_switches[UUID_ARG] && !dm_task_set_uuid(dmt, _uuid))
588 if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file))
591 if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
594 if (_switches[MAJOR_ARG] && !dm_task_set_major(dmt, _int_args[MAJOR_ARG]))
597 if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
600 if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _int_args[UID_ARG]))
603 if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _int_args[GID_ARG]))
606 if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _int_args[MODE_ARG]))
609 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
612 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
615 if (_switches[READAHEAD_ARG] &&
616 !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG],
620 if (_switches[NOTABLE_ARG])
621 dm_udev_set_sync_support(0);
623 if (_switches[NOUDEVRULES_ARG])
624 udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
625 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
628 cookie = _udev_cookie;
630 udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
633 if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
640 (void) dm_udev_wait(cookie);
642 if (_switches[VERBOSE_ARG])
643 r = _display_info(dmt);
645 dm_task_destroy(dmt);
651 (void) dm_udev_wait(cookie);
652 dm_task_destroy(dmt);
657 static int _rename(int argc, char **argv, void *data __attribute__((unused)))
662 uint16_t udev_flags = 0;
664 if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
667 /* FIXME Kernel doesn't support uuid or device number here yet */
668 if (!_set_task_device(dmt, (argc == 3) ? argv[1] : NULL, 0))
671 if (_switches[SETUUID_ARG]) {
672 if (!dm_task_set_newuuid(dmt, argv[argc - 1]))
674 } else if (!dm_task_set_newname(dmt, argv[argc - 1]))
677 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
680 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
683 if (_switches[NOUDEVRULES_ARG])
684 udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
685 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
688 cookie = _udev_cookie;
690 udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
693 if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
701 (void) dm_udev_wait(cookie);
702 dm_task_destroy(dmt);
707 static int _message(int argc, char **argv, void *data __attribute__((unused)))
714 if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
717 if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) {
718 if (!_set_task_device(dmt, NULL, 0))
721 if (!_set_task_device(dmt, argv[1], 0))
727 if (!dm_task_set_sector(dmt, (uint64_t) atoll(argv[1])))
734 err("No message supplied.\n");
736 for (i = 0; i < argc; i++)
737 sz += strlen(argv[i]) + 1;
739 if (!(str = dm_zalloc(sz))) {
740 err("message string allocation failed");
744 for (i = 0; i < argc; i++) {
747 strcat(str, argv[i]);
750 if (!dm_task_set_message(dmt, str))
755 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
758 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
761 if (!dm_task_run(dmt))
767 dm_task_destroy(dmt);
772 static int _setgeometry(int argc, char **argv, void *data __attribute__((unused)))
777 if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY)))
780 if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) {
781 if (!_set_task_device(dmt, NULL, 0))
784 if (!_set_task_device(dmt, argv[1], 0))
790 if (!dm_task_set_geometry(dmt, argv[1], argv[2], argv[3], argv[4]))
793 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
796 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
800 if (!dm_task_run(dmt))
806 dm_task_destroy(dmt);
811 static int _splitname(int argc, char **argv, void *data __attribute__((unused)))
813 struct dmsetup_report_obj obj;
818 obj.deps_task = NULL;
819 obj.tree_node = NULL;
820 obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM",
823 r = dm_report_object(_report, &obj);
824 _destroy_split_name(obj.split_name);
829 static uint32_t _get_cookie_value(const char *str_value)
831 unsigned long int value;
834 if (!(value = strtoul(str_value, &p, 0)) ||
836 (value == ULONG_MAX && errno == ERANGE) ||
837 value > 0xFFFFFFFF) {
838 err("Incorrect cookie value");
842 return (uint32_t) value;
845 static int _udevflags(int args, char **argv, void *data __attribute__((unused)))
850 static const char *dm_flag_names[] = {"DISABLE_DM_RULES",
851 "DISABLE_SUBSYSTEM_RULES",
852 "DISABLE_DISK_RULES",
853 "DISABLE_OTHER_RULES",
855 "DISABLE_LIBRARY_FALLBACK",
859 if (!(cookie = _get_cookie_value(argv[1])))
862 flags = cookie >> DM_UDEV_FLAGS_SHIFT;
864 for (i = 0; i < DM_UDEV_FLAGS_SHIFT; i++)
865 if (1 << i & flags) {
866 if (i < DM_UDEV_FLAGS_SHIFT / 2 && dm_flag_names[i])
867 printf("DM_UDEV_%s_FLAG='1'\n", dm_flag_names[i]);
868 else if (i < DM_UDEV_FLAGS_SHIFT / 2)
870 * This is just a fallback. Each new DM flag
871 * should have its symbolic name assigned.
873 printf("DM_UDEV_FLAG%d='1'\n", i);
876 * We can't assign symbolic names to subsystem
877 * flags. Their semantics vary based on the
878 * subsystem that is currently used.
880 printf("DM_SUBSYSTEM_UDEV_FLAG%d='1'\n",
881 i - DM_UDEV_FLAGS_SHIFT / 2);
887 static int _udevcomplete(int argc, char **argv, void *data __attribute__((unused)))
891 if (!(cookie = _get_cookie_value(argv[1])))
895 * Strip flags from the cookie and use cookie magic instead.
896 * If the cookie has non-zero prefix and the base is zero then
897 * this one carries flags to control udev rules only and it is
898 * not meant to be for notification. Return with success in this
901 if (!(cookie &= ~DM_UDEV_FLAGS_MASK))
904 cookie |= DM_COOKIE_MAGIC << DM_UDEV_FLAGS_SHIFT;
906 return dm_udev_complete(cookie);
909 #ifndef UDEV_SYNC_SUPPORT
910 static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev-sync\" to enable.";
912 static int _udevcreatecookie(int argc, char **argv,
913 void *data __attribute__((unused)))
915 log_error(_cmd_not_supported);
920 static int _udevreleasecookie(int argc, char **argv,
921 void *data __attribute__((unused)))
923 log_error(_cmd_not_supported);
928 static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
930 log_error(_cmd_not_supported);
935 static int _udevcookies(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
937 log_error(_cmd_not_supported);
942 #else /* UDEV_SYNC_SUPPORT */
943 static int _set_up_udev_support(const char *dev_dir)
946 const char *udev_dev_dir;
947 size_t udev_dev_dir_len;
951 if (_switches[NOUDEVSYNC_ARG])
952 dm_udev_set_sync_support(0);
955 env = getenv(DM_UDEV_COOKIE_ENV_VAR_NAME);
956 if (env && *env && (_udev_cookie = _get_cookie_value(env)))
957 log_debug("Using udev transaction 0x%08" PRIX32
958 " defined by %s environment variable.",
960 DM_UDEV_COOKIE_ENV_VAR_NAME);
962 else if (_switches[UDEVCOOKIE_ARG])
963 log_debug("Using udev transaction 0x%08" PRIX32
964 " defined by --udevcookie option.",
967 if (!(udev = udev_new()) ||
968 !(udev_dev_dir = udev_get_dev_path(udev)) ||
970 log_error("Could not get udev dev path.");
973 udev_dev_dir_len = strlen(udev_dev_dir);
976 * Normally, there's always a fallback action by libdevmapper if udev
977 * has not done its job correctly, e.g. the nodes were not created.
978 * If using udev transactions by specifying existing cookie value,
979 * we need to disable node creation by libdevmapper completely,
980 * disabling any fallback actions, since any synchronisation happens
981 * at the end of the transaction only. We need to do this to prevent
982 * races between udev and libdevmapper but only in case udev "dev path"
983 * is the same as "dev path" used by libdevmapper.
986 /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */
987 if (udev_dev_dir[udev_dev_dir_len - 1] != '/')
988 dirs_diff = strncmp(dev_dir, udev_dev_dir, udev_dev_dir_len);
990 dirs_diff = strcmp(dev_dir, udev_dev_dir);
992 _udev_only = _udev_cookie && !dirs_diff;
995 log_debug("The path %s used for creating device nodes that is "
996 "set via DM_DEV_DIR environment variable differs from "
997 "the path %s that is used by udev. All warnings "
998 "about udev not working correctly while processing "
999 "particular nodes will be suppressed. These nodes "
1000 "and symlinks will be managed in each directory "
1001 "separately.", dev_dir, udev_dev_dir);
1002 dm_udev_set_checking(0);
1009 static int _udevcreatecookie(int argc, char **argv,
1010 void *data __attribute__((unused)))
1014 if (!dm_udev_create_cookie(&cookie))
1018 printf("0x%08" PRIX32 "\n", cookie);
1023 static int _udevreleasecookie(int argc, char **argv,
1024 void *data __attribute__((unused)))
1026 if (argv[1] && !(_udev_cookie = _get_cookie_value(argv[1])))
1029 if (!_udev_cookie) {
1030 log_error("No udev transaction cookie given.");
1034 return dm_udev_wait(_udev_cookie);
1037 static char _yes_no_prompt(const char *prompt, ...)
1043 if (c == '\n' || !c) {
1044 va_start(ap, prompt);
1045 vprintf(prompt, ap);
1049 if ((c = getchar()) == EOF) {
1055 if ((c == 'y') || (c == 'n'))
1057 } while (!ret || c != '\n');
1065 static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
1067 int max_id, id, sid;
1068 struct seminfo sinfo;
1069 struct semid_ds sdata;
1072 if (!_switches[YES_ARG]) {
1073 log_warn("This operation will destroy all semaphores with keys "
1074 "that have a prefix %" PRIu16 " (0x%" PRIx16 ").",
1075 DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
1077 if (_yes_no_prompt("Do you really want to continue? [y/n]: ") == 'n') {
1078 log_print("Semaphores with keys prefixed by %" PRIu16
1079 " (0x%" PRIx16 ") NOT destroyed.",
1080 DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
1085 if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) {
1086 log_sys_error("semctl", "SEM_INFO");
1090 for (id = 0; id <= max_id; id++) {
1091 if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0)
1094 if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) {
1095 if (semctl(sid, 0, IPC_RMID, 0) < 0) {
1096 log_error("Could not cleanup notification semaphore "
1097 "with semid %d and cookie value "
1098 "%" PRIu32 " (0x%" PRIx32 ")", sid,
1099 sdata.sem_perm.__key, sdata.sem_perm.__key);
1107 log_print("%d semaphores with keys prefixed by "
1108 "%" PRIu16 " (0x%" PRIx16 ") destroyed.",
1109 counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
1114 static int _udevcookies(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
1116 int max_id, id, sid;
1117 struct seminfo sinfo;
1118 struct semid_ds sdata;
1122 if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) {
1123 log_sys_error("sem_ctl", "SEM_INFO");
1127 printf("cookie semid value last_semop_time\n");
1129 for (id = 0; id <= max_id; id++) {
1130 if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0)
1133 if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) {
1134 if ((val = semctl(sid, 0, GETVAL)) < 0) {
1135 log_error("semid %d: sem_ctl failed for "
1136 "cookie 0x%" PRIx32 ": %s",
1137 sid, sdata.sem_perm.__key,
1142 time_str = ctime((const time_t *) &sdata.sem_otime);
1144 printf("0x%-10x %-10d %-10d %s", sdata.sem_perm.__key,
1145 sid, val, time_str ? time_str : "unknown\n");
1151 #endif /* UDEV_SYNC_SUPPORT */
1153 static int _version(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
1157 if (dm_get_library_version(version, sizeof(version)))
1158 printf("Library version: %s\n", version);
1160 if (!dm_driver_version(version, sizeof(version)))
1163 printf("Driver version: %s\n", version);
1168 static int _simple(int task, const char *name, uint32_t event_nr, int display)
1170 uint32_t cookie = 0;
1171 uint16_t udev_flags = 0;
1172 int udev_wait_flag = task == DM_DEVICE_RESUME ||
1173 task == DM_DEVICE_REMOVE;
1176 struct dm_task *dmt;
1178 if (!(dmt = dm_task_create(task)))
1181 if (!_set_task_device(dmt, name, 0))
1184 if (event_nr && !dm_task_set_event_nr(dmt, event_nr))
1187 if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt))
1190 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1193 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1196 if (_switches[NOLOCKFS_ARG] && !dm_task_skip_lockfs(dmt))
1199 if (_switches[READAHEAD_ARG] &&
1200 !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG],
1204 if (_switches[NOUDEVRULES_ARG])
1205 udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
1206 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
1209 cookie = _udev_cookie;
1211 udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
1214 if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags))
1217 r = dm_task_run(dmt);
1219 if (r && display && _switches[VERBOSE_ARG])
1220 r = _display_info(dmt);
1223 if (!_udev_cookie && udev_wait_flag)
1224 (void) dm_udev_wait(cookie);
1226 dm_task_destroy(dmt);
1230 static int _suspend(int argc, char **argv, void *data __attribute__((unused)))
1232 return _simple(DM_DEVICE_SUSPEND, argc > 1 ? argv[1] : NULL, 0, 1);
1235 static int _resume(int argc, char **argv, void *data __attribute__((unused)))
1237 return _simple(DM_DEVICE_RESUME, argc > 1 ? argv[1] : NULL, 0, 1);
1240 static int _clear(int argc, char **argv, void *data __attribute__((unused)))
1242 return _simple(DM_DEVICE_CLEAR, argc > 1 ? argv[1] : NULL, 0, 1);
1245 static int _wait(int argc, char **argv, void *data __attribute__((unused)))
1247 const char *name = NULL;
1249 if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
1251 err("No device specified.");
1258 return _simple(DM_DEVICE_WAITEVENT, name,
1259 (argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1);
1262 static int _process_all(int argc, char **argv, int silent,
1263 int (*fn) (int argc, char **argv, void *data))
1266 struct dm_names *names;
1269 struct dm_task *dmt;
1271 if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
1274 if (!dm_task_run(dmt)) {
1279 if (!(names = dm_task_get_names(dmt))) {
1286 printf("No devices found\n");
1291 names = (struct dm_names *)((char *) names + next);
1292 if (!fn(argc, argv, names))
1298 dm_task_destroy(dmt);
1302 static uint64_t _get_device_size(const char *name)
1304 uint64_t start, length, size = UINT64_C(0);
1305 struct dm_info info;
1306 char *target_type, *params;
1307 struct dm_task *dmt;
1310 if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
1313 if (!_set_task_device(dmt, name, 0))
1316 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1319 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1322 if (!dm_task_run(dmt))
1325 if (!dm_task_get_info(dmt, &info) || !info.exists)
1329 next = dm_get_next_target(dmt, next, &start, &length,
1330 &target_type, ¶ms);
1335 dm_task_destroy(dmt);
1339 static int _error_device(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data)
1341 struct dm_names *names = (struct dm_names *) data;
1342 struct dm_task *dmt;
1352 size = _get_device_size(name);
1354 if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
1357 if (!_set_task_device(dmt, name, 0))
1360 if (!dm_task_add_target(dmt, UINT64_C(0), size, "error", ""))
1363 if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
1366 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1369 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1372 if (!dm_task_run(dmt))
1375 if (!_simple(DM_DEVICE_RESUME, name, 0, 0)) {
1376 _simple(DM_DEVICE_CLEAR, name, 0, 0);
1383 dm_task_destroy(dmt);
1387 static int _remove(int argc, char **argv, void *data __attribute__((unused)))
1389 if (_switches[FORCE_ARG] && argc > 1)
1390 (void) _error_device(argc, argv, NULL);
1392 return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0);
1395 static int _count_devices(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
1402 static int _remove_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
1406 /* Remove all closed devices */
1407 r = _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL);
1409 if (!_switches[FORCE_ARG])
1413 r |= _process_all(argc, argv, 1, _count_devices);
1415 /* No devices left? */
1419 r |= _process_all(argc, argv, 1, _error_device);
1420 r |= _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL);
1423 r |= _process_all(argc, argv, 1, _count_devices);
1427 fprintf(stderr, "Unable to remove %d device(s).\n", _num_devices);
1432 static void _display_dev(struct dm_task *dmt, const char *name)
1434 struct dm_info info;
1436 if (dm_task_get_info(dmt, &info))
1437 printf("%s\t(%u, %u)\n", name, info.major, info.minor);
1440 static int _mknodes(int argc, char **argv, void *data __attribute__((unused)))
1442 return dm_mknodes(argc > 1 ? argv[1] : NULL);
1445 static int _exec_command(const char *name)
1448 static char path[PATH_MAX];
1449 static char *args[ARGS_MAX + 1];
1450 static int argc = 0;
1457 if (!dm_mknodes(name))
1460 n = snprintf(path, sizeof(path), "%s/%s", dm_dir(), name);
1461 if (n < 0 || n > (int) sizeof(path) - 1)
1466 while (argc < ARGS_MAX) {
1467 while (*c && isspace(*c))
1472 while (*c && !isspace(*c))
1483 if (argc == ARGS_MAX) {
1484 err("Too many args to --exec\n");
1489 args[argc++] = path;
1493 if (!(pid = fork())) {
1494 execvp(args[0], args);
1496 } else if (pid < (pid_t) 0)
1499 TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
1504 static int _status(int argc, char **argv, void *data)
1507 struct dm_task *dmt;
1509 uint64_t start, length;
1510 char *target_type = NULL;
1513 struct dm_names *names = (struct dm_names *) data;
1514 const char *name = NULL;
1517 struct dm_info info;
1522 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1523 return _process_all(argc, argv, 0, _status);
1528 if (!strcmp(argv[0], "table"))
1529 cmd = DM_DEVICE_TABLE;
1531 cmd = DM_DEVICE_STATUS;
1533 if (!strcmp(argv[0], "ls"))
1536 if (!(dmt = dm_task_create(cmd)))
1539 if (!_set_task_device(dmt, name, 0))
1542 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1545 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1548 if (!dm_task_run(dmt))
1551 if (!dm_task_get_info(dmt, &info) || !info.exists)
1555 name = dm_task_get_name(dmt);
1557 /* Fetch targets and print 'em */
1559 next = dm_get_next_target(dmt, next, &start, &length,
1560 &target_type, ¶ms);
1561 /* Skip if target type doesn't match */
1562 if (_switches[TARGET_ARG] &&
1563 (!target_type || strcmp(target_type, _target)))
1566 if (!_switches[EXEC_ARG] || !_command ||
1567 _switches[VERBOSE_ARG])
1568 _display_dev(dmt, name);
1570 } else if (!_switches[EXEC_ARG] || !_command ||
1571 _switches[VERBOSE_ARG]) {
1572 if (!matched && _switches[VERBOSE_ARG])
1574 if (data && !_switches[VERBOSE_ARG])
1575 printf("%s: ", name);
1577 /* Suppress encryption key */
1578 if (!_switches[SHOWKEYS_ARG] &&
1579 cmd == DM_DEVICE_TABLE &&
1580 !strcmp(target_type, "crypt")) {
1582 while (*c && *c != ' ')
1586 while (*c && *c != ' ')
1589 printf("%" PRIu64 " %" PRIu64 " %s %s",
1590 start, length, target_type, params);
1597 if (data && _switches[VERBOSE_ARG] && matched && !ls_only)
1600 if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name))
1606 dm_task_destroy(dmt);
1610 /* Show target names and their version numbers */
1611 static int _targets(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
1614 struct dm_task *dmt;
1615 struct dm_versions *target;
1616 struct dm_versions *last_target;
1618 if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
1621 if (!dm_task_run(dmt))
1624 target = dm_task_get_versions(dmt);
1626 /* Fetch targets and print 'em */
1628 last_target = target;
1630 printf("%-16s v%d.%d.%d\n", target->name, target->version[0],
1631 target->version[1], target->version[2]);
1633 target = (struct dm_versions *)((char *) target + target->next);
1634 } while (last_target != target);
1639 dm_task_destroy(dmt);
1643 static int _info(int argc, char **argv, void *data)
1647 struct dm_task *dmt;
1648 struct dm_names *names = (struct dm_names *) data;
1654 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1655 return _process_all(argc, argv, 0, _info);
1660 if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
1663 if (!_set_task_device(dmt, name, 0))
1666 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1669 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1672 if (!dm_task_run(dmt))
1675 r = _display_info(dmt);
1678 dm_task_destroy(dmt);
1682 static int _deps(int argc, char **argv, void *data)
1686 struct dm_deps *deps;
1687 struct dm_task *dmt;
1688 struct dm_info info;
1689 struct dm_names *names = (struct dm_names *) data;
1695 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1696 return _process_all(argc, argv, 0, _deps);
1701 if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
1704 if (!_set_task_device(dmt, name, 0))
1707 if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1710 if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1713 if (!dm_task_run(dmt))
1716 if (!dm_task_get_info(dmt, &info))
1719 if (!(deps = dm_task_get_deps(dmt)))
1723 printf("Device does not exist.\n");
1728 if (_switches[VERBOSE_ARG])
1731 if (data && !_switches[VERBOSE_ARG])
1732 printf("%s: ", name);
1733 printf("%d dependencies\t:", deps->count);
1735 for (i = 0; i < deps->count; i++)
1737 (int) MAJOR(deps->device[i]),
1738 (int) MINOR(deps->device[i]));
1741 if (data && _switches[VERBOSE_ARG])
1747 dm_task_destroy(dmt);
1751 static int _display_name(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data)
1753 struct dm_names *names = (struct dm_names *) data;
1755 printf("%s\t(%d, %d)\n", names->name,
1756 (int) MAJOR(names->dev), (int) MINOR(names->dev));
1766 TR_DEVICE=0, /* display device major:minor number */
1779 static int _tree_switches[NUM_TREEMODE];
1781 #define TR_PRINT_ATTRIBUTE ( _tree_switches[TR_ACTIVE] || \
1782 _tree_switches[TR_RW] || \
1783 _tree_switches[TR_OPENCOUNT] || \
1784 _tree_switches[TR_UUID] )
1786 #define TR_PRINT_TARGETS ( _tree_switches[TR_TABLE] || \
1787 _tree_switches[TR_STATUS] )
1789 /* Compact - fewer newlines */
1790 #define TR_PRINT_COMPACT (_tree_switches[TR_COMPACT] && \
1791 !TR_PRINT_ATTRIBUTE && \
1794 /* FIXME Get rid of this */
1795 #define MAX_DEPTH 100
1797 /* Drawing character definition from pstree */
1798 /* [pstree comment] UTF-8 defines by Johan Myreen, updated by Ben Winslow */
1799 #define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */
1800 #define UTF_VR "\342\224\234" /* U+251C, Vertical and right */
1801 #define UTF_H "\342\224\200" /* U+2500, Horizontal */
1802 #define UTF_UR "\342\224\224" /* U+2514, Up and right */
1803 #define UTF_HD "\342\224\254" /* U+252C, Horizontal and down */
1805 #define VT_BEG "\033(0\017" /* use graphic chars */
1806 #define VT_END "\033(B" /* back to normal char set */
1807 #define VT_V "x" /* see UTF definitions above */
1814 const char *empty_2; /* */
1815 const char *branch_2; /* |- */
1816 const char *vert_2; /* | */
1817 const char *last_2; /* `- */
1818 const char *single_3; /* --- */
1819 const char *first_3; /* -+- */
1839 VT_BEG VT_VR VT_H VT_END,
1840 VT_BEG VT_V VT_END " ",
1841 VT_BEG VT_UR VT_H VT_END,
1842 VT_BEG VT_H VT_H VT_H VT_END,
1843 VT_BEG VT_H VT_HD VT_H VT_END
1845 *_tsym = &_tsym_ascii;
1848 * Tree drawing functions.
1850 /* FIXME Get rid of these statics - use dynamic struct */
1851 /* FIXME Explain what these vars are for */
1852 static int _tree_width[MAX_DEPTH], _tree_more[MAX_DEPTH];
1853 static int _termwidth = 80; /* Maximum output width */
1854 static int _cur_x = 1; /* Current horizontal output position */
1855 static char _last_char = 0;
1857 static void _out_char(const unsigned c)
1859 /* Only first UTF-8 char counts */
1860 _cur_x += ((c & 0xc0) != 0x80);
1862 if (!_tree_switches[TR_TRUNCATE]) {
1868 if (_cur_x <= _termwidth)
1871 if (_cur_x == _termwidth + 1 && ((c & 0xc0) != 0x80)) {
1872 if (_last_char || (c & 0x80)) {
1883 static void _out_string(const char *str)
1886 _out_char((unsigned char) *str++);
1889 /* non-negative integers only */
1890 static unsigned _out_int(unsigned num)
1892 unsigned digits = 0;
1901 for (divi = 1; num / divi; divi *= 10)
1904 for (divi /= 10; divi; divi /= 10)
1905 _out_char('0' + (num / divi) % 10);
1910 static void _out_newline(void)
1912 if (_last_char && _cur_x == _termwidth)
1913 putchar(_last_char);
1919 static void _out_prefix(unsigned depth)
1923 for (d = 0; d < depth; d++) {
1924 for (x = _tree_width[d] + 1; x > 0; x--)
1927 _out_string(d == depth - 1 ?
1928 !_tree_more[depth] ? _tsym->last_2 : _tsym->branch_2
1929 : _tree_more[d + 1] ?
1930 _tsym->vert_2 : _tsym->empty_2);
1937 static void _display_tree_attributes(struct dm_tree_node *node)
1941 const struct dm_info *info;
1943 uuid = dm_tree_node_get_uuid(node);
1944 info = dm_tree_node_get_info(node);
1949 if (_tree_switches[TR_ACTIVE]) {
1950 _out_string(attr++ ? ", " : " [");
1951 _out_string(info->suspended ? "SUSPENDED" : "ACTIVE");
1954 if (_tree_switches[TR_RW]) {
1955 _out_string(attr++ ? ", " : " [");
1956 _out_string(info->read_only ? "RO" : "RW");
1959 if (_tree_switches[TR_OPENCOUNT]) {
1960 _out_string(attr++ ? ", " : " [");
1961 (void) _out_int((unsigned) info->open_count);
1964 if (_tree_switches[TR_UUID]) {
1965 _out_string(attr++ ? ", " : " [");
1966 _out_string(uuid && *uuid ? uuid : "");
1973 static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
1974 unsigned first_child __attribute__((unused)),
1975 unsigned last_child, unsigned has_children)
1979 const struct dm_info *info;
1980 int first_on_line = 0;
1982 /* Sub-tree for targets has 2 more depth */
1983 if (depth + 2 > MAX_DEPTH)
1986 name = dm_tree_node_get_name(node);
1988 if ((!name || !*name) && !_tree_switches[TR_DEVICE])
1991 /* Indicate whether there are more nodes at this depth */
1992 _tree_more[depth] = !last_child;
1993 _tree_width[depth] = 0;
1998 if (!TR_PRINT_COMPACT || first_on_line)
2001 /* Remember the starting point for compact */
2004 if (TR_PRINT_COMPACT && !first_on_line)
2005 _out_string(_tree_more[depth] ? _tsym->first_3 : _tsym->single_3);
2011 info = dm_tree_node_get_info(node);
2013 if (_tree_switches[TR_DEVICE]) {
2014 _out_string(name ? " (" : "(");
2015 (void) _out_int(info->major);
2017 (void) _out_int(info->minor);
2021 /* display additional info */
2022 if (TR_PRINT_ATTRIBUTE)
2023 _display_tree_attributes(node);
2025 if (TR_PRINT_COMPACT)
2026 _tree_width[depth] = _cur_x - offset;
2028 if (!TR_PRINT_COMPACT || !has_children)
2031 if (TR_PRINT_TARGETS) {
2032 _tree_more[depth + 1] = has_children;
2033 // FIXME _display_tree_targets(name, depth + 2);
2038 * Walk the dependency tree
2040 static void _display_tree_walk_children(struct dm_tree_node *node,
2043 struct dm_tree_node *child, *next_child;
2044 void *handle = NULL;
2045 uint32_t inverted = _tree_switches[TR_BOTTOMUP];
2046 unsigned first_child = 1;
2047 unsigned has_children;
2049 next_child = dm_tree_next_child(&handle, node, inverted);
2051 while ((child = next_child)) {
2052 next_child = dm_tree_next_child(&handle, node, inverted);
2054 dm_tree_node_num_children(child, inverted) ? 1 : 0;
2056 _display_tree_node(child, depth, first_child,
2057 next_child ? 0U : 1U, has_children);
2060 _display_tree_walk_children(child, depth + 1);
2066 static int _add_dep(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data)
2068 struct dm_names *names = (struct dm_names *) data;
2070 if (!dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev)))
2077 * Create and walk dependency tree
2079 static int _build_whole_deptree(void)
2084 if (!(_dtree = dm_tree_create()))
2087 if (!_process_all(0, NULL, 0, _add_dep))
2093 static int _display_tree(int argc __attribute__((unused)),
2094 char **argv __attribute__((unused)),
2095 void *data __attribute__((unused)))
2097 if (!_build_whole_deptree())
2100 _display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
2106 * Report device information
2109 /* dm specific display functions */
2111 static int _int32_disp(struct dm_report *rh,
2112 struct dm_pool *mem __attribute__((unused)),
2113 struct dm_report_field *field, const void *data,
2114 void *private __attribute__((unused)))
2116 const int32_t value = *(const int32_t *)data;
2118 return dm_report_field_int32(rh, field, &value);
2121 static int _uint32_disp(struct dm_report *rh,
2122 struct dm_pool *mem __attribute__((unused)),
2123 struct dm_report_field *field, const void *data,
2124 void *private __attribute__((unused)))
2126 const uint32_t value = *(const int32_t *)data;
2128 return dm_report_field_uint32(rh, field, &value);
2131 static int _dm_name_disp(struct dm_report *rh,
2132 struct dm_pool *mem __attribute__((unused)),
2133 struct dm_report_field *field, const void *data,
2134 void *private __attribute__((unused)))
2136 const char *name = dm_task_get_name((const struct dm_task *) data);
2138 return dm_report_field_string(rh, field, &name);
2141 static int _dm_uuid_disp(struct dm_report *rh,
2142 struct dm_pool *mem __attribute__((unused)),
2143 struct dm_report_field *field,
2144 const void *data, void *private __attribute__((unused)))
2146 const char *uuid = dm_task_get_uuid((const struct dm_task *) data);
2148 if (!uuid || !*uuid)
2151 return dm_report_field_string(rh, field, &uuid);
2154 static int _dm_read_ahead_disp(struct dm_report *rh,
2155 struct dm_pool *mem __attribute__((unused)),
2156 struct dm_report_field *field, const void *data,
2157 void *private __attribute__((unused)))
2161 if (!dm_task_get_read_ahead((const struct dm_task *) data, &value))
2164 return dm_report_field_uint32(rh, field, &value);
2167 static int _dm_info_status_disp(struct dm_report *rh,
2168 struct dm_pool *mem __attribute__((unused)),
2169 struct dm_report_field *field, const void *data,
2170 void *private __attribute__((unused)))
2173 const char *s = buf;
2174 const struct dm_info *info = data;
2176 buf[0] = info->live_table ? 'L' : '-';
2177 buf[1] = info->inactive_table ? 'I' : '-';
2178 buf[2] = info->suspended ? 's' : '-';
2179 buf[3] = info->read_only ? 'r' : 'w';
2182 return dm_report_field_string(rh, field, &s);
2185 static int _dm_info_table_loaded_disp(struct dm_report *rh,
2186 struct dm_pool *mem __attribute__((unused)),
2187 struct dm_report_field *field,
2189 void *private __attribute__((unused)))
2191 const struct dm_info *info = data;
2193 if (info->live_table) {
2194 if (info->inactive_table)
2195 dm_report_field_set_value(field, "Both", NULL);
2197 dm_report_field_set_value(field, "Live", NULL);
2201 if (info->inactive_table)
2202 dm_report_field_set_value(field, "Inactive", NULL);
2204 dm_report_field_set_value(field, "None", NULL);
2209 static int _dm_info_suspended_disp(struct dm_report *rh,
2210 struct dm_pool *mem __attribute__((unused)),
2211 struct dm_report_field *field,
2213 void *private __attribute__((unused)))
2215 const struct dm_info *info = data;
2217 if (info->suspended)
2218 dm_report_field_set_value(field, "Suspended", NULL);
2220 dm_report_field_set_value(field, "Active", NULL);
2225 static int _dm_info_read_only_disp(struct dm_report *rh,
2226 struct dm_pool *mem __attribute__((unused)),
2227 struct dm_report_field *field,
2229 void *private __attribute__((unused)))
2231 const struct dm_info *info = data;
2233 if (info->read_only)
2234 dm_report_field_set_value(field, "Read-only", NULL);
2236 dm_report_field_set_value(field, "Writeable", NULL);
2242 static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem,
2243 struct dm_report_field *field, const void *data,
2246 char buf[DM_MAX_TYPE_NAME], *repstr;
2247 const struct dm_info *info = data;
2249 if (!dm_pool_begin_object(mem, 8)) {
2250 log_error("dm_pool_begin_object failed");
2254 if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2255 info->major, info->minor) < 0) {
2256 log_error("dm_pool_alloc failed");
2260 if (!dm_pool_grow_object(mem, buf, strlen(buf) + 1)) {
2261 log_error("dm_pool_grow_object failed");
2265 repstr = dm_pool_end_object(mem);
2266 dm_report_field_set_value(field, repstr, repstr);
2270 dm_pool_abandon_object(mem);
2274 static int _dm_tree_names(struct dm_report *rh, struct dm_pool *mem,
2275 struct dm_report_field *field, const void *data,
2276 void *private, unsigned inverted)
2278 const struct dm_tree_node *node = data;
2279 struct dm_tree_node *parent;
2285 if (!dm_pool_begin_object(mem, 16)) {
2286 log_error("dm_pool_begin_object failed");
2290 while ((parent = dm_tree_next_child(&t, node, inverted))) {
2291 name = dm_tree_node_get_name(parent);
2292 if (!name || !*name)
2294 if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
2295 log_error("dm_pool_grow_object failed");
2298 if (!dm_pool_grow_object(mem, name, 0)) {
2299 log_error("dm_pool_grow_object failed");
2306 if (!dm_pool_grow_object(mem, "\0", 1)) {
2307 log_error("dm_pool_grow_object failed");
2311 repstr = dm_pool_end_object(mem);
2312 dm_report_field_set_value(field, repstr, repstr);
2316 dm_pool_abandon_object(mem);
2320 static int _dm_deps_names_disp(struct dm_report *rh,
2321 struct dm_pool *mem,
2322 struct dm_report_field *field,
2323 const void *data, void *private)
2325 return _dm_tree_names(rh, mem, field, data, private, 0);
2328 static int _dm_tree_parents_names_disp(struct dm_report *rh,
2329 struct dm_pool *mem,
2330 struct dm_report_field *field,
2331 const void *data, void *private)
2333 return _dm_tree_names(rh, mem, field, data, private, 1);
2336 static int _dm_tree_parents_devs_disp(struct dm_report *rh, struct dm_pool *mem,
2337 struct dm_report_field *field,
2338 const void *data, void *private)
2340 const struct dm_tree_node *node = data;
2341 struct dm_tree_node *parent;
2343 const struct dm_info *info;
2345 char buf[DM_MAX_TYPE_NAME], *repstr;
2347 if (!dm_pool_begin_object(mem, 16)) {
2348 log_error("dm_pool_begin_object failed");
2352 while ((parent = dm_tree_next_child(&t, node, 1))) {
2353 info = dm_tree_node_get_info(parent);
2354 if (!info->major && !info->minor)
2356 if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
2357 log_error("dm_pool_grow_object failed");
2360 if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2361 info->major, info->minor) < 0) {
2362 log_error("dm_snprintf failed");
2365 if (!dm_pool_grow_object(mem, buf, 0)) {
2366 log_error("dm_pool_grow_object failed");
2373 if (!dm_pool_grow_object(mem, "\0", 1)) {
2374 log_error("dm_pool_grow_object failed");
2378 repstr = dm_pool_end_object(mem);
2379 dm_report_field_set_value(field, repstr, repstr);
2383 dm_pool_abandon_object(mem);
2387 static int _dm_tree_parents_count_disp(struct dm_report *rh,
2388 struct dm_pool *mem,
2389 struct dm_report_field *field,
2390 const void *data, void *private)
2392 const struct dm_tree_node *node = data;
2393 int num_parent = dm_tree_node_num_children(node, 1);
2395 return dm_report_field_int(rh, field, &num_parent);
2398 static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
2399 struct dm_report_field *field, const void *data,
2402 const struct dm_deps *deps = data;
2404 char buf[DM_MAX_TYPE_NAME], *repstr;
2406 if (!dm_pool_begin_object(mem, 16)) {
2407 log_error("dm_pool_begin_object failed");
2411 for (i = 0; i < deps->count; i++) {
2412 if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2413 (int) MAJOR(deps->device[i]),
2414 (int) MINOR(deps->device[i])) < 0) {
2415 log_error("dm_snprintf failed");
2418 if (!dm_pool_grow_object(mem, buf, 0)) {
2419 log_error("dm_pool_grow_object failed");
2422 if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) {
2423 log_error("dm_pool_grow_object failed");
2428 if (!dm_pool_grow_object(mem, "\0", 1)) {
2429 log_error("dm_pool_grow_object failed");
2433 repstr = dm_pool_end_object(mem);
2434 dm_report_field_set_value(field, repstr, repstr);
2438 dm_pool_abandon_object(mem);
2442 static int _dm_subsystem_disp(struct dm_report *rh,
2443 struct dm_pool *mem __attribute__((unused)),
2444 struct dm_report_field *field, const void *data,
2445 void *private __attribute__((unused)))
2447 return dm_report_field_string(rh, field, (const char **) data);
2450 static int _dm_vg_name_disp(struct dm_report *rh,
2451 struct dm_pool *mem __attribute__((unused)),
2452 struct dm_report_field *field, const void *data,
2453 void *private __attribute__((unused)))
2456 return dm_report_field_string(rh, field, (const char **) data);
2459 static int _dm_lv_name_disp(struct dm_report *rh,
2460 struct dm_pool *mem __attribute__((unused)),
2461 struct dm_report_field *field, const void *data,
2462 void *private __attribute__((unused)))
2465 return dm_report_field_string(rh, field, (const char **) data);
2468 static int _dm_lv_layer_name_disp(struct dm_report *rh,
2469 struct dm_pool *mem __attribute__((unused)),
2470 struct dm_report_field *field, const void *data,
2471 void *private __attribute__((unused)))
2474 return dm_report_field_string(rh, field, (const char **) data);
2477 static void *_task_get_obj(void *obj)
2479 return ((struct dmsetup_report_obj *)obj)->task;
2482 static void *_info_get_obj(void *obj)
2484 return ((struct dmsetup_report_obj *)obj)->info;
2487 static void *_deps_get_obj(void *obj)
2489 return dm_task_get_deps(((struct dmsetup_report_obj *)obj)->deps_task);
2492 static void *_tree_get_obj(void *obj)
2494 return ((struct dmsetup_report_obj *)obj)->tree_node;
2497 static void *_split_name_get_obj(void *obj)
2499 return ((struct dmsetup_report_obj *)obj)->split_name;
2502 static const struct dm_report_object_type _report_types[] = {
2503 { DR_TASK, "Mapped Device Name", "", _task_get_obj },
2504 { DR_INFO, "Mapped Device Information", "", _info_get_obj },
2505 { DR_DEPS, "Mapped Device Relationship Information", "", _deps_get_obj },
2506 { DR_TREE, "Mapped Device Relationship Information", "", _tree_get_obj },
2507 { DR_NAME, "Mapped Device Name Components", "", _split_name_get_obj },
2508 { 0, "", "", NULL },
2511 /* Column definitions */
2512 #define OFFSET_OF(strct, field) (((char*)&((struct strct*)0)->field) - (char*)0)
2513 #define STR (DM_REPORT_FIELD_TYPE_STRING)
2514 #define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
2515 #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},
2516 #define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},
2518 static const struct dm_report_field_type _report_fields[] = {
2520 FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
2521 FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
2523 /* FIXME Next one should be INFO */
2524 FIELD_F(TASK, NUM, "RAhead", 6, dm_read_ahead, "read_ahead", "Read ahead in sectors.")
2526 FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
2527 FIELD_F(INFO, STR, "Tables", 6, dm_info_table_loaded, "tables_loaded", "Which of the live and inactive table slots are filled.")
2528 FIELD_F(INFO, STR, "Suspended", 9, dm_info_suspended, "suspended", "Whether the device is suspended.")
2529 FIELD_F(INFO, STR, "Read-only", 9, dm_info_read_only, "readonly", "Whether the device is read-only or writeable.")
2530 FIELD_F(INFO, STR, "DevNo", 5, dm_info_devno, "devno", "Device major and minor numbers")
2531 FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.")
2532 FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.")
2533 FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.")
2534 FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.")
2535 FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
2537 FIELD_O(DEPS, dm_deps, NUM, "#Devs", count, 5, int32, "device_count", "Number of devices used by this one.")
2538 FIELD_F(TREE, STR, "DevNames", 8, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.")
2539 FIELD_F(DEPS, STR, "DevNos", 6, dm_deps, "devnos_used", "List of device numbers of devices used by this one.")
2541 FIELD_F(TREE, NUM, "#Refs", 5, dm_tree_parents_count, "device_ref_count", "Number of mapped devices referencing this one.")
2542 FIELD_F(TREE, STR, "RefNames", 8, dm_tree_parents_names, "names_using_dev", "List of names of mapped devices using this one.")
2543 FIELD_F(TREE, STR, "RefDevNos", 9, dm_tree_parents_devs, "devnos_using_dev", "List of device numbers of mapped devices using this one.")
2545 FIELD_O(NAME, dm_split_name, STR, "Subsys", subsystem, 6, dm_subsystem, "subsystem", "Userspace subsystem responsible for this device.")
2546 FIELD_O(NAME, dm_split_name, STR, "VG", vg_name, 4, dm_vg_name, "vg_name", "LVM Volume Group name.")
2547 FIELD_O(NAME, dm_split_name, STR, "LV", lv_name, 4, dm_lv_name, "lv_name", "LVM Logical Volume name.")
2548 FIELD_O(NAME, dm_split_name, STR, "LVLayer", lv_layer, 7, dm_lv_layer_name, "lv_layer", "LVM device layer.")
2550 {0, 0, 0, 0, "", "", NULL, NULL},
2559 static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid";
2560 static const char *splitname_report_options = "vg_name,lv_name,lv_layer";
2562 static int _report_init(struct command *c)
2564 char *options = (char *) default_report_options;
2565 const char *keys = "";
2566 const char *separator = " ";
2567 int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0;
2568 int quoted = 1, columns_as_rows = 0;
2573 if (c && !strcmp(c->name, "splitname"))
2574 options = (char *) splitname_report_options;
2576 /* emulate old dmsetup behaviour */
2577 if (_switches[NOHEADINGS_ARG]) {
2583 if (_switches[UNBUFFERED_ARG])
2586 if (_switches[ROWS_ARG])
2587 columns_as_rows = 1;
2589 if (_switches[UNQUOTED_ARG])
2592 if (_switches[NAMEPREFIXES_ARG]) {
2597 if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) {
2598 if (*_string_args[OPTIONS_ARG] != '+')
2599 options = _string_args[OPTIONS_ARG];
2601 len = strlen(default_report_options) +
2602 strlen(_string_args[OPTIONS_ARG]) + 1;
2603 if (!(options = dm_malloc(len))) {
2604 err("Failed to allocate option string.");
2607 if (dm_snprintf(options, len, "%s,%s",
2608 default_report_options,
2609 &_string_args[OPTIONS_ARG][1]) < 0) {
2610 err("snprintf failed");
2616 if (_switches[SORT_ARG] && _string_args[SORT_ARG]) {
2617 keys = _string_args[SORT_ARG];
2619 if (c && (!strcmp(c->name, "status") || !strcmp(c->name, "table"))) {
2620 err("--sort is not yet supported with status and table");
2625 if (_switches[SEPARATOR_ARG] && _string_args[SEPARATOR_ARG]) {
2626 separator = _string_args[SEPARATOR_ARG];
2631 flags |= DM_REPORT_OUTPUT_ALIGNED;
2634 flags |= DM_REPORT_OUTPUT_BUFFERED;
2637 flags |= DM_REPORT_OUTPUT_HEADINGS;
2640 flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX;
2643 flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED;
2645 if (columns_as_rows)
2646 flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
2648 if (!(_report = dm_report_init(&_report_type,
2649 _report_types, _report_fields,
2650 options, separator, flags, keys, NULL)))
2653 if ((_report_type & DR_TREE) && !_build_whole_deptree()) {
2654 err("Internal device dependency tree creation failed.");
2659 dm_report_set_output_field_name_prefix(_report, "dm_");
2664 if (!strcasecmp(options, "help") || !strcmp(options, "?"))
2676 static int _ls(int argc, char **argv, void *data)
2678 if ((_switches[TARGET_ARG] && _target) ||
2679 (_switches[EXEC_ARG] && _command))
2680 return _status(argc, argv, data);
2681 else if ((_switches[TREE_ARG]))
2682 return _display_tree(argc, argv, data);
2684 return _process_all(argc, argv, 0, _display_name);
2687 static int _help(int argc, char **argv, void *data);
2692 static struct command _commands[] = {
2693 {"help", "[-c|-C|--columns]", 0, 0, _help},
2694 {"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
2695 "\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
2696 "\t [-u|uuid <uuid>]\n"
2697 "\t [--notable | --table <table> | <table_file>]",
2699 {"remove", "[-f|--force] <device>", 0, 1, _remove},
2700 {"remove_all", "[-f|--force]", 0, 0, _remove_all},
2701 {"suspend", "[--noflush] <device>", 0, 1, _suspend},
2702 {"resume", "<device>", 0, 1, _resume},
2703 {"load", "<device> [<table_file>]", 0, 2, _load},
2704 {"clear", "<device>", 0, 1, _clear},
2705 {"reload", "<device> [<table_file>]", 0, 2, _load},
2706 {"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, _rename},
2707 {"message", "<device> <sector> <message>", 2, -1, _message},
2708 {"ls", "[--target <target_type>] [--exec <command>] [--tree [-o options]]", 0, 0, _ls},
2709 {"info", "[<device>]", 0, 1, _info},
2710 {"deps", "[<device>]", 0, 1, _deps},
2711 {"status", "[<device>] [--target <target_type>]", 0, 1, _status},
2712 {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, 1, _status},
2713 {"wait", "<device> [<event_nr>]", 0, 2, _wait},
2714 {"mknodes", "[<device>]", 0, 1, _mknodes},
2715 {"udevcreatecookie", "", 0, 0, _udevcreatecookie},
2716 {"udevreleasecookie", "[<cookie>]", 0, 1, _udevreleasecookie},
2717 {"udevflags", "<cookie>", 1, 1, _udevflags},
2718 {"udevcomplete", "<cookie>", 1, 1, _udevcomplete},
2719 {"udevcomplete_all", "", 0, 0, _udevcomplete_all},
2720 {"udevcookies", "", 0, 0, _udevcookies},
2721 {"targets", "", 0, 0, _targets},
2722 {"version", "", 0, 0, _version},
2723 {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, _setgeometry},
2724 {"splitname", "<device> [<subsystem>]", 1, 2, _splitname},
2725 {NULL, NULL, 0, 0, NULL}
2728 static void _usage(FILE *out)
2732 fprintf(out, "Usage:\n\n");
2733 fprintf(out, "dmsetup [--version] [-h|--help [-c|-C|--columns]]\n"
2734 " [-v|--verbose [-v|--verbose ...]]\n"
2735 " [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n"
2736 " [--udevcookie] [--noudevrules] [--noudevsync] [-y|--yes]\n"
2737 " [--readahead [+]<sectors>|auto|none]\n"
2738 " [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
2739 " [--nameprefixes] [--noheadings] [--separator <separator>]\n\n");
2740 for (i = 0; _commands[i].name; i++)
2741 fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
2742 fprintf(out, "\n<device> may be device name or -u <uuid> or "
2743 "-j <major> -m <minor>\n");
2744 fprintf(out, "<fields> are comma-separated. Use 'help -c' for list.\n");
2745 fprintf(out, "Table_file contents may be supplied on stdin.\n");
2746 fprintf(out, "Tree options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
2747 " [no]device, active, open, rw and uuid.\n");
2751 static void _losetup_usage(FILE *out)
2753 fprintf(out, "Usage:\n\n");
2754 fprintf(out, "losetup [-d|-a] [-e encryption] "
2755 "[-o offset] [-f|loop_device] [file]\n\n");
2758 static int _help(int argc __attribute__((unused)),
2759 char **argv __attribute__((unused)),
2760 void *data __attribute__((unused)))
2764 if (_switches[COLS_ARG]) {
2765 _switches[OPTIONS_ARG] = 1;
2766 _string_args[OPTIONS_ARG] = (char *) "help";
2767 _switches[SORT_ARG] = 0;
2770 dm_report_free(_report);
2773 (void) _report_init(NULL);
2779 static struct command *_find_command(const char *name)
2783 for (i = 0; _commands[i].name; i++)
2784 if (!strcmp(_commands[i].name, name))
2785 return _commands + i;
2790 static int _process_tree_options(const char *options)
2792 const char *s, *end;
2793 struct winsize winsz;
2796 /* Symbol set default */
2797 if (!strcmp(nl_langinfo(CODESET), "UTF-8"))
2800 _tsym = &_tsym_ascii;
2803 _tree_switches[TR_DEVICE] = 1;
2804 _tree_switches[TR_TRUNCATE] = 1;
2807 for (s = options; s && *s; s++) {
2809 for (end = s; *end && *end != ','; end++, len++)
2811 if (!strncmp(s, "device", len))
2812 _tree_switches[TR_DEVICE] = 1;
2813 else if (!strncmp(s, "nodevice", len))
2814 _tree_switches[TR_DEVICE] = 0;
2815 else if (!strncmp(s, "status", len))
2816 _tree_switches[TR_STATUS] = 1;
2817 else if (!strncmp(s, "table", len))
2818 _tree_switches[TR_TABLE] = 1;
2819 else if (!strncmp(s, "active", len))
2820 _tree_switches[TR_ACTIVE] = 1;
2821 else if (!strncmp(s, "open", len))
2822 _tree_switches[TR_OPENCOUNT] = 1;
2823 else if (!strncmp(s, "uuid", len))
2824 _tree_switches[TR_UUID] = 1;
2825 else if (!strncmp(s, "rw", len))
2826 _tree_switches[TR_RW] = 1;
2827 else if (!strncmp(s, "utf", len))
2829 else if (!strncmp(s, "vt100", len))
2830 _tsym = &_tsym_vt100;
2831 else if (!strncmp(s, "ascii", len))
2832 _tsym = &_tsym_ascii;
2833 else if (!strncmp(s, "inverted", len))
2834 _tree_switches[TR_BOTTOMUP] = 1;
2835 else if (!strncmp(s, "compact", len))
2836 _tree_switches[TR_COMPACT] = 1;
2837 else if (!strncmp(s, "notrunc", len))
2838 _tree_switches[TR_TRUNCATE] = 0;
2840 fprintf(stderr, "Tree options not recognised: %s\n", s);
2848 /* Truncation doesn't work well with vt100 drawing char */
2849 if (_tsym != &_tsym_vt100)
2850 if (ioctl(1, (unsigned long) TIOCGWINSZ, &winsz) >= 0 && winsz.ws_col > 3)
2851 _termwidth = winsz.ws_col - 3;
2857 * Returns the full absolute path, or NULL if the path could
2860 static char *_get_abspath(const char *path)
2864 #ifdef HAVE_CANONICALIZE_FILE_NAME
2865 _path = canonicalize_file_name(path);
2867 /* FIXME Provide alternative */
2872 static char *parse_loop_device_name(const char *dev, const char *dev_dir)
2877 if (!(buf = dm_malloc(PATH_MAX)))
2880 if (dev[0] == '/') {
2881 if (!(device = _get_abspath(dev)))
2884 if (strncmp(device, dev_dir, strlen(dev_dir)))
2887 /* If dev_dir does not end in a slash, ensure that the
2888 following byte in the device string is "/". */
2889 if (dev_dir[strlen(dev_dir) - 1] != '/' &&
2890 device[strlen(dev_dir)] != '/')
2893 strncpy(buf, strrchr(device, '/') + 1, (size_t) PATH_MAX);
2897 /* check for device number */
2898 if (!strncmp(dev, "loop", strlen("loop")))
2899 strncpy(buf, dev, (size_t) PATH_MAX);
2912 * create a table for a mapped device using the loop target.
2914 static int _loop_table(char *table, size_t tlen, char *file,
2915 char *dev __attribute__((unused)), off_t off)
2918 off_t size, sectors;
2920 #ifdef HAVE_SYS_STATVFS_H
2921 struct statvfs fsbuf;
2925 if (!_switches[READ_ONLY])
2926 fd = open(file, O_RDWR);
2929 _switches[READ_ONLY]++;
2930 fd = open(file, O_RDONLY);
2936 if (fstat(fd, &fbuf))
2939 size = (fbuf.st_size - off);
2940 sectors = size >> SECTOR_SHIFT;
2942 if (_switches[VERBOSE_ARG])
2943 fprintf(stderr, "losetup: set loop size to %llukB "
2944 "(%llu sectors)\n", (long long unsigned) sectors >> 1,
2945 (long long unsigned) sectors);
2947 #ifdef HAVE_SYS_STATVFS_H
2948 if (fstatvfs(fd, &fsbuf))
2951 /* FIXME Fragment size currently unused */
2952 blksize = fsbuf.f_frsize;
2957 if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
2958 (long long unsigned)sectors, file, (long long unsigned)off) < 0)
2961 if (_switches[VERBOSE_ARG] > 1)
2962 fprintf(stderr, "Table: %s\n", table);
2972 static int _process_losetup_switches(const char *base, int *argc, char ***argv,
2973 const char *dev_dir)
2977 int encrypt_loop = 0, delete = 0, find = 0, show_all = 0;
2978 char *device_name = NULL;
2979 char *loop_file = NULL;
2982 #ifdef HAVE_GETOPTLONG
2983 static struct option long_options[] = {
2989 optind = OPTIND_INIT;
2990 while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
2991 long_options, NULL)) != -1 ) {
2992 if (c == ':' || c == '?')
3003 offset = atoi(optarg);
3005 _switches[VERBOSE_ARG]++;
3012 fprintf(stderr, "%s: Sorry, cryptoloop is not yet implemented "
3013 "in this version.\n", base);
3018 fprintf(stderr, "%s: Sorry, show all is not yet implemented "
3019 "in this version.\n", base);
3024 fprintf(stderr, "%s: Sorry, find is not yet implemented "
3025 "in this version.\n", base);
3031 fprintf(stderr, "%s: Please specify loop_device.\n", base);
3032 _losetup_usage(stderr);
3036 if (!(device_name = parse_loop_device_name((*argv)[0], dev_dir))) {
3037 fprintf(stderr, "%s: Could not parse loop_device %s\n",
3039 _losetup_usage(stderr);
3046 (*argv)[1] = device_name;
3047 (*argv)[0] = (char *) "remove";
3053 fprintf(stderr, "%s: Too few arguments\n", base);
3054 _losetup_usage(stderr);
3055 dm_free(device_name);
3059 /* FIXME move these to make them available to native dmsetup */
3060 if (!(loop_file = _get_abspath((*argv)[(find) ? 0 : 1]))) {
3061 fprintf(stderr, "%s: Could not parse loop file name %s\n",
3063 _losetup_usage(stderr);
3064 dm_free(device_name);
3068 /* FIXME Missing free */
3069 _table = dm_malloc(LOOP_TABLE_SIZE);
3070 if (!_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
3071 fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]);
3072 dm_free(device_name);
3075 _switches[TABLE_ARG]++;
3077 (*argv)[0] = (char *) "create";
3078 (*argv)[1] = device_name ;
3083 static int _process_switches(int *argc, char ***argv, const char *dev_dir)
3085 char *base, *namebase, *s;
3089 #ifdef HAVE_GETOPTLONG
3090 static struct option long_options[] = {
3091 {"readonly", 0, &ind, READ_ONLY},
3092 {"columns", 0, &ind, COLS_ARG},
3093 {"exec", 1, &ind, EXEC_ARG},
3094 {"force", 0, &ind, FORCE_ARG},
3095 {"gid", 1, &ind, GID_ARG},
3096 {"help", 0, &ind, HELP_ARG},
3097 {"inactive", 0, &ind, INACTIVE_ARG},
3098 {"major", 1, &ind, MAJOR_ARG},
3099 {"minor", 1, &ind, MINOR_ARG},
3100 {"mode", 1, &ind, MODE_ARG},
3101 {"nameprefixes", 0, &ind, NAMEPREFIXES_ARG},
3102 {"noflush", 0, &ind, NOFLUSH_ARG},
3103 {"noheadings", 0, &ind, NOHEADINGS_ARG},
3104 {"nolockfs", 0, &ind, NOLOCKFS_ARG},
3105 {"noopencount", 0, &ind, NOOPENCOUNT_ARG},
3106 {"notable", 0, &ind, NOTABLE_ARG},
3107 {"udevcookie", 1, &ind, UDEVCOOKIE_ARG},
3108 {"noudevrules", 0, &ind, NOUDEVRULES_ARG},
3109 {"noudevsync", 0, &ind, NOUDEVSYNC_ARG},
3110 {"options", 1, &ind, OPTIONS_ARG},
3111 {"readahead", 1, &ind, READAHEAD_ARG},
3112 {"rows", 0, &ind, ROWS_ARG},
3113 {"separator", 1, &ind, SEPARATOR_ARG},
3114 {"setuuid", 0, &ind, SETUUID_ARG},
3115 {"showkeys", 0, &ind, SHOWKEYS_ARG},
3116 {"sort", 1, &ind, SORT_ARG},
3117 {"table", 1, &ind, TABLE_ARG},
3118 {"target", 1, &ind, TARGET_ARG},
3119 {"tree", 0, &ind, TREE_ARG},
3120 {"uid", 1, &ind, UID_ARG},
3121 {"uuid", 1, &ind, UUID_ARG},
3122 {"unbuffered", 0, &ind, UNBUFFERED_ARG},
3123 {"unquoted", 0, &ind, UNQUOTED_ARG},
3124 {"verbose", 1, &ind, VERBOSE_ARG},
3125 {"version", 0, &ind, VERSION_ARG},
3126 {"yes", 0, &ind, YES_ARG},
3130 struct option long_options;
3134 * Zero all the index counts.
3136 memset(&_switches, 0, sizeof(_switches));
3137 memset(&_int_args, 0, sizeof(_int_args));
3138 _read_ahead_flags = 0;
3140 namebase = strdup((*argv)[0]);
3141 base = basename(namebase);
3143 if (!strcmp(base, "devmap_name")) {
3145 _switches[COLS_ARG]++;
3146 _switches[NOHEADINGS_ARG]++;
3147 _switches[OPTIONS_ARG]++;
3148 _switches[MAJOR_ARG]++;
3149 _switches[MINOR_ARG]++;
3150 _string_args[OPTIONS_ARG] = (char *) "name";
3153 _int_args[MAJOR_ARG] = atoi((*argv)[1]);
3154 _int_args[MINOR_ARG] = atoi((*argv)[2]);
3157 } else if ((*argc == 2) &&
3158 (2 == sscanf((*argv)[1], "%i:%i",
3159 &_int_args[MAJOR_ARG],
3160 &_int_args[MINOR_ARG]))) {
3164 fprintf(stderr, "Usage: devmap_name <major> <minor>\n");
3168 (*argv)[0] = (char *) "info";
3172 if (!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
3173 r = _process_losetup_switches(base, argc, argv, dev_dir);
3181 optind = OPTIND_INIT;
3182 while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:hj:m:M:no:O:ru:U:vy",
3183 long_options, NULL)) != -1) {
3184 if (c == ':' || c == '?')
3186 if (c == 'h' || ind == HELP_ARG)
3187 _switches[HELP_ARG]++;
3188 if (c == 'c' || c == 'C' || ind == COLS_ARG)
3189 _switches[COLS_ARG]++;
3190 if (c == 'f' || ind == FORCE_ARG)
3191 _switches[FORCE_ARG]++;
3192 if (c == 'r' || ind == READ_ONLY)
3193 _switches[READ_ONLY]++;
3194 if (c == 'j' || ind == MAJOR_ARG) {
3195 _switches[MAJOR_ARG]++;
3196 _int_args[MAJOR_ARG] = atoi(optarg);
3198 if (c == 'm' || ind == MINOR_ARG) {
3199 _switches[MINOR_ARG]++;
3200 _int_args[MINOR_ARG] = atoi(optarg);
3202 if (c == 'n' || ind == NOTABLE_ARG)
3203 _switches[NOTABLE_ARG]++;
3204 if (c == 'o' || ind == OPTIONS_ARG) {
3205 _switches[OPTIONS_ARG]++;
3206 _string_args[OPTIONS_ARG] = optarg;
3208 if (ind == SEPARATOR_ARG) {
3209 _switches[SEPARATOR_ARG]++;
3210 _string_args[SEPARATOR_ARG] = optarg;
3212 if (c == 'O' || ind == SORT_ARG) {
3213 _switches[SORT_ARG]++;
3214 _string_args[SORT_ARG] = optarg;
3216 if (c == 'v' || ind == VERBOSE_ARG)
3217 _switches[VERBOSE_ARG]++;
3218 if (c == 'u' || ind == UUID_ARG) {
3219 _switches[UUID_ARG]++;
3222 if (c == 'y' || ind == YES_ARG)
3223 _switches[YES_ARG]++;
3224 if (ind == UDEVCOOKIE_ARG) {
3225 _switches[UDEVCOOKIE_ARG]++;
3226 _udev_cookie = _get_cookie_value(optarg);
3228 if (ind == NOUDEVRULES_ARG)
3229 _switches[NOUDEVRULES_ARG]++;
3230 if (ind == NOUDEVSYNC_ARG)
3231 _switches[NOUDEVSYNC_ARG]++;
3232 if (c == 'G' || ind == GID_ARG) {
3233 _switches[GID_ARG]++;
3234 _int_args[GID_ARG] = atoi(optarg);
3236 if (c == 'U' || ind == UID_ARG) {
3237 _switches[UID_ARG]++;
3238 _int_args[UID_ARG] = atoi(optarg);
3240 if (c == 'M' || ind == MODE_ARG) {
3241 _switches[MODE_ARG]++;
3242 /* FIXME Accept modes as per chmod */
3243 _int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
3245 if ((ind == EXEC_ARG)) {
3246 _switches[EXEC_ARG]++;
3249 if ((ind == TARGET_ARG)) {
3250 _switches[TARGET_ARG]++;
3253 if ((ind == INACTIVE_ARG))
3254 _switches[INACTIVE_ARG]++;
3255 if ((ind == NAMEPREFIXES_ARG))
3256 _switches[NAMEPREFIXES_ARG]++;
3257 if ((ind == NOFLUSH_ARG))
3258 _switches[NOFLUSH_ARG]++;
3259 if ((ind == NOHEADINGS_ARG))
3260 _switches[NOHEADINGS_ARG]++;
3261 if ((ind == NOLOCKFS_ARG))
3262 _switches[NOLOCKFS_ARG]++;
3263 if ((ind == NOOPENCOUNT_ARG))
3264 _switches[NOOPENCOUNT_ARG]++;
3265 if ((ind == READAHEAD_ARG)) {
3266 _switches[READAHEAD_ARG]++;
3267 if (!strcasecmp(optarg, "auto"))
3268 _int_args[READAHEAD_ARG] = DM_READ_AHEAD_AUTO;
3269 else if (!strcasecmp(optarg, "none"))
3270 _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE;
3272 for (s = optarg; isspace(*s); s++)
3275 _read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG;
3276 _int_args[READAHEAD_ARG] = atoi(optarg);
3277 if (_int_args[READAHEAD_ARG] < -1) {
3278 log_error("Negative read ahead value "
3279 "(%d) is not understood.",
3280 _int_args[READAHEAD_ARG]);
3285 if ((ind == ROWS_ARG))
3286 _switches[ROWS_ARG]++;
3287 if ((ind == SETUUID_ARG))
3288 _switches[SETUUID_ARG]++;
3289 if ((ind == SHOWKEYS_ARG))
3290 _switches[SHOWKEYS_ARG]++;
3291 if ((ind == TABLE_ARG)) {
3292 _switches[TABLE_ARG]++;
3295 if ((ind == TREE_ARG))
3296 _switches[TREE_ARG]++;
3297 if ((ind == UNQUOTED_ARG))
3298 _switches[UNQUOTED_ARG]++;
3299 if ((ind == VERSION_ARG))
3300 _switches[VERSION_ARG]++;
3303 if (_switches[VERBOSE_ARG] > 1)
3304 dm_log_init_verbose(_switches[VERBOSE_ARG] - 1);
3306 if ((_switches[MAJOR_ARG] && !_switches[MINOR_ARG]) ||
3307 (!_switches[MAJOR_ARG] && _switches[MINOR_ARG])) {
3308 fprintf(stderr, "Please specify both major number and "
3313 if (_switches[TREE_ARG] && !_process_tree_options(_string_args[OPTIONS_ARG]))
3316 if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
3317 fprintf(stderr, "--table and --notable are incompatible.\n");
3326 int main(int argc, char **argv)
3330 const char *dev_dir;
3332 (void) setlocale(LC_ALL, "");
3334 dev_dir = getenv (DM_DEV_DIR_ENV_VAR_NAME);
3335 if (dev_dir && *dev_dir) {
3336 if (!dm_set_dev_dir(dev_dir)) {
3337 fprintf(stderr, "Invalid DM_DEV_DIR environment variable value.\n");
3341 dev_dir = DEFAULT_DM_DEV_DIR;
3343 if (!_process_switches(&argc, &argv, dev_dir)) {
3344 fprintf(stderr, "Couldn't process command line.\n");
3348 if (_switches[HELP_ARG]) {
3349 c = _find_command("help");
3353 if (_switches[VERSION_ARG]) {
3354 c = _find_command("version");
3363 if (!(c = _find_command(argv[0]))) {
3364 fprintf(stderr, "Unknown command\n");
3369 if (argc < c->min_args + 1 ||
3370 (c->max_args >= 0 && argc > c->max_args + 1)) {
3371 fprintf(stderr, "Incorrect number of arguments\n");
3376 if (!_switches[COLS_ARG] && !strcmp(c->name, "splitname"))
3377 _switches[COLS_ARG]++;
3379 if (_switches[COLS_ARG]) {
3380 if (!_report_init(c))
3383 if (!strcmp(c->name, "info"))
3384 r = 0; /* info -c -o help */
3389 #ifdef UDEV_SYNC_SUPPORT
3390 if (!_set_up_udev_support(dev_dir))
3395 if (!c->fn(argc, argv, NULL)) {
3396 fprintf(stderr, "Command failed\n");
3404 dm_report_output(_report);
3405 dm_report_free(_report);
3409 dm_tree_free(_dtree);