diff options
Diffstat (limited to 'tools/dmsetup.c')
-rw-r--r-- | tools/dmsetup.c | 1002 |
1 files changed, 728 insertions, 274 deletions
diff --git a/tools/dmsetup.c b/tools/dmsetup.c index 2eeee7f..196c170 100644 --- a/tools/dmsetup.c +++ b/tools/dmsetup.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * Copyright (C) 2005-2007 NEC Corporation * * This file is part of the device-mapper userspace tools. @@ -30,7 +30,6 @@ #include <dirent.h> #include <errno.h> #include <unistd.h> -#include <libgen.h> #include <sys/wait.h> #include <unistd.h> #include <sys/param.h> @@ -45,7 +44,6 @@ # include <sys/types.h> # include <sys/ipc.h> # include <sys/sem.h> -# define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE # include <libudev.h> #endif @@ -118,12 +116,16 @@ extern char *optarg; */ enum { READ_ONLY = 0, + ADD_NODE_ON_CREATE_ARG, + ADD_NODE_ON_RESUME_ARG, + CHECKS_ARG, COLS_ARG, EXEC_ARG, FORCE_ARG, GID_ARG, HELP_ARG, INACTIVE_ARG, + MANGLENAME_ARG, MAJOR_ARG, MINOR_ARG, MODE_ARG, @@ -138,6 +140,7 @@ enum { NOUDEVSYNC_ARG, OPTIONS_ARG, READAHEAD_ARG, + RETRY_ARG, ROWS_ARG, SEPARATOR_ARG, SETUUID_ARG, @@ -151,6 +154,7 @@ enum { UNQUOTED_ARG, UUID_ARG, VERBOSE_ARG, + VERIFYUDEV_ARG, VERSION_ARG, YES_ARG, NUM_SWITCHES @@ -164,6 +168,12 @@ typedef enum { DR_NAME = 16 } report_type_t; +typedef enum { + DN_DEVNO, /* Major and minor number pair */ + DN_BLK, /* Block device name (e.g. dm-0) */ + DN_MAP /* Map name (for dm devices only, equal to DN_BLK otherwise) */ +} dev_name_t; + static int _switches[NUM_SWITCHES]; static int _int_args[NUM_SWITCHES]; static char *_string_args[NUM_SWITCHES]; @@ -178,18 +188,22 @@ static int _udev_only; static struct dm_tree *_dtree; static struct dm_report *_report; static report_type_t _report_type; +static dev_name_t _dev_name_type; /* * Commands */ -typedef int (*command_fn) (int argc, char **argv, void *data); +struct command; +#define CMD_ARGS const struct command *cmd, int argc, char **argv, struct dm_names *names, int multiple_devices +typedef int (*command_fn) (CMD_ARGS); struct command { const char *name; const char *help; int min_args; int max_args; + int repeatable_cmd; /* Repeat to process device list? */ command_fn fn; }; @@ -312,6 +326,9 @@ static struct dm_task *_get_deps_task(int major, int minor) if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto err; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto err; + if (!dm_task_run(dmt)) goto err; @@ -362,7 +379,11 @@ static struct dm_split_name *_get_split_name(const char *uuid, const char *name, return NULL; } - split_name->subsystem = _extract_uuid_prefix(uuid, separator); + if (!(split_name->subsystem = _extract_uuid_prefix(uuid, separator))) { + dm_free(split_name); + return_NULL; + } + split_name->vg_name = split_name->lv_name = split_name->lv_layer = (char *) ""; @@ -405,16 +426,24 @@ static int _display_info_cols(struct dm_task *dmt, struct dm_info *info) obj.split_name = NULL; if (_report_type & DR_TREE) - obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor); + if (!(obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor))) { + log_error("Cannot find node %d:%d.", info->major, info->minor); + goto out; + } if (_report_type & DR_DEPS) - obj.deps_task = _get_deps_task(info->major, info->minor); + if (!(obj.deps_task = _get_deps_task(info->major, info->minor))) { + log_error("Cannot get deps for %d:%d.", info->major, info->minor); + goto out; + } if (_report_type & DR_NAME) - obj.split_name = _get_split_name(dm_task_get_uuid(dmt), dm_task_get_name(dmt), '-'); + if (!(obj.split_name = _get_split_name(dm_task_get_uuid(dmt), + dm_task_get_name(dmt), '-'))) + goto_out; if (!dm_report_object(_report, &obj)) - goto out; + goto_out; r = 1; @@ -505,7 +534,23 @@ static int _set_task_device(struct dm_task *dmt, const char *name, int optional) return 1; } -static int _load(int argc, char **argv, void *data __attribute__((unused))) +static int _set_task_add_node(struct dm_task *dmt) +{ + if (!dm_task_set_add_node(dmt, DEFAULT_DM_ADD_NODE)) + return 0; + + if (_switches[ADD_NODE_ON_RESUME_ARG] && + !dm_task_set_add_node(dmt, DM_ADD_NODE_ON_RESUME)) + return 0; + + if (_switches[ADD_NODE_ON_CREATE_ARG] && + !dm_task_set_add_node(dmt, DM_ADD_NODE_ON_CREATE)) + return 0; + + return 1; +} + +static int _load(CMD_ARGS) { int r = 0; struct dm_task *dmt; @@ -551,6 +596,9 @@ static int _load(int argc, char **argv, void *data __attribute__((unused))) if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + if (!dm_task_run(dmt)) goto out; @@ -565,7 +613,7 @@ static int _load(int argc, char **argv, void *data __attribute__((unused))) return r; } -static int _create(int argc, char **argv, void *data __attribute__((unused))) +static int _create(CMD_ARGS) { int r = 0; struct dm_task *dmt; @@ -624,11 +672,17 @@ static int _create(int argc, char **argv, void *data __attribute__((unused))) udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; - if (_udev_cookie) { + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + + if (!_set_task_add_node(dmt)) + goto out; + + if (_udev_cookie) cookie = _udev_cookie; - if (_udev_only) - udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; - } + + if (_udev_only) + udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; if (!dm_task_set_cookie(dmt, &cookie, udev_flags) || !dm_task_run(dmt)) @@ -636,26 +690,19 @@ static int _create(int argc, char **argv, void *data __attribute__((unused))) r = 1; + out: if (!_udev_cookie) (void) dm_udev_wait(cookie); - if (_switches[VERBOSE_ARG]) + if (r && _switches[VERBOSE_ARG]) r = _display_info(dmt); dm_task_destroy(dmt); return r; - - out: - if (!_udev_cookie) - (void) dm_udev_wait(cookie); - dm_task_destroy(dmt); - - return r; } -static int _rename(int argc, char **argv, void *data __attribute__((unused))) -{ +static int _do_rename(const char *name, const char *new_name, const char *new_uuid) { int r = 0; struct dm_task *dmt; uint32_t cookie = 0; @@ -665,13 +712,13 @@ static int _rename(int argc, char **argv, void *data __attribute__((unused))) return 0; /* FIXME Kernel doesn't support uuid or device number here yet */ - if (!_set_task_device(dmt, (argc == 3) ? argv[1] : NULL, 0)) + if (!_set_task_device(dmt, name, 0)) goto out; - if (_switches[SETUUID_ARG]) { - if (!dm_task_set_newuuid(dmt, argv[argc - 1])) + if (new_uuid) { + if (!dm_task_set_newuuid(dmt, new_uuid)) goto out; - } else if (!dm_task_set_newname(dmt, argv[argc - 1])) + } else if (!new_name || !dm_task_set_newname(dmt, new_name)) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) @@ -680,15 +727,18 @@ static int _rename(int argc, char **argv, void *data __attribute__((unused))) if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + if (_switches[NOUDEVRULES_ARG]) udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; - if (_udev_cookie) { + if (_udev_cookie) cookie = _udev_cookie; - if (_udev_only) - udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; - } + + if (_udev_only) + udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; if (!dm_task_set_cookie(dmt, &cookie, udev_flags) || !dm_task_run(dmt)) @@ -699,12 +749,22 @@ static int _rename(int argc, char **argv, void *data __attribute__((unused))) out: if (!_udev_cookie) (void) dm_udev_wait(cookie); + dm_task_destroy(dmt); return r; } -static int _message(int argc, char **argv, void *data __attribute__((unused))) +static int _rename(CMD_ARGS) +{ + const char *name = (argc == 3) ? argv[1] : NULL; + + return _switches[SETUUID_ARG] ? _do_rename(name, NULL, argv[argc - 1]) : + _do_rename(name, argv[argc - 1], NULL); + +} + +static int _message(CMD_ARGS) { int r = 0, i; size_t sz = 1; @@ -747,17 +807,22 @@ static int _message(int argc, char **argv, void *data __attribute__((unused))) strcat(str, argv[i]); } - if (!dm_task_set_message(dmt, str)) - goto out; + i = dm_task_set_message(dmt, str); dm_free(str); + if (!i) + goto out; + if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + if (!dm_task_run(dmt)) goto out; @@ -769,7 +834,7 @@ static int _message(int argc, char **argv, void *data __attribute__((unused))) return r; } -static int _setgeometry(int argc, char **argv, void *data __attribute__((unused))) +static int _setgeometry(CMD_ARGS) { int r = 0; struct dm_task *dmt; @@ -796,6 +861,9 @@ static int _setgeometry(int argc, char **argv, void *data __attribute__((unused) if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + /* run the task */ if (!dm_task_run(dmt)) goto out; @@ -808,7 +876,7 @@ static int _setgeometry(int argc, char **argv, void *data __attribute__((unused) return r; } -static int _splitname(int argc, char **argv, void *data __attribute__((unused))) +static int _splitname(CMD_ARGS) { struct dmsetup_report_obj obj; int r = 1; @@ -817,8 +885,9 @@ static int _splitname(int argc, char **argv, void *data __attribute__((unused))) obj.info = NULL; obj.deps_task = NULL; obj.tree_node = NULL; - obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM", - argv[1], '\0'); + if (!(obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM", + argv[1], '\0'))) + return_0; r = dm_report_object(_report, &obj); _destroy_split_name(obj.split_name); @@ -842,7 +911,7 @@ static uint32_t _get_cookie_value(const char *str_value) return (uint32_t) value; } -static int _udevflags(int args, char **argv, void *data __attribute__((unused))) +static int _udevflags(CMD_ARGS) { uint32_t cookie; uint16_t flags; @@ -884,7 +953,7 @@ static int _udevflags(int args, char **argv, void *data __attribute__((unused))) return 1; } -static int _udevcomplete(int argc, char **argv, void *data __attribute__((unused))) +static int _udevcomplete(CMD_ARGS) { uint32_t cookie; @@ -907,32 +976,30 @@ static int _udevcomplete(int argc, char **argv, void *data __attribute__((unused } #ifndef UDEV_SYNC_SUPPORT -static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev-sync\" to enable."; +static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev_sync\" to enable."; -static int _udevcreatecookie(int argc, char **argv, - void *data __attribute__((unused))) +static int _udevcreatecookie(CMD_ARGS) { log_error(_cmd_not_supported); return 0; } -static int _udevreleasecookie(int argc, char **argv, - void *data __attribute__((unused))) +static int _udevreleasecookie(CMD_ARGS) { log_error(_cmd_not_supported); return 0; } -static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused))) +static int _udevcomplete_all(CMD_ARGS) { log_error(_cmd_not_supported); return 0; } -static int _udevcookies(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused))) +static int _udevcookies(CMD_ARGS) { log_error(_cmd_not_supported); @@ -942,11 +1009,9 @@ static int _udevcookies(int argc __attribute__((unused)), char **argv __attribut #else /* UDEV_SYNC_SUPPORT */ static int _set_up_udev_support(const char *dev_dir) { - struct udev *udev; - const char *udev_dev_dir; - size_t udev_dev_dir_len; int dirs_diff; const char *env; + size_t len = strlen(dev_dir), udev_dir_len = strlen(DM_UDEV_DEV_DIR); if (_switches[NOUDEVSYNC_ARG]) dm_udev_set_sync_support(0); @@ -964,14 +1029,6 @@ static int _set_up_udev_support(const char *dev_dir) " defined by --udevcookie option.", _udev_cookie); - if (!(udev = udev_new()) || - !(udev_dev_dir = udev_get_dev_path(udev)) || - !*udev_dev_dir) { - log_error("Could not get udev dev path."); - return 0; - } - udev_dev_dir_len = strlen(udev_dev_dir); - /* * Normally, there's always a fallback action by libdevmapper if udev * has not done its job correctly, e.g. the nodes were not created. @@ -983,13 +1040,18 @@ static int _set_up_udev_support(const char *dev_dir) * is the same as "dev path" used by libdevmapper. */ - /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */ - if (udev_dev_dir[udev_dev_dir_len - 1] != '/') - dirs_diff = strncmp(dev_dir, udev_dev_dir, udev_dev_dir_len); - else - dirs_diff = strcmp(dev_dir, udev_dev_dir); - _udev_only = _udev_cookie && !dirs_diff; + /* + * DM_UDEV_DEV_DIR always has '/' at its end. + * If the dev_dir does not have it, be sure + * to make the right comparison without the '/' char! + */ + if (dev_dir[len - 1] != '/') + udev_dir_len--; + + dirs_diff = udev_dir_len != len || + strncmp(DM_UDEV_DEV_DIR, dev_dir, len); + _udev_only = !dirs_diff && (_udev_cookie || !_switches[VERIFYUDEV_ARG]); if (dirs_diff) { log_debug("The path %s used for creating device nodes that is " @@ -998,16 +1060,14 @@ static int _set_up_udev_support(const char *dev_dir) "about udev not working correctly while processing " "particular nodes will be suppressed. These nodes " "and symlinks will be managed in each directory " - "separately.", dev_dir, udev_dev_dir); + "separately.", dev_dir, DM_UDEV_DEV_DIR); dm_udev_set_checking(0); } - udev_unref(udev); return 1; } -static int _udevcreatecookie(int argc, char **argv, - void *data __attribute__((unused))) +static int _udevcreatecookie(CMD_ARGS) { uint32_t cookie; @@ -1020,8 +1080,7 @@ static int _udevcreatecookie(int argc, char **argv, return 1; } -static int _udevreleasecookie(int argc, char **argv, - void *data __attribute__((unused))) +static int _udevreleasecookie(CMD_ARGS) { if (argv[1] && !(_udev_cookie = _get_cookie_value(argv[1]))) return 0; @@ -1034,6 +1093,7 @@ static int _udevreleasecookie(int argc, char **argv, return dm_udev_wait(_udev_cookie); } +__attribute__((format(printf, 1, 2))) static char _yes_no_prompt(const char *prompt, ...) { int c = 0, ret = 0; @@ -1062,16 +1122,25 @@ static char _yes_no_prompt(const char *prompt, ...) return ret; } -static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused))) +static int _udevcomplete_all(CMD_ARGS) { int max_id, id, sid; struct seminfo sinfo; struct semid_ds sdata; int counter = 0; + int skipped = 0; + unsigned age = 0; + time_t t; + + if (argc == 2 && (sscanf(argv[1], "%i", &age) != 1)) { + log_error("Failed to read age_in_minutes parameter."); + return 0; + } if (!_switches[YES_ARG]) { - log_warn("This operation will destroy all semaphores with keys " + log_warn("This operation will destroy all semaphores %s%.0d%swith keys " "that have a prefix %" PRIu16 " (0x%" PRIx16 ").", + age ? "older than " : "", age, age ? " minutes " : "", DM_COOKIE_MAGIC, DM_COOKIE_MAGIC); if (_yes_no_prompt("Do you really want to continue? [y/n]: ") == 'n') { @@ -1092,6 +1161,13 @@ static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __att continue; if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) { + t = time(NULL); + + if (sdata.sem_ctime + age * 60 > t || + sdata.sem_otime + age * 60 > t) { + skipped++; + continue; + } if (semctl(sid, 0, IPC_RMID, 0) < 0) { log_error("Could not cleanup notification semaphore " "with semid %d and cookie value " @@ -1105,26 +1181,27 @@ static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __att } log_print("%d semaphores with keys prefixed by " - "%" PRIu16 " (0x%" PRIx16 ") destroyed.", - counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC); + "%" PRIu16 " (0x%" PRIx16 ") destroyed. %d skipped.", + counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC, skipped); return 1; } -static int _udevcookies(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused))) +static int _udevcookies(CMD_ARGS) { int max_id, id, sid; struct seminfo sinfo; struct semid_ds sdata; int val; - char *time_str; + char otime_str[26], ctime_str[26]; + char *otimes, *ctimes; if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) { log_sys_error("sem_ctl", "SEM_INFO"); return 0; } - printf("cookie semid value last_semop_time\n"); + printf("Cookie Semid Value Last semop time Last change time\n"); for (id = 0; id <= max_id; id++) { if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0) @@ -1139,10 +1216,14 @@ static int _udevcookies(int argc __attribute__((unused)), char **argv __attribut continue; } - time_str = ctime((const time_t *) &sdata.sem_otime); + if ((otimes = ctime_r((const time_t *) &sdata.sem_otime, (char *)&otime_str))) + otime_str[strlen(otimes)-1] = '\0'; + if ((ctimes = ctime_r((const time_t *) &sdata.sem_ctime, (char *)&ctime_str))) + ctime_str[strlen(ctimes)-1] = '\0'; - printf("0x%-10x %-10d %-10d %s", sdata.sem_perm.__key, - sid, val, time_str ? time_str : "unknown\n"); + printf("0x%-10x %-10d %-10d %s %s\n", sdata.sem_perm.__key, + sid, val, otimes ? : "unknown", + ctimes? : "unknown"); } } @@ -1150,7 +1231,7 @@ static int _udevcookies(int argc __attribute__((unused)), char **argv __attribut } #endif /* UDEV_SYNC_SUPPORT */ -static int _version(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused))) +static int _version(CMD_ARGS) { char version[80]; @@ -1196,6 +1277,13 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display) if (_switches[NOLOCKFS_ARG] && !dm_task_skip_lockfs(dmt)) goto out; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + + /* FIXME: needs to coperate with udev */ + if (!_set_task_add_node(dmt)) + goto out; + if (_switches[READAHEAD_ARG] && !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG], _read_ahead_flags)) @@ -1205,44 +1293,48 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display) udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; - if (_udev_cookie) { + if (_udev_cookie) cookie = _udev_cookie; - if (_udev_only) - udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; - } + + if (_udev_only) + udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags)) goto out; - r = dm_task_run(dmt); + if (_switches[RETRY_ARG] && task == DM_DEVICE_REMOVE) + dm_task_retry_remove(dmt); - if (r && display && _switches[VERBOSE_ARG]) - r = _display_info(dmt); + r = dm_task_run(dmt); out: if (!_udev_cookie && udev_wait_flag) (void) dm_udev_wait(cookie); + if (r && display && _switches[VERBOSE_ARG]) + r = _display_info(dmt); + dm_task_destroy(dmt); + return r; } -static int _suspend(int argc, char **argv, void *data __attribute__((unused))) +static int _suspend(CMD_ARGS) { return _simple(DM_DEVICE_SUSPEND, argc > 1 ? argv[1] : NULL, 0, 1); } -static int _resume(int argc, char **argv, void *data __attribute__((unused))) +static int _resume(CMD_ARGS) { return _simple(DM_DEVICE_RESUME, argc > 1 ? argv[1] : NULL, 0, 1); } -static int _clear(int argc, char **argv, void *data __attribute__((unused))) +static int _clear(CMD_ARGS) { return _simple(DM_DEVICE_CLEAR, argc > 1 ? argv[1] : NULL, 0, 1); } -static int _wait(int argc, char **argv, void *data __attribute__((unused))) +static int _wait(CMD_ARGS) { const char *name = NULL; @@ -1259,8 +1351,8 @@ static int _wait(int argc, char **argv, void *data __attribute__((unused))) (argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1); } -static int _process_all(int argc, char **argv, int silent, - int (*fn) (int argc, char **argv, void *data)) +static int _process_all(const struct command *cmd, int argc, char **argv, int silent, + int (*fn) (CMD_ARGS)) { int r = 1; struct dm_names *names; @@ -1271,6 +1363,9 @@ static int _process_all(int argc, char **argv, int silent, if (!(dmt = dm_task_create(DM_DEVICE_LIST))) return 0; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + if (!dm_task_run(dmt)) { r = 0; goto out; @@ -1289,7 +1384,7 @@ static int _process_all(int argc, char **argv, int silent, do { names = (struct dm_names *)((char *) names + next); - if (!fn(argc, argv, names)) + if (!fn(cmd, argc, argv, names, 1)) r = 0; next = names->next; } while (next); @@ -1319,6 +1414,9 @@ static uint64_t _get_device_size(const char *name) if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + if (!dm_task_run(dmt)) goto out; @@ -1336,18 +1434,14 @@ static uint64_t _get_device_size(const char *name) return size; } -static int _error_device(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data) +static int _error_device(CMD_ARGS) { - struct dm_names *names = (struct dm_names *) data; struct dm_task *dmt; const char *name; uint64_t size; int r = 0; - if (data) - name = names->name; - else - name = argv[1]; + name = names ? names->name : argv[1]; size = _get_device_size(name); @@ -1369,6 +1463,9 @@ static int _error_device(int argc __attribute__((unused)), char **argv __attribu if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto error; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto error; + if (!dm_task_run(dmt)) goto error; @@ -1384,22 +1481,22 @@ error: return r; } -static int _remove(int argc, char **argv, void *data __attribute__((unused))) +static int _remove(CMD_ARGS) { if (_switches[FORCE_ARG] && argc > 1) - (void) _error_device(argc, argv, NULL); + (void) _error_device(cmd, argc, argv, NULL, 0); return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0); } -static int _count_devices(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused))) +static int _count_devices(CMD_ARGS) { _num_devices++; return 1; } -static int _remove_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused))) +static int _remove_all(CMD_ARGS) { int r; @@ -1410,17 +1507,17 @@ static int _remove_all(int argc __attribute__((unused)), char **argv __attribute return r; _num_devices = 0; - r |= _process_all(argc, argv, 1, _count_devices); + r |= _process_all(cmd, argc, argv, 1, _count_devices); /* No devices left? */ if (!_num_devices) return r; - r |= _process_all(argc, argv, 1, _error_device); + r |= _process_all(cmd, argc, argv, 1, _error_device); r |= _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL); _num_devices = 0; - r |= _process_all(argc, argv, 1, _count_devices); + r |= _process_all(cmd, argc, argv, 1, _count_devices); if (!_num_devices) return r; @@ -1437,7 +1534,7 @@ static void _display_dev(struct dm_task *dmt, const char *name) printf("%s\t(%u, %u)\n", name, info.major, info.minor); } -static int _mknodes(int argc, char **argv, void *data __attribute__((unused))) +static int _mknodes(CMD_ARGS) { return dm_mknodes(argc > 1 ? argv[1] : NULL); } @@ -1501,7 +1598,7 @@ static int _exec_command(const char *name) return 1; } -static int _status(int argc, char **argv, void *data) +static int _status(CMD_ARGS) { int r = 0; struct dm_task *dmt; @@ -1509,31 +1606,29 @@ static int _status(int argc, char **argv, void *data) uint64_t start, length; char *target_type = NULL; char *params, *c; - int cmd; - struct dm_names *names = (struct dm_names *) data; + int cmdno; const char *name = NULL; int matched = 0; int ls_only = 0; struct dm_info info; - if (data) + if (names) name = names->name; else { if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) - return _process_all(argc, argv, 0, _status); - if (argc == 2) - name = argv[1]; + return _process_all(cmd, argc, argv, 0, _status); + name = argv[1]; } - if (!strcmp(argv[0], "table")) - cmd = DM_DEVICE_TABLE; + if (!strcmp(cmd->name, "table")) + cmdno = DM_DEVICE_TABLE; else - cmd = DM_DEVICE_STATUS; + cmdno = DM_DEVICE_STATUS; - if (!strcmp(argv[0], "ls")) + if (!strcmp(cmd->name, "ls")) ls_only = 1; - if (!(dmt = dm_task_create(cmd))) + if (!(dmt = dm_task_create(cmdno))) return 0; if (!_set_task_device(dmt, name, 0)) @@ -1545,6 +1640,12 @@ static int _status(int argc, char **argv, void *data) if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + + if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt)) + goto out; + if (!dm_task_run(dmt)) goto out; @@ -1571,12 +1672,12 @@ static int _status(int argc, char **argv, void *data) _switches[VERBOSE_ARG]) { if (!matched && _switches[VERBOSE_ARG]) _display_info(dmt); - if (data && !_switches[VERBOSE_ARG]) + if (multiple_devices && !_switches[VERBOSE_ARG]) printf("%s: ", name); if (target_type) { /* Suppress encryption key */ if (!_switches[SHOWKEYS_ARG] && - cmd == DM_DEVICE_TABLE && + cmdno == DM_DEVICE_TABLE && !strcmp(target_type, "crypt")) { c = params; while (*c && *c != ' ') @@ -1594,7 +1695,7 @@ static int _status(int argc, char **argv, void *data) matched = 1; } while (next); - if (data && _switches[VERBOSE_ARG] && matched && !ls_only) + if (multiple_devices && _switches[VERBOSE_ARG] && matched && !ls_only) printf("\n"); if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name)) @@ -1608,7 +1709,7 @@ static int _status(int argc, char **argv, void *data) } /* Show target names and their version numbers */ -static int _targets(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused))) +static int _targets(CMD_ARGS) { int r = 0; struct dm_task *dmt; @@ -1618,6 +1719,9 @@ static int _targets(int argc __attribute__((unused)), char **argv __attribute__( if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) return 0; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + if (!dm_task_run(dmt)) goto out; @@ -1640,21 +1744,19 @@ static int _targets(int argc __attribute__((unused)), char **argv __attribute__( return r; } -static int _info(int argc, char **argv, void *data) +static int _info(CMD_ARGS) { int r = 0; struct dm_task *dmt; - struct dm_names *names = (struct dm_names *) data; char *name = NULL; - if (data) + if (names) name = names->name; else { if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) - return _process_all(argc, argv, 0, _info); - if (argc == 2) - name = argv[1]; + return _process_all(cmd, argc, argv, 0, _info); + name = argv[1]; } if (!(dmt = dm_task_create(DM_DEVICE_INFO))) @@ -1669,6 +1771,9 @@ static int _info(int argc, char **argv, void *data) if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + if (!dm_task_run(dmt)) goto out; @@ -1679,23 +1784,23 @@ static int _info(int argc, char **argv, void *data) return r; } -static int _deps(int argc, char **argv, void *data) +static int _deps(CMD_ARGS) { int r = 0; uint32_t i; struct dm_deps *deps; struct dm_task *dmt; struct dm_info info; - struct dm_names *names = (struct dm_names *) data; char *name = NULL; + char dev_name[PATH_MAX]; + int major, minor; - if (data) + if (names) name = names->name; else { if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) - return _process_all(argc, argv, 0, _deps); - if (argc == 2) - name = argv[1]; + return _process_all(cmd, argc, argv, 0, _deps); + name = argv[1]; } if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) @@ -1710,6 +1815,9 @@ static int _deps(int argc, char **argv, void *data) if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; + if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + if (!dm_task_run(dmt)) goto out; @@ -1728,17 +1836,24 @@ static int _deps(int argc, char **argv, void *data) if (_switches[VERBOSE_ARG]) _display_info(dmt); - if (data && !_switches[VERBOSE_ARG]) + if (multiple_devices && !_switches[VERBOSE_ARG]) printf("%s: ", name); printf("%d dependencies\t:", deps->count); - for (i = 0; i < deps->count; i++) - printf(" (%d, %d)", - (int) MAJOR(deps->device[i]), - (int) MINOR(deps->device[i])); + for (i = 0; i < deps->count; i++) { + major = (int) MAJOR(deps->device[i]); + minor = (int) MINOR(deps->device[i]); + + if ((_dev_name_type == DN_BLK || _dev_name_type == DN_MAP) && + dm_device_get_name(major, minor, _dev_name_type == DN_BLK, + dev_name, PATH_MAX)) + printf(" (%s)", dev_name); + else + printf(" (%d, %d)", major, minor); + } printf("\n"); - if (data && _switches[VERBOSE_ARG]) + if (multiple_devices && _switches[VERBOSE_ARG]) printf("\n"); r = 1; @@ -1748,12 +1863,21 @@ static int _deps(int argc, char **argv, void *data) return r; } -static int _display_name(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data) +static int _display_name(CMD_ARGS) { - struct dm_names *names = (struct dm_names *) data; + char dev_name[PATH_MAX]; + + if (!names) + return 1; - printf("%s\t(%d, %d)\n", names->name, - (int) MAJOR(names->dev), (int) MINOR(names->dev)); + if ((_dev_name_type == DN_BLK || _dev_name_type == DN_MAP) && + dm_device_get_name((int) MAJOR(names->dev), (int) MINOR(names->dev), + _dev_name_type == DN_BLK, dev_name, PATH_MAX)) + printf("%s\t(%s)\n", names->name, dev_name); + else + printf("%s\t(%d:%d)\n", names->name, + (int) MAJOR(names->dev), + (int) MINOR(names->dev)); return 1; } @@ -1764,6 +1888,7 @@ static int _display_name(int argc __attribute__((unused)), char **argv __attribu enum { TR_DEVICE=0, /* display device major:minor number */ + TR_BLKDEVNAME, /* display device kernel name */ TR_TABLE, TR_STATUS, TR_ACTIVE, @@ -1970,6 +2095,11 @@ static void _display_tree_attributes(struct dm_tree_node *node) _out_char(']'); } +/* FIXME Display table or status line. (Disallow both?) */ +static void _display_tree_targets(struct dm_tree_node *node, unsigned depth) +{ +} + static void _display_tree_node(struct dm_tree_node *node, unsigned depth, unsigned first_child __attribute__((unused)), unsigned last_child, unsigned has_children) @@ -1978,6 +2108,7 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth, const char *name; const struct dm_info *info; int first_on_line = 0; + char dev_name[PATH_MAX]; /* Sub-tree for targets has 2 more depth */ if (depth + 2 > MAX_DEPTH) @@ -1985,7 +2116,8 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth, name = dm_tree_node_get_name(node); - if ((!name || !*name) && !_tree_switches[TR_DEVICE]) + if ((!name || !*name) && + (!_tree_switches[TR_DEVICE] && !_tree_switches[TR_BLKDEVNAME])) return; /* Indicate whether there are more nodes at this depth */ @@ -2010,6 +2142,13 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth, info = dm_tree_node_get_info(node); + if (_tree_switches[TR_BLKDEVNAME] && + dm_device_get_name(info->major, info->minor, 1, dev_name, PATH_MAX)) { + _out_string(name ? " <" : "<"); + _out_string(dev_name); + _out_char('>'); + } + if (_tree_switches[TR_DEVICE]) { _out_string(name ? " (" : "("); (void) _out_int(info->major); @@ -2030,7 +2169,7 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth, if (TR_PRINT_TARGETS) { _tree_more[depth + 1] = has_children; - // FIXME _display_tree_targets(name, depth + 2); + _display_tree_targets(node, depth + 2); } } @@ -2063,11 +2202,10 @@ static void _display_tree_walk_children(struct dm_tree_node *node, } } -static int _add_dep(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data) +static int _add_dep(CMD_ARGS) { - struct dm_names *names = (struct dm_names *) data; - - if (!dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev))) + if (names && + !dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev))) return 0; return 1; @@ -2076,7 +2214,7 @@ static int _add_dep(int argc __attribute__((unused)), char **argv __attribute__( /* * Create and walk dependency tree */ -static int _build_whole_deptree(void) +static int _build_whole_deptree(const struct command *cmd) { if (_dtree) return 1; @@ -2084,17 +2222,15 @@ static int _build_whole_deptree(void) if (!(_dtree = dm_tree_create())) return 0; - if (!_process_all(0, NULL, 0, _add_dep)) + if (!_process_all(cmd, 0, NULL, 0, _add_dep)) return 0; return 1; } -static int _display_tree(int argc __attribute__((unused)), - char **argv __attribute__((unused)), - void *data __attribute__((unused))) +static int _display_tree(CMD_ARGS) { - if (!_build_whole_deptree()) + if (!_build_whole_deptree(cmd)) return 0; _display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0); @@ -2138,6 +2274,38 @@ static int _dm_name_disp(struct dm_report *rh, return dm_report_field_string(rh, field, &name); } +static int _dm_mangled_name_disp(struct dm_report *rh, + struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, const void *data, + void *private __attribute__((unused))) +{ + char *name; + int r = 0; + + if ((name = dm_task_get_name_mangled((const struct dm_task *) data))) { + r = dm_report_field_string(rh, field, (const char * const *) &name); + dm_free(name); + } + + return r; +} + +static int _dm_unmangled_name_disp(struct dm_report *rh, + struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, const void *data, + void *private __attribute__((unused))) +{ + char *name; + int r = 0; + + if ((name = dm_task_get_name_unmangled((const struct dm_task *) data))) { + r = dm_report_field_string(rh, field, (const char * const *) &name); + dm_free(name); + } + + return r; +} + static int _dm_uuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, @@ -2151,6 +2319,38 @@ static int _dm_uuid_disp(struct dm_report *rh, return dm_report_field_string(rh, field, &uuid); } +static int _dm_mangled_uuid_disp(struct dm_report *rh, + struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + char *uuid; + int r = 0; + + if ((uuid = dm_task_get_uuid_mangled((const struct dm_task *) data))) { + r = dm_report_field_string(rh, field, (const char * const *) &uuid); + dm_free(uuid); + } + + return r; +} + +static int _dm_unmangled_uuid_disp(struct dm_report *rh, + struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + char *uuid; + int r = 0; + + if ((uuid = dm_task_get_uuid_unmangled((const struct dm_task *) data))) { + r = dm_report_field_string(rh, field, (const char * const *) &uuid); + dm_free(uuid); + } + + return r; +} + static int _dm_read_ahead_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, @@ -2164,6 +2364,24 @@ static int _dm_read_ahead_disp(struct dm_report *rh, return dm_report_field_uint32(rh, field, &value); } +static int _dm_blk_name_disp(struct dm_report *rh, + struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, const void *data, + void *private __attribute__((unused))) +{ + char dev_name[PATH_MAX]; + const char *s = dev_name; + const struct dm_info *info = data; + + if (!dm_device_get_name(info->major, info->minor, 1, dev_name, PATH_MAX)) { + log_error("Could not resolve block device name for %d:%d.", + info->major, info->minor); + return 0; + } + + return dm_report_field_string(rh, field, &s); +} + static int _dm_info_status_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, @@ -2243,7 +2461,7 @@ static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { - char buf[DM_MAX_TYPE_NAME], *repstr; + char buf[PATH_MAX], *repstr; const struct dm_info *info = data; if (!dm_pool_begin_object(mem, 8)) { @@ -2251,10 +2469,17 @@ static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem, return 0; } - if (dm_snprintf(buf, sizeof(buf), "%d:%d", - info->major, info->minor) < 0) { - log_error("dm_pool_alloc failed"); - goto out_abandon; + if (private) { + if (!dm_device_get_name(info->major, info->minor, + 1, buf, PATH_MAX)) + goto out_abandon; + } + else { + if (dm_snprintf(buf, sizeof(buf), "%d:%d", + info->major, info->minor) < 0) { + log_error("dm_pool_alloc failed"); + goto out_abandon; + } } if (!dm_pool_grow_object(mem, buf, strlen(buf) + 1)) { @@ -2395,13 +2620,14 @@ static int _dm_tree_parents_count_disp(struct dm_report *rh, return dm_report_field_int(rh, field, &num_parent); } -static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem, - struct dm_report_field *field, const void *data, - void *private) +static int _dm_deps_disp_common(struct dm_report *rh, struct dm_pool*mem, + struct dm_report_field *field, const void *data, + void *private, int disp_blk_dev_names) { const struct dm_deps *deps = data; - int i; - char buf[DM_MAX_TYPE_NAME], *repstr; + char buf[PATH_MAX], *repstr; + int major, minor; + unsigned i; if (!dm_pool_begin_object(mem, 16)) { log_error("dm_pool_begin_object failed"); @@ -2409,16 +2635,27 @@ static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem, } for (i = 0; i < deps->count; i++) { - if (dm_snprintf(buf, sizeof(buf), "%d:%d", - (int) MAJOR(deps->device[i]), - (int) MINOR(deps->device[i])) < 0) { + major = (int) MAJOR(deps->device[i]); + minor = (int) MINOR(deps->device[i]); + + if (disp_blk_dev_names) { + if (!dm_device_get_name(major, minor, 1, buf, PATH_MAX)) { + log_error("Could not resolve block device " + "name for %d:%d.", major, minor); + goto out_abandon; + } + } + else if (dm_snprintf(buf, sizeof(buf), "%d:%d", + major, minor) < 0) { log_error("dm_snprintf failed"); goto out_abandon; } + if (!dm_pool_grow_object(mem, buf, 0)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } + if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; @@ -2439,12 +2676,26 @@ static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem, return 0; } +static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, const void *data, + void *private) +{ + return _dm_deps_disp_common(rh, mem, field, data, private, 0); +} + +static int _dm_deps_blk_names_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + return _dm_deps_disp_common(rh, mem, field, data, private, 1); +} + static int _dm_subsystem_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { - return dm_report_field_string(rh, field, (const char **) data); + return dm_report_field_string(rh, field, (const char *const *) data); } static int _dm_vg_name_disp(struct dm_report *rh, @@ -2453,7 +2704,7 @@ static int _dm_vg_name_disp(struct dm_report *rh, void *private __attribute__((unused))) { - return dm_report_field_string(rh, field, (const char **) data); + return dm_report_field_string(rh, field, (const char *const *) data); } static int _dm_lv_name_disp(struct dm_report *rh, @@ -2462,7 +2713,7 @@ static int _dm_lv_name_disp(struct dm_report *rh, void *private __attribute__((unused))) { - return dm_report_field_string(rh, field, (const char **) data); + return dm_report_field_string(rh, field, (const char *const *) data); } static int _dm_lv_layer_name_disp(struct dm_report *rh, @@ -2471,7 +2722,7 @@ static int _dm_lv_layer_name_disp(struct dm_report *rh, void *private __attribute__((unused))) { - return dm_report_field_string(rh, field, (const char **) data); + return dm_report_field_string(rh, field, (const char *const *) data); } static void *_task_get_obj(void *obj) @@ -2518,11 +2769,16 @@ static const struct dm_report_object_type _report_types[] = { static const struct dm_report_field_type _report_fields[] = { /* *INDENT-OFF* */ FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.") +FIELD_F(TASK, STR, "MangledName", 16, dm_mangled_name, "mangled_name", "Mangled name of mapped device.") +FIELD_F(TASK, STR, "UnmangledName", 16, dm_unmangled_name, "unmangled_name", "Unmangled name of mapped device.") FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.") +FIELD_F(TASK, STR, "MangledUUID", 32, dm_mangled_uuid, "mangled_uuid", "Mangled unique (optional) identifier for mapped device.") +FIELD_F(TASK, STR, "UnmangledUUID", 32, dm_unmangled_uuid, "unmangled_uuid", "Unmangled unique (optional) identifier for mapped device.") /* FIXME Next one should be INFO */ FIELD_F(TASK, NUM, "RAhead", 6, dm_read_ahead, "read_ahead", "Read ahead in sectors.") +FIELD_F(INFO, STR, "BlkDevName", 16, dm_blk_name, "blkdevname", "Name of block device.") FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.") FIELD_F(INFO, STR, "Tables", 6, dm_info_table_loaded, "tables_loaded", "Which of the live and inactive table slots are filled.") FIELD_F(INFO, STR, "Suspended", 9, dm_info_suspended, "suspended", "Whether the device is suspended.") @@ -2535,8 +2791,9 @@ FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.") FIELD_O(DEPS, dm_deps, NUM, "#Devs", count, 5, int32, "device_count", "Number of devices used by this one.") -FIELD_F(TREE, STR, "DevNames", 8, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.") -FIELD_F(DEPS, STR, "DevNos", 6, dm_deps, "devnos_used", "List of device numbers of devices used by this one.") +FIELD_F(TREE, STR, "DevNamesUsed", 16, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.") +FIELD_F(DEPS, STR, "DevNosUsed", 16, dm_deps, "devnos_used", "List of device numbers of devices used by this one.") +FIELD_F(DEPS, STR, "BlkDevNamesUsed", 16, dm_deps_blk_names, "blkdevs_used", "List of names of block devices used by this one.") FIELD_F(TREE, NUM, "#Refs", 5, dm_tree_parents_count, "device_ref_count", "Number of mapped devices referencing this one.") FIELD_F(TREE, STR, "RefNames", 8, dm_tree_parents_names, "names_using_dev", "List of names of mapped devices using this one.") @@ -2559,7 +2816,7 @@ FIELD_O(NAME, dm_split_name, STR, "LVLayer", lv_layer, 7, dm_lv_layer_name, "lv_ static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid"; static const char *splitname_report_options = "vg_name,lv_name,lv_layer"; -static int _report_init(struct command *c) +static int _report_init(const struct command *cmd) { char *options = (char *) default_report_options; const char *keys = ""; @@ -2570,7 +2827,7 @@ static int _report_init(struct command *c) size_t len = 0; int r = 0; - if (c && !strcmp(c->name, "splitname")) + if (cmd && !strcmp(cmd->name, "splitname")) options = (char *) splitname_report_options; /* emulate old dmsetup behaviour */ @@ -2616,7 +2873,7 @@ static int _report_init(struct command *c) if (_switches[SORT_ARG] && _string_args[SORT_ARG]) { keys = _string_args[SORT_ARG]; buffered = 1; - if (c && (!strcmp(c->name, "status") || !strcmp(c->name, "table"))) { + if (cmd && (!strcmp(cmd->name, "status") || !strcmp(cmd->name, "table"))) { err("--sort is not yet supported with status and table"); goto out; } @@ -2650,7 +2907,7 @@ static int _report_init(struct command *c) options, separator, flags, keys, NULL))) goto out; - if ((_report_type & DR_TREE) && !_build_whole_deptree()) { + if ((_report_type & DR_TREE) && !_build_whole_deptree(cmd)) { err("Internal device dependency tree creation failed."); goto out; } @@ -2673,56 +2930,149 @@ out: /* * List devices */ -static int _ls(int argc, char **argv, void *data) +static int _ls(CMD_ARGS) { if ((_switches[TARGET_ARG] && _target) || (_switches[EXEC_ARG] && _command)) - return _status(argc, argv, data); + return _status(cmd, argc, argv, NULL, 0); else if ((_switches[TREE_ARG])) - return _display_tree(argc, argv, data); + return _display_tree(cmd, 0, NULL, NULL, 0); else - return _process_all(argc, argv, 0, _display_name); + return _process_all(cmd, argc, argv, 0, _display_name); } -static int _help(int argc, char **argv, void *data); +static int _mangle(CMD_ARGS) +{ + const char *name, *uuid; + char *new_name = NULL, *new_uuid = NULL; + struct dm_task *dmt; + struct dm_info info; + int r = 0; + int target_format; + + if (names) + name = names->name; + else { + if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) + return _process_all(cmd, argc, argv, 0, _mangle); + name = argv[1]; + } + + if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) + return 0; + + if (!(_set_task_device(dmt, name, 0))) + goto out; + + if (!_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) + goto out; + + if (!dm_task_run(dmt)) + goto out; + + if (!dm_task_get_info(dmt, &info) || !info.exists) + goto out; + + uuid = dm_task_get_uuid(dmt); + + target_format = _switches[MANGLENAME_ARG] ? _int_args[MANGLENAME_ARG] + : DEFAULT_DM_NAME_MANGLING; + + if (target_format == DM_STRING_MANGLING_AUTO) { + if (strstr(name, "\\x5cx")) { + log_error("The name \"%s\" seems to be mangled more than once. " + "Manual intervention required to rename the device.", name); + goto out; + } + if (strstr(uuid, "\\x5cx")) { + log_error("The UUID \"%s\" seems to be mangled more than once. " + "Manual intervention required to correct the device UUID.", uuid); + goto out; + } + } + + if (target_format == DM_STRING_MANGLING_NONE) { + if (!(new_name = dm_task_get_name_unmangled(dmt))) + goto out; + if (!(new_uuid = dm_task_get_uuid_unmangled(dmt))) + goto out; + } + else { + if (!(new_name = dm_task_get_name_mangled(dmt))) + goto out; + if (!(new_uuid = dm_task_get_uuid_mangled(dmt))) + goto out; + } + + /* We can't rename the UUID, the device must be reactivated manually. */ + if (strcmp(uuid, new_uuid)) { + log_error("%s: %s: UUID in incorrect form. ", name, uuid); + log_error("Unable to change device UUID. The device must be deactivated first."); + r = 0; + goto out; + } + + /* Nothing to do if the name is in correct form already. */ + if (!strcmp(name, new_name)) { + log_print("%s: %s: name %salready in correct form", name, + *uuid ? uuid : "[no UUID]", *uuid ? "and UUID " : ""); + r = 1; + goto out; + } + else + log_print("%s: renaming to %s", name, new_name); + + /* Rename to correct form of the name. */ + r = _do_rename(name, new_name, NULL); + +out: + dm_free(new_name); + dm_free(new_uuid); + dm_task_destroy(dmt); + return r; +} + +static int _help(CMD_ARGS); /* * Dispatch table */ static struct command _commands[] = { - {"help", "[-c|-C|--columns]", 0, 0, _help}, + {"help", "[-c|-C|--columns]", 0, 0, 0, _help}, {"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n" "\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n" - "\t [-u|uuid <uuid>]\n" + "\t [-u|uuid <uuid>] [{--addnodeonresume|--addnodeoncreate}]\n" "\t [--notable | --table <table> | <table_file>]", - 1, 2, _create}, - {"remove", "[-f|--force] <device>", 0, 1, _remove}, - {"remove_all", "[-f|--force]", 0, 0, _remove_all}, - {"suspend", "[--noflush] <device>", 0, 1, _suspend}, - {"resume", "<device>", 0, 1, _resume}, - {"load", "<device> [<table_file>]", 0, 2, _load}, - {"clear", "<device>", 0, 1, _clear}, - {"reload", "<device> [<table_file>]", 0, 2, _load}, - {"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, _rename}, - {"message", "<device> <sector> <message>", 2, -1, _message}, - {"ls", "[--target <target_type>] [--exec <command>] [--tree [-o options]]", 0, 0, _ls}, - {"info", "[<device>]", 0, 1, _info}, - {"deps", "[<device>]", 0, 1, _deps}, - {"status", "[<device>] [--target <target_type>]", 0, 1, _status}, - {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, 1, _status}, - {"wait", "<device> [<event_nr>]", 0, 2, _wait}, - {"mknodes", "[<device>]", 0, 1, _mknodes}, - {"udevcreatecookie", "", 0, 0, _udevcreatecookie}, - {"udevreleasecookie", "[<cookie>]", 0, 1, _udevreleasecookie}, - {"udevflags", "<cookie>", 1, 1, _udevflags}, - {"udevcomplete", "<cookie>", 1, 1, _udevcomplete}, - {"udevcomplete_all", "", 0, 0, _udevcomplete_all}, - {"udevcookies", "", 0, 0, _udevcookies}, - {"targets", "", 0, 0, _targets}, - {"version", "", 0, 0, _version}, - {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, _setgeometry}, - {"splitname", "<device> [<subsystem>]", 1, 2, _splitname}, - {NULL, NULL, 0, 0, NULL} + 1, 2,0, _create}, + {"remove", "[-f|--force] <device>", 0, -1, 1, _remove}, + {"remove_all", "[-f|--force]", 0, 0, 0, _remove_all}, + {"suspend", "[--noflush] <device>", 0, -1, 1, _suspend}, + {"resume", "<device> [{--addnodeonresume|--addnodeoncreate}]", 0, -1, 1, _resume}, + {"load", "<device> [<table_file>]", 0, 2, 0, _load}, + {"clear", "<device>", 0, -1, 1, _clear}, + {"reload", "<device> [<table_file>]", 0, 2, 0, _load}, + {"wipe_table", "<device>", 0, -1, 1, _error_device}, + {"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, 0, _rename}, + {"message", "<device> <sector> <message>", 2, -1, 0, _message}, + {"ls", "[--target <target_type>] [--exec <command>] [-o options] [--tree]", 0, 0, 0, _ls}, + {"info", "[<device>]", 0, -1, 1, _info}, + {"deps", "[-o options] [<device>]", 0, -1, 1, _deps}, + {"status", "[<device>] [--noflush] [--target <target_type>]", 0, -1, 1, _status}, + {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, -1, 1, _status}, + {"wait", "<device> [<event_nr>] [--noflush]", 0, 2, 0, _wait}, + {"mknodes", "[<device>]", 0, -1, 1, _mknodes}, + {"mangle", "[<device>]", 0, -1, 1, _mangle}, + {"udevcreatecookie", "", 0, 0, 0, _udevcreatecookie}, + {"udevreleasecookie", "[<cookie>]", 0, 1, 0, _udevreleasecookie}, + {"udevflags", "<cookie>", 1, 1, 0, _udevflags}, + {"udevcomplete", "<cookie>", 1, 1, 0, _udevcomplete}, + {"udevcomplete_all", "<age_in_minutes>", 0, 1, 0, _udevcomplete_all}, + {"udevcookies", "", 0, 0, 0, _udevcookies}, + {"targets", "", 0, 0, 0, _targets}, + {"version", "", 0, 0, 0, _version}, + {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, 0, _setgeometry}, + {"splitname", "<device> [<subsystem>]", 1, 2, 0, _splitname}, + {NULL, NULL, 0, 0, 0, NULL} }; static void _usage(FILE *out) @@ -2731,20 +3081,22 @@ static void _usage(FILE *out) fprintf(out, "Usage:\n\n"); fprintf(out, "dmsetup [--version] [-h|--help [-c|-C|--columns]]\n" - " [-v|--verbose [-v|--verbose ...]]\n" + " [--checks] [--manglename <mangling_mode>] [-v|--verbose [-v|--verbose ...]]\n" " [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n" - " [--udevcookie] [--noudevrules] [--noudevsync] [-y|--yes]\n" - " [--readahead [+]<sectors>|auto|none]\n" + " [--udevcookie [cookie]] [--noudevrules] [--noudevsync] [--verifyudev]\n" + " [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n" " [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n" " [--nameprefixes] [--noheadings] [--separator <separator>]\n\n"); for (i = 0; _commands[i].name; i++) fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help); fprintf(out, "\n<device> may be device name or -u <uuid> or " "-j <major> -m <minor>\n"); + fprintf(out, "<mangling_mode> is one of 'none', 'auto' and 'hex'.\n"); fprintf(out, "<fields> are comma-separated. Use 'help -c' for list.\n"); fprintf(out, "Table_file contents may be supplied on stdin.\n"); - fprintf(out, "Tree options are: ascii, utf, vt100; compact, inverted, notrunc;\n" - " [no]device, active, open, rw and uuid.\n"); + fprintf(out, "Options are: devno, devname, blkdevname.\n"); + fprintf(out, "Tree specific options are: ascii, utf, vt100; compact, inverted, notrunc;\n" + " blkdevname, [no]device, active, open, rw and uuid.\n"); fprintf(out, "\n"); } @@ -2755,9 +3107,7 @@ static void _losetup_usage(FILE *out) "[-o offset] [-f|loop_device] [file]\n\n"); } -static int _help(int argc __attribute__((unused)), - char **argv __attribute__((unused)), - void *data __attribute__((unused))) +static int _help(CMD_ARGS) { _usage(stderr); @@ -2770,7 +3120,7 @@ static int _help(int argc __attribute__((unused)), dm_report_free(_report); _report = NULL; } - (void) _report_init(NULL); + (void) _report_init(cmd); } return 1; @@ -2810,6 +3160,8 @@ static int _process_tree_options(const char *options) ; if (!strncmp(s, "device", len)) _tree_switches[TR_DEVICE] = 1; + else if (!strncmp(s, "blkdevname", len)) + _tree_switches[TR_BLKDEVNAME] = 1; else if (!strncmp(s, "nodevice", len)) _tree_switches[TR_DEVICE] = 0; else if (!strncmp(s, "status", len)) @@ -2865,6 +3217,8 @@ static char *_get_abspath(const char *path) _path = canonicalize_file_name(path); #else /* FIXME Provide alternative */ + log_error(INTERNAL_ERROR "Unimplemented _get_abspath."); + _path = NULL; #endif return _path; } @@ -2872,7 +3226,7 @@ static char *_get_abspath(const char *path) static char *parse_loop_device_name(const char *dev, const char *dev_dir) { char *buf; - char *device; + char *device = NULL; if (!(buf = dm_malloc(PATH_MAX))) return NULL; @@ -2890,7 +3244,8 @@ static char *parse_loop_device_name(const char *dev, const char *dev_dir) device[strlen(dev_dir)] != '/') goto error; - strncpy(buf, strrchr(device, '/') + 1, (size_t) PATH_MAX); + strncpy(buf, strrchr(device, '/') + 1, PATH_MAX - 1); + buf[PATH_MAX - 1] = '\0'; dm_free(device); } else { @@ -2904,7 +3259,9 @@ static char *parse_loop_device_name(const char *dev, const char *dev_dir) return buf; error: + dm_free(device); dm_free(buf); + return NULL; } @@ -2952,7 +3309,8 @@ static int _loop_table(char *table, size_t tlen, char *file, blksize = fsbuf.f_frsize; #endif - close(fd); + if (close(fd)) + log_sys_error("close", file); if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL, (long long unsigned)sectors, file, (long long unsigned)off) < 0) @@ -2964,15 +3322,15 @@ static int _loop_table(char *table, size_t tlen, char *file, return 1; error: - if (fd > -1) - close(fd); + if (fd > -1 && close(fd)) + log_sys_error("close", file); + return 0; } static int _process_losetup_switches(const char *base, int *argc, char ***argv, const char *dev_dir) { - static int ind; int c; int encrypt_loop = 0, delete = 0, find = 0, show_all = 0; char *device_name = NULL; @@ -2987,8 +3345,8 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv, optarg = 0; optind = OPTIND_INIT; - while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v", - long_options, NULL)) != -1 ) { + while ((c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v", + long_options, NULL)) != -1 ) { if (c == ':' || c == '?') return 0; if (c == 'a') @@ -3065,9 +3423,9 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv, return 0; } - /* FIXME Missing free */ _table = dm_malloc(LOOP_TABLE_SIZE); - if (!_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) { + if (!_table || + !_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) { fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]); dm_free(device_name); return 0; @@ -3080,21 +3438,68 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv, return 1; } +static int _process_options(const char *options) +{ + const char *s, *end; + size_t len; + + /* Tree options are processed separately. */ + if (_switches[TREE_ARG]) + return _process_tree_options(_string_args[OPTIONS_ARG]); + + /* Column options are processed separately by _report_init (called later). */ + if (_switches[COLS_ARG]) + return 1; + + /* No options specified. */ + if (!_switches[OPTIONS_ARG]) + return 1; + + /* Set defaults. */ + _dev_name_type = DN_DEVNO; + + /* Parse. */ + for (s = options; s && *s; s++) { + len = 0; + for (end = s; *end && *end != ','; end++, len++) + ; + if (!strncmp(s, "devno", len)) + _dev_name_type = DN_DEVNO; + else if (!strncmp(s, "blkdevname", len)) + _dev_name_type = DN_BLK; + else if (!strncmp(s, "devname", len)) + _dev_name_type = DN_MAP; + else { + fprintf(stderr, "Option not recognised: %s\n", s); + return 0; + } + + if (!*end) + break; + s = end; + } + + return 1; +} + static int _process_switches(int *argc, char ***argv, const char *dev_dir) { - char *base, *namebase, *s; + const char *base; + char *namebase, *s; static int ind; int c, r; #ifdef HAVE_GETOPTLONG static struct option long_options[] = { {"readonly", 0, &ind, READ_ONLY}, + {"checks", 0, &ind, CHECKS_ARG}, {"columns", 0, &ind, COLS_ARG}, {"exec", 1, &ind, EXEC_ARG}, {"force", 0, &ind, FORCE_ARG}, {"gid", 1, &ind, GID_ARG}, {"help", 0, &ind, HELP_ARG}, {"inactive", 0, &ind, INACTIVE_ARG}, + {"manglename", 1, &ind, MANGLENAME_ARG}, {"major", 1, &ind, MAJOR_ARG}, {"minor", 1, &ind, MINOR_ARG}, {"mode", 1, &ind, MODE_ARG}, @@ -3109,6 +3514,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) {"noudevsync", 0, &ind, NOUDEVSYNC_ARG}, {"options", 1, &ind, OPTIONS_ARG}, {"readahead", 1, &ind, READAHEAD_ARG}, + {"retry", 0, &ind, RETRY_ARG}, {"rows", 0, &ind, ROWS_ARG}, {"separator", 1, &ind, SEPARATOR_ARG}, {"setuuid", 0, &ind, SETUUID_ARG}, @@ -3122,8 +3528,11 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) {"unbuffered", 0, &ind, UNBUFFERED_ARG}, {"unquoted", 0, &ind, UNQUOTED_ARG}, {"verbose", 1, &ind, VERBOSE_ARG}, + {"verifyudev", 0, &ind, VERIFYUDEV_ARG}, {"version", 0, &ind, VERSION_ARG}, {"yes", 0, &ind, YES_ARG}, + {"addnodeonresume", 0, &ind, ADD_NODE_ON_RESUME_ARG}, + {"addnodeoncreate", 0, &ind, ADD_NODE_ON_CREATE_ARG}, {0, 0, 0, 0} }; #else @@ -3137,8 +3546,11 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) memset(&_int_args, 0, sizeof(_int_args)); _read_ahead_flags = 0; - namebase = strdup((*argv)[0]); - base = basename(namebase); + if (!(namebase = strdup((*argv)[0]))) { + fprintf(stderr, "Failed to duplicate name.\n"); + return 0; + } + base = dm_basename(namebase); if (!strcmp(base, "devmap_name")) { free(namebase); @@ -3221,6 +3633,12 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) } if (c == 'y' || ind == YES_ARG) _switches[YES_ARG]++; + if (ind == ADD_NODE_ON_RESUME_ARG) + _switches[ADD_NODE_ON_RESUME_ARG]++; + if (ind == ADD_NODE_ON_CREATE_ARG) + _switches[ADD_NODE_ON_CREATE_ARG]++; + if (ind == CHECKS_ARG) + _switches[CHECKS_ARG]++; if (ind == UDEVCOOKIE_ARG) { _switches[UDEVCOOKIE_ARG]++; _udev_cookie = _get_cookie_value(optarg); @@ -3229,6 +3647,8 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) _switches[NOUDEVRULES_ARG]++; if (ind == NOUDEVSYNC_ARG) _switches[NOUDEVSYNC_ARG]++; + if (ind == VERIFYUDEV_ARG) + _switches[VERIFYUDEV_ARG]++; if (c == 'G' || ind == GID_ARG) { _switches[GID_ARG]++; _int_args[GID_ARG] = atoi(optarg); @@ -3242,32 +3662,46 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) /* FIXME Accept modes as per chmod */ _int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8); } - if ((ind == EXEC_ARG)) { + if (ind == EXEC_ARG) { _switches[EXEC_ARG]++; _command = optarg; } - if ((ind == TARGET_ARG)) { + if (ind == TARGET_ARG) { _switches[TARGET_ARG]++; _target = optarg; } - if ((ind == INACTIVE_ARG)) - _switches[INACTIVE_ARG]++; - if ((ind == NAMEPREFIXES_ARG)) + if (ind == INACTIVE_ARG) + _switches[INACTIVE_ARG]++; + if ((ind == MANGLENAME_ARG)) { + _switches[MANGLENAME_ARG]++; + if (!strcasecmp(optarg, "none")) + _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_NONE; + else if (!strcasecmp(optarg, "auto")) + _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_AUTO; + else if (!strcasecmp(optarg, "hex")) + _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_HEX; + else { + log_error("Unknown name mangling mode"); + return 0; + } + dm_set_name_mangling_mode((dm_string_mangling_t) _int_args[MANGLENAME_ARG]); + } + if (ind == NAMEPREFIXES_ARG) _switches[NAMEPREFIXES_ARG]++; - if ((ind == NOFLUSH_ARG)) + if (ind == NOFLUSH_ARG) _switches[NOFLUSH_ARG]++; - if ((ind == NOHEADINGS_ARG)) + if (ind == NOHEADINGS_ARG) _switches[NOHEADINGS_ARG]++; - if ((ind == NOLOCKFS_ARG)) + if (ind == NOLOCKFS_ARG) _switches[NOLOCKFS_ARG]++; - if ((ind == NOOPENCOUNT_ARG)) + if (ind == NOOPENCOUNT_ARG) _switches[NOOPENCOUNT_ARG]++; - if ((ind == READAHEAD_ARG)) { + if (ind == READAHEAD_ARG) { _switches[READAHEAD_ARG]++; if (!strcasecmp(optarg, "auto")) _int_args[READAHEAD_ARG] = DM_READ_AHEAD_AUTO; else if (!strcasecmp(optarg, "none")) - _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE; + _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE; else { for (s = optarg; isspace(*s); s++) ; @@ -3282,21 +3716,26 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) } } } - if ((ind == ROWS_ARG)) + if (ind == RETRY_ARG) + _switches[RETRY_ARG]++; + if (ind == ROWS_ARG) _switches[ROWS_ARG]++; - if ((ind == SETUUID_ARG)) + if (ind == SETUUID_ARG) _switches[SETUUID_ARG]++; - if ((ind == SHOWKEYS_ARG)) + if (ind == SHOWKEYS_ARG) _switches[SHOWKEYS_ARG]++; - if ((ind == TABLE_ARG)) { + if (ind == TABLE_ARG) { _switches[TABLE_ARG]++; - _table = optarg; + if (!(_table = dm_strdup(optarg))) { + log_error("Could not allocate memory for table string."); + return 0; + } } - if ((ind == TREE_ARG)) + if (ind == TREE_ARG) _switches[TREE_ARG]++; - if ((ind == UNQUOTED_ARG)) + if (ind == UNQUOTED_ARG) _switches[UNQUOTED_ARG]++; - if ((ind == VERSION_ARG)) + if (ind == VERSION_ARG) _switches[VERSION_ARG]++; } @@ -3310,7 +3749,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) return 0; } - if (_switches[TREE_ARG] && !_process_tree_options(_string_args[OPTIONS_ARG])) + if (!_process_options(_string_args[OPTIONS_ARG])) return 0; if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) { @@ -3318,6 +3757,11 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) return 0; } + if (_switches[ADD_NODE_ON_RESUME_ARG] && _switches[ADD_NODE_ON_CREATE_ARG]) { + fprintf(stderr, "--addnodeonresume and --addnodeoncreate are incompatible.\n"); + return 0; + } + *argv += optind; *argc -= optind; return 1; @@ -3325,9 +3769,10 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) int main(int argc, char **argv) { - struct command *c; int r = 1; const char *dev_dir; + const struct command *cmd; + int multiple_devices; (void) setlocale(LC_ALL, ""); @@ -3346,12 +3791,12 @@ int main(int argc, char **argv) } if (_switches[HELP_ARG]) { - c = _find_command("help"); + cmd = _find_command("help"); goto doit; } if (_switches[VERSION_ARG]) { - c = _find_command("version"); + cmd = _find_command("version"); goto doit; } @@ -3360,27 +3805,30 @@ int main(int argc, char **argv) goto out; } - if (!(c = _find_command(argv[0]))) { + if (!(cmd = _find_command(argv[0]))) { fprintf(stderr, "Unknown command\n"); _usage(stderr); goto out; } - if (argc < c->min_args + 1 || - (c->max_args >= 0 && argc > c->max_args + 1)) { + if (argc < cmd->min_args + 1 || + (cmd->max_args >= 0 && argc > cmd->max_args + 1)) { fprintf(stderr, "Incorrect number of arguments\n"); _usage(stderr); goto out; } - if (!_switches[COLS_ARG] && !strcmp(c->name, "splitname")) + if (!_switches[COLS_ARG] && !strcmp(cmd->name, "splitname")) _switches[COLS_ARG]++; + if (!strcmp(cmd->name, "mangle")) + dm_set_name_mangling_mode(DM_STRING_MANGLING_NONE); + if (_switches[COLS_ARG]) { - if (!_report_init(c)) + if (!_report_init(cmd)) goto out; if (!_report) { - if (!strcmp(c->name, "info")) + if (!strcmp(cmd->name, "info")) r = 0; /* info -c -o help */ goto out; } @@ -3392,10 +3840,14 @@ int main(int argc, char **argv) #endif doit: - if (!c->fn(argc, argv, NULL)) { - fprintf(stderr, "Command failed\n"); - goto out; - } + multiple_devices = (cmd->repeatable_cmd && argc != 2 && + (argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]))); + do { + if (!cmd->fn(cmd, argc--, argv++, NULL, multiple_devices)) { + fprintf(stderr, "Command failed\n"); + goto out; + } + } while (cmd->repeatable_cmd && argc > 1); r = 0; @@ -3408,5 +3860,7 @@ out: if (_dtree) dm_tree_free(_dtree); + dm_free(_table); + return r; } |