diff --git a/libdm/.export.sym b/libdm/.export.sym index 07ce90884..0399e6e2e 100644 --- a/libdm/.export.sym +++ b/libdm/.export.sym @@ -10,6 +10,8 @@ Base { dm_task_get_driver_version; dm_task_get_info; dm_task_get_deps; + dm_task_get_name; + dm_task_get_names; dm_task_get_uuid; dm_task_set_ro; dm_task_set_newname; @@ -21,6 +23,9 @@ Base { dm_task_run; dm_set_dev_dir; dm_dir; + dm_format_dev; + dm_lib_release; + dm_lib_exit; local: *; }; diff --git a/libdm/ioctl/libdevmapper.c b/libdm/ioctl/libdevmapper.c index 02e7e00af..05f753cb6 100644 --- a/libdm/ioctl/libdevmapper.c +++ b/libdm/ioctl/libdevmapper.c @@ -13,7 +13,10 @@ #include #include #include +#include #include +#include +#include #include /* @@ -31,6 +34,10 @@ static int _dm_version = DM_VERSION_MAJOR; static int _log_suppress = 0; +static int _control_fd = -1; +static int _version_checked = 0; +static int _version_ok = 1; + /* * Support both old and new major numbers to ease the transition. * Clumsy, but only temporary. @@ -45,18 +52,20 @@ const int _dm_compat = 0; /* *INDENT-OFF* */ static struct cmd_data _cmd_data_v4[] = { {"create", DM_DEV_CREATE, {4, 0, 0}}, - {"reload", DM_DEV_RELOAD, {4, 0, 0}}, + {"reload", DM_TABLE_LOAD, {4, 0, 0}}, {"remove", DM_DEV_REMOVE, {4, 0, 0}}, {"remove_all", DM_REMOVE_ALL, {4, 0, 0}}, {"suspend", DM_DEV_SUSPEND, {4, 0, 0}}, {"resume", DM_DEV_SUSPEND, {4, 0, 0}}, {"info", DM_DEV_STATUS, {4, 0, 0}}, - {"deps", DM_DEV_DEPS, {4, 0, 0}}, + {"deps", DM_TABLE_DEPS, {4, 0, 0}}, {"rename", DM_DEV_RENAME, {4, 0, 0}}, {"version", DM_VERSION, {4, 0, 0}}, - {"status", DM_TARGET_STATUS, {4, 0, 0}}, - {"table", DM_TARGET_STATUS, {4, 0, 0}}, - {"waitevent", DM_TARGET_WAIT, {4, 0, 0}}, + {"status", DM_TABLE_STATUS, {4, 0, 0}}, + {"table", DM_TABLE_STATUS, {4, 0, 0}}, + {"waitevent", DM_DEV_WAIT, {4, 0, 0}}, + {"names", DM_LIST_DEVICES, {4, 0, 0}}, + {"clear", DM_TABLE_CLEAR, {4, 0, 0}}, }; /* *INDENT-ON* */ @@ -113,6 +122,20 @@ static int _unmarshal_status_v1(struct dm_task *dmt, struct dm_ioctl_v1 *dmi) return 1; } +static int _dm_format_dev_v1(char *buf, int bufsize, uint32_t dev_major, uint32_t dev_minor) +{ + int r; + + if (bufsize < 8) + return 0; + + r = snprintf(buf, bufsize, "%03x:%03x", dev_major, dev_minor); + if (r < 0 || r > bufsize - 1) + return 0; + + return 1; +} + static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info) { if (!dmt->dmi.v1) @@ -131,10 +154,17 @@ static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info) info->event_nr = 0; info->major = MAJOR(dmt->dmi.v1->dev); info->minor = MINOR(dmt->dmi.v1->dev); + info->live_table = 1; + info->inactive_table = 0; return 1; } +static const char *_dm_task_get_name_v1(struct dm_task *dmt) +{ + return (dmt->dmi.v1->name); +} + static const char *_dm_task_get_uuid_v1(struct dm_task *dmt) { return (dmt->dmi.v1->uuid); @@ -146,6 +176,12 @@ static struct dm_deps *_dm_task_get_deps_v1(struct dm_task *dmt) return NULL; } +static struct dm_names *_dm_task_get_names_v1(struct dm_task *dmt) +{ + return (struct dm_names *) (((void *) dmt->dmi.v1) + + dmt->dmi.v1->data_start); +} + static void *_add_target_v1(struct target *t, void *out, void *end) { void *out_sp = out; @@ -271,12 +307,86 @@ static struct dm_ioctl_v1 *_flatten_v1(struct dm_task *dmt) return NULL; } +static int _dm_names_v1(struct dm_ioctl_v1 *dmi) +{ + const char *dev_dir = dm_dir(); + int r = 1, len; + const char *name; + struct dirent *dirent; + DIR *d; + struct dm_names *names, *old_names = NULL; + void *end = (void *) dmi + dmi->data_size; + struct stat buf; + char path[PATH_MAX]; + + if (!(d = opendir(dev_dir))) { + log_error("%s: opendir failed: %s", dev_dir, strerror(errno)); + return 0; + } + + names = (struct dm_names *) ((void *) dmi + dmi->data_start); + + names->dev = 0; /* Flags no data */ + + while ((dirent = readdir(d))) { + name = dirent->d_name; + + if (name[0] == '.' || !strcmp(name, "control")) + continue; + + if (old_names) + old_names->next = (uint32_t) ((void *) names - + (void *) old_names); + snprintf(path, sizeof(path), "%s/%s", dev_dir, name); + if (stat(path, &buf)) { + log_error("%s: stat failed: %s", path, strerror(errno)); + continue; + } + if (!S_ISBLK(buf.st_mode)) + continue; + names->dev = (uint64_t) buf.st_rdev; + names->next = 0; + len = strlen(name); + if (((void *) (names + 1) + len + 1) >= end) { + log_error("Insufficient buffer space for device list"); + r = 0; + break; + } + + strcpy(names->name, name); + + old_names = names; + names = _align((void *) ++names + len + 1, ALIGNMENT); + } + + if (closedir(d)) + log_error("%s: closedir failed: %s", dev_dir, strerror(errno)); + + return r; +} + +static int _open_control(void) +{ + char control[PATH_MAX]; + + if (_control_fd != -1) + return 1; + + snprintf(control, sizeof(control), "%s/control", dm_dir()); + + if ((_control_fd = open(control, O_RDWR)) < 0) { + log_error("%s: open failed: %s", control, strerror(errno)); + log_error("Is device-mapper driver missing from kernel?"); + return 0; + } + + return 1; +} + static int _dm_task_run_v1(struct dm_task *dmt) { - int fd = -1; struct dm_ioctl_v1 *dmi; unsigned int command; - char control[PATH_MAX]; dmi = _flatten_v1(dmt); if (!dmi) { @@ -284,13 +394,8 @@ static int _dm_task_run_v1(struct dm_task *dmt) return 0; } - snprintf(control, sizeof(control), "%s/control", dm_dir()); - - if ((fd = open(control, O_RDWR)) < 0) { - log_error("%s: open failed: %s", control, strerror(errno)); - log_error("Is device-mapper driver missing from kernel?"); - goto bad; - } + if (!_open_control()) + return 0; if ((unsigned) dmt->type >= (sizeof(_cmd_data_v1) / sizeof(*_cmd_data_v1))) { @@ -306,7 +411,10 @@ static int _dm_task_run_v1(struct dm_task *dmt) log_debug("dm %s %s %s %s", _cmd_data_v1[dmt->type].name, dmi->name, dmi->uuid, dmt->newname ? dmt->newname : ""); - if (ioctl(fd, command, dmi) < 0) { + if (dmt->type == DM_DEVICE_LIST) { + if (!_dm_names_v1(dmi)) + goto bad; + } else if (ioctl(_control_fd, command, dmi) < 0) { if (_log_suppress) log_verbose("device-mapper ioctl cmd %d failed: %s", _IOC_NR(command), strerror(errno)); @@ -337,13 +445,10 @@ static int _dm_task_run_v1(struct dm_task *dmt) } dmt->dmi.v1 = dmi; - close(fd); return 1; bad: free(dmi); - if (fd >= 0) - close(fd); return 0; } @@ -418,15 +523,13 @@ static int _check_version(char *version, size_t size, int log_suppress) */ int dm_check_version(void) { - static int _checked = 0; - static int _ok = 1; char libversion[64], dmversion[64]; const char *compat = ""; - if (_checked) - return _ok; + if (_version_checked) + return _version_ok; - _checked = 1; + _version_checked = 1; if (_check_version(dmversion, sizeof(dmversion), _dm_compat)) return 1; @@ -450,7 +553,7 @@ int dm_check_version(void) libversion, compat, dmversion); bad: - _ok = 0; + _version_ok = 0; return 0; } @@ -496,6 +599,23 @@ static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi) return 1; } +int dm_format_dev(char *buf, int bufsize, uint32_t dev_major, uint32_t dev_minor) +{ + int r; + + if (_dm_version == 1) + return _dm_format_dev_v1(buf, bufsize, dev_major, dev_minor); + + if (bufsize < 8) + return 0; + + r = snprintf(buf, bufsize, "%03u:%03u", dev_major, dev_minor); + if (r < 0 || r > bufsize - 1) + return 0; + + return 1; +} + int dm_task_get_info(struct dm_task *dmt, struct dm_info *info) { if (_dm_version == 1) @@ -512,6 +632,9 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info) info->suspended = dmt->dmi.v4->flags & DM_SUSPEND_FLAG ? 1 : 0; info->read_only = dmt->dmi.v4->flags & DM_READONLY_FLAG ? 1 : 0; + info->live_table = dmt->dmi.v4->flags & DM_ACTIVE_PRESENT_FLAG ? 1 : 0; + info->inactive_table = dmt->dmi.v4->flags & DM_INACTIVE_PRESENT_FLAG ? + 1 : 0; info->target_count = dmt->dmi.v4->target_count; info->open_count = dmt->dmi.v4->open_count; info->event_nr = dmt->dmi.v4->event_nr; @@ -521,6 +644,14 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info) return 1; } +const char *dm_task_get_name(struct dm_task *dmt) +{ + if (_dm_version == 1) + return _dm_task_get_name_v1(dmt); + + return (dmt->dmi.v4->name); +} + const char *dm_task_get_uuid(struct dm_task *dmt) { if (_dm_version == 1) @@ -538,6 +669,15 @@ struct dm_deps *dm_task_get_deps(struct dm_task *dmt) dmt->dmi.v4->data_start); } +struct dm_names *dm_task_get_names(struct dm_task *dmt) +{ + if (_dm_version == 1) + return _dm_task_get_names_v1(dmt); + + return (struct dm_names *) (((void *) dmt->dmi.v4) + + dmt->dmi.v4->data_start); +} + int dm_task_set_ro(struct dm_task *dmt) { dmt->read_only = 1; @@ -719,30 +859,78 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt) return NULL; } -int dm_task_run(struct dm_task *dmt) +static int _create_and_load_v4(struct dm_task *dmt) { - int fd = -1; - struct dm_ioctl *dmi; - unsigned int command; - char control[PATH_MAX]; + struct dm_task *task; + int r; - if (_dm_version == 1) - return _dm_task_run_v1(dmt); - - dmi = _flatten(dmt); - if (!dmi) { - log_error("Couldn't create ioctl argument"); + /* Use new task struct to create the device */ + if (!(task = dm_task_create(DM_DEVICE_CREATE))) { + log_error("Failed to create device-mapper task struct"); return 0; } - snprintf(control, sizeof(control), "%s/control", dm_dir()); - - if ((fd = open(control, O_RDWR)) < 0) { - log_error("%s: open failed: %s", control, strerror(errno)); - log_error("Is device-mapper driver missing from kernel?"); - goto bad; + /* Copy across relevant fields */ + if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) { + dm_task_destroy(task); + return 0; } + if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid)) { + dm_task_destroy(task); + return 0; + } + + task->major = dmt->major; + task->minor = dmt->minor; + + r = dm_task_run(task); + dm_task_destroy(task); + if (!r) + return r; + + /* Next load the table */ + if (!(task = dm_task_create(DM_DEVICE_RELOAD))) { + log_error("Failed to create device-mapper task struct"); + return 0; + } + + /* Copy across relevant fields */ + if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) { + dm_task_destroy(task); + return 0; + } + + task->read_only = dmt->read_only; + task->head = dmt->head; + task->tail = dmt->tail; + + r = dm_task_run(task); + + task->head = NULL; + task->tail = NULL; + dm_task_destroy(task); + if (!r) + return r; + + /* Use the original structure last so the info will be correct */ + dmt->type = DM_DEVICE_RESUME; + dmt->uuid = NULL; + free(dmt->uuid); + + r = dm_task_run(dmt); + + return r; +} + +int dm_task_run(struct dm_task *dmt) +{ + struct dm_ioctl *dmi; + unsigned int command; + + if (_dm_version == 1) + return _dm_task_run_v1(dmt); + if ((unsigned) dmt->type >= (sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) { log_error("Internal error: unknown device-mapper task %d", @@ -752,13 +940,26 @@ int dm_task_run(struct dm_task *dmt) command = _cmd_data_v4[dmt->type].cmd; + /* Old-style creation had a table supplied */ + if (dmt->type == DM_DEVICE_CREATE && dmt->head) + return _create_and_load_v4(dmt); + + if (!_open_control()) + return 0; + + dmi = _flatten(dmt); + if (!dmi) { + log_error("Couldn't create ioctl argument"); + return 0; + } + if (dmt->type == DM_DEVICE_TABLE) dmi->flags |= DM_STATUS_TABLE_FLAG; dmi->flags |= DM_EXISTS_FLAG; /* FIXME */ log_debug("dm %s %s %s %s", _cmd_data_v4[dmt->type].name, dmi->name, dmi->uuid, dmt->newname ? dmt->newname : ""); - if (ioctl(fd, command, dmi) < 0) { + if (ioctl(_control_fd, command, dmi) < 0) { if (errno == ENXIO && dmt->type == DM_DEVICE_INFO) { dmi->flags &= ~DM_EXISTS_FLAG; /* FIXME */ goto ignore_error; @@ -795,12 +996,28 @@ int dm_task_run(struct dm_task *dmt) } dmt->dmi.v4 = dmi; - close(fd); return 1; bad: free(dmi); - if (fd >= 0) - close(fd); return 0; } + +void dm_lib_release(void) +{ + if (_control_fd != -1) { + close(_control_fd); + _control_fd = -1; + } + update_devs(); +} + +void dm_lib_exit(void) +{ + if (_control_fd != -1) { + close(_control_fd); + _control_fd = -1; + } + _version_ok = 1; + _version_checked = 0; +} diff --git a/libdm/ioctl/libdm-compat.h b/libdm/ioctl/libdm-compat.h index 551a9c958..9422f63bc 100644 --- a/libdm/ioctl/libdm-compat.h +++ b/libdm/ioctl/libdm-compat.h @@ -54,21 +54,55 @@ struct dm_target_deps_v1 { __kernel_dev_t dev[0]; /* out */ }; +enum { + /* Top level cmds */ + DM_VERSION_CMD_V1 = 0, + DM_REMOVE_ALL_CMD_V1, + + /* device level cmds */ + DM_DEV_CREATE_CMD_V1, + DM_DEV_REMOVE_CMD_V1, + DM_DEV_RELOAD_CMD_V1, + DM_DEV_RENAME_CMD_V1, + DM_DEV_SUSPEND_CMD_V1, + DM_DEV_DEPS_CMD_V1, + DM_DEV_STATUS_CMD_V1, + + /* target level cmds */ + DM_TARGET_STATUS_CMD_V1, + DM_TARGET_WAIT_CMD_V1, +}; + +#define DM_VERSION_V1 _IOWR(DM_IOCTL, DM_VERSION_CMD_V1, struct dm_ioctl) +#define DM_REMOVE_ALL_V1 _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD_V1, struct dm_ioctl) + +#define DM_DEV_CREATE_V1 _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD_V1, struct dm_ioctl) +#define DM_DEV_REMOVE_V1 _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD_V1, struct dm_ioctl) +#define DM_DEV_RELOAD_V1 _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD_V1, struct dm_ioctl) +#define DM_DEV_SUSPEND_V1 _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD_V1, struct dm_ioctl) +#define DM_DEV_RENAME_V1 _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD_V1, struct dm_ioctl) +#define DM_DEV_DEPS_V1 _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD_V1, struct dm_ioctl) +#define DM_DEV_STATUS_V1 _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD_V1, struct dm_ioctl) + +#define DM_TARGET_STATUS_V1 _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD_V1, struct dm_ioctl) +#define DM_TARGET_WAIT_V1 _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD_V1, struct dm_ioctl) + /* *INDENT-OFF* */ static struct cmd_data _cmd_data_v1[] = { - { "create", DM_DEV_CREATE, {1, 0, 0} }, - { "reload", DM_DEV_RELOAD, {1, 0, 0} }, - { "remove", DM_DEV_REMOVE, {1, 0, 0} }, - { "remove_all", DM_REMOVE_ALL, {1, 0, 0} }, - { "suspend", DM_DEV_SUSPEND, {1, 0, 0} }, - { "resume", DM_DEV_SUSPEND, {1, 0, 0} }, - { "info", DM_DEV_STATUS, {1, 0, 0} }, - { "deps", DM_DEV_DEPS, {1, 0, 0} }, - { "rename", DM_DEV_RENAME, {1, 0, 0} }, - { "version", DM_VERSION, {1, 0, 0} }, - { "status", DM_TARGET_STATUS, {1, 0, 0} }, - { "table", DM_TARGET_STATUS, {1, 0, 0} }, - { "waitevent", DM_TARGET_WAIT, {1, 0, 0} }, + { "create", DM_DEV_CREATE_V1, {1, 0, 0} }, + { "reload", DM_DEV_RELOAD_V1, {1, 0, 0} }, + { "remove", DM_DEV_REMOVE_V1, {1, 0, 0} }, + { "remove_all", DM_REMOVE_ALL_V1, {1, 0, 0} }, + { "suspend", DM_DEV_SUSPEND_V1, {1, 0, 0} }, + { "resume", DM_DEV_SUSPEND_V1, {1, 0, 0} }, + { "info", DM_DEV_STATUS_V1, {1, 0, 0} }, + { "deps", DM_DEV_DEPS_V1, {1, 0, 0} }, + { "rename", DM_DEV_RENAME_V1, {1, 0, 0} }, + { "version", DM_VERSION_V1, {1, 0, 0} }, + { "status", DM_TARGET_STATUS_V1, {1, 0, 0} }, + { "table", DM_TARGET_STATUS_V1, {1, 0, 0} }, + { "waitevent", DM_TARGET_WAIT_V1, {1, 0, 0} }, + { "names", 0, {4, 0, 0} } }; /* *INDENT-ON* */ diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h index a9148d490..7a248e2ed 100644 --- a/libdm/libdevmapper.h +++ b/libdm/libdevmapper.h @@ -48,7 +48,11 @@ enum { DM_DEVICE_STATUS, DM_DEVICE_TABLE, - DM_DEVICE_WAITEVENT + DM_DEVICE_WAITEVENT, + + DM_DEVICE_LIST, + + DM_DEVICE_CLEAR }; struct dm_task; @@ -65,6 +69,8 @@ int dm_task_set_uuid(struct dm_task *dmt, const char *uuid); struct dm_info { int exists; int suspended; + int live_table; + int inactive_table; int32_t open_count; uint32_t event_nr; uint32_t major; @@ -80,12 +86,20 @@ struct dm_deps { uint64_t device[0]; }; +struct dm_names { + uint64_t dev; + uint32_t next; /* Offset to next struct from start of this struct */ + char name[0]; +}; + int dm_get_library_version(char *version, size_t size); int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size); int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi); +const char *dm_task_get_name(struct dm_task *dmt); const char *dm_task_get_uuid(struct dm_task *dmt); struct dm_deps *dm_task_get_deps(struct dm_task *dmt); +struct dm_names *dm_task_get_names(struct dm_task *dmt); int dm_task_set_ro(struct dm_task *dmt); int dm_task_set_newname(struct dm_task *dmt, const char *newname); @@ -100,6 +114,11 @@ int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size, const char *ttype, const char *params); +/* + * Format major/minor numbers correctly for input to driver + */ +int dm_format_dev(char *buf, int bufsize, uint32_t dev_major, uint32_t dev_minor); + /* Use this to retrive target information returned from a STATUS call */ void *dm_get_next_target(struct dm_task *dmt, void *next, uint64_t *start, uint64_t *length, @@ -116,4 +135,8 @@ int dm_task_run(struct dm_task *dmt); int dm_set_dev_dir(const char *dir); const char *dm_dir(void); +/* Release library resources */ +void dm_lib_release(void); +void dm_lib_exit(void); + #endif /* LIB_DEVICE_MAPPER_H */ diff --git a/libdm/libdm-common.c b/libdm/libdm-common.c index 5b39c0e48..739d721ac 100644 --- a/libdm/libdm-common.c +++ b/libdm/libdm-common.c @@ -6,6 +6,7 @@ #include "libdm-targets.h" #include "libdm-common.h" +#include "list.h" #include #include @@ -183,7 +184,7 @@ int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size, return 1; } -int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor) +static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor) { char path[PATH_MAX]; struct stat info; @@ -216,7 +217,7 @@ int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor) return 1; } -int rename_dev_node(const char *old_name, const char *new_name) +static int _rename_dev_node(const char *old_name, const char *new_name) { char oldpath[PATH_MAX]; char newpath[PATH_MAX]; @@ -252,7 +253,7 @@ int rename_dev_node(const char *old_name, const char *new_name) return 1; } -int rm_dev_node(const char *dev_name) +static int _rm_dev_node(const char *dev_name) { char path[PATH_MAX]; struct stat info; @@ -270,6 +271,105 @@ int rm_dev_node(const char *dev_name) return 1; } +typedef enum { + NODE_ADD, + NODE_DEL, + NODE_RENAME +} node_op_t; + +static int _do_node_op(node_op_t type, const char *dev_name, uint32_t major, + uint32_t minor, const char *old_name) +{ + switch (type) { + case NODE_ADD: + return _add_dev_node(dev_name, major, minor); + case NODE_DEL: + return _rm_dev_node(dev_name); + case NODE_RENAME: + return _rename_dev_node(old_name, dev_name); + } + + return 1; +} + +static LIST_INIT(_node_ops); + +struct node_op_parms { + struct list list; + node_op_t type; + char *dev_name; + uint32_t major; + uint32_t minor; + char *old_name; + char names[0]; +}; + +static void _store_str(char **pos, char **ptr, const char *str) +{ + strcpy(*pos, str); + *ptr = *pos; + *pos += strlen(*ptr) + 1; +} + +static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major, + uint32_t minor, const char *old_name) +{ + struct node_op_parms *nop; + size_t len = strlen(dev_name) + strlen(old_name) + 2; + char *pos; + + if (!(nop = malloc(sizeof(*nop) + len))) { + log_error("Insufficient memory to stack mknod operation"); + return 0; + } + + pos = nop->names; + nop->type = type; + nop->major = major; + nop->minor = minor; + + _store_str(&pos, &nop->dev_name, dev_name); + _store_str(&pos, &nop->old_name, old_name); + + list_add(&_node_ops, &nop->list); + + return 1; +} + +static void _pop_node_ops(void) +{ + struct list *noph, *nopht; + struct node_op_parms *nop; + + list_iterate_safe(noph, nopht, &_node_ops) { + nop = list_item(noph, struct node_op_parms); + _do_node_op(nop->type, nop->dev_name, nop->major, nop->minor, + nop->old_name); + list_del(&nop->list); + free(nop); + } +} + +int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor) +{ + return _stack_node_op(NODE_ADD, dev_name, major, minor, ""); +} + +int rename_dev_node(const char *old_name, const char *new_name) +{ + return _stack_node_op(NODE_RENAME, new_name, 0, 0, old_name); +} + +int rm_dev_node(const char *dev_name) +{ + return _stack_node_op(NODE_DEL, dev_name, 0, 0, ""); +} + +void update_devs(void) +{ + _pop_node_ops(); +} + int dm_set_dev_dir(const char *dir) { snprintf(_dm_dir, sizeof(_dm_dir), "%s%s", dir, DM_DIR); diff --git a/libdm/libdm-common.h.in b/libdm/libdm-common.h.in index 84eedd39b..2eabe5ebb 100644 --- a/libdm/libdm-common.h.in +++ b/libdm/libdm-common.h.in @@ -31,6 +31,7 @@ struct target *create_target(uint64_t start, int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major); int rm_dev_node(const char *dev_name); int rename_dev_node(const char *old_name, const char *new_name); +void update_devs(void); #define DM_LIB_VERSION @DM_LIB_VERSION@ diff --git a/tools/dmsetup.c b/tools/dmsetup.c index 06515bf4d..79ad850d5 100644 --- a/tools/dmsetup.c +++ b/tools/dmsetup.c @@ -84,6 +84,47 @@ static int _parse_file(struct dm_task *dmt, const char *file) return r; } +static void _display_info(struct dm_task *dmt) +{ + struct dm_info info; + const char *uuid; + + if (!dm_task_get_info(dmt, &info)) + return; + + if (!info.exists) { + printf("Device does not exist.\n"); + return; + } + + printf("Name: %s\n", dm_task_get_name(dmt)); + + printf("State: %s%s\n", + info.suspended ? "SUSPENDED" : "ACTIVE", + info.read_only ? " (READ-ONLY)" : ""); + + if (!info.live_table && !info.inactive_table) + printf("Tables present: None\n"); + else + printf("Tables present: %s%s%s\n", + info.live_table ? "LIVE" : "", + info.live_table && info.inactive_table ? " & " : "", + info.inactive_table ? "INACTIVE" : ""); + + if (info.open_count != -1) + printf("Open count: %d\n", info.open_count); + + printf("Event number: %" PRIu32 "\n", info.event_nr); + printf("Major, minor: %d, %d\n", info.major, info.minor); + + if (info.target_count != -1) + printf("Number of targets: %d\n", info.target_count); + + if ((uuid = dm_task_get_uuid(dmt)) && *uuid) + printf("UUID: %s\n", uuid); + +} + static int _load(int task, const char *name, const char *file, const char *uuid) { int r = 0; @@ -98,7 +139,7 @@ static int _load(int task, const char *name, const char *file, const char *uuid) if (uuid && !dm_task_set_uuid(dmt, uuid)) goto out; - if (!_parse_file(dmt, file)) + if (file && !_parse_file(dmt, file)) goto out; if (_switches[READ_ONLY] && !dm_task_set_ro(dmt)) @@ -115,6 +156,8 @@ static int _load(int task, const char *name, const char *file, const char *uuid) r = 1; + _display_info(dmt); + out: dm_task_destroy(dmt); @@ -123,7 +166,11 @@ static int _load(int task, const char *name, const char *file, const char *uuid) static int _create(int argc, char **argv) { - return _load(DM_DEVICE_CREATE, argv[1], argv[2], argv[3]); + if (argc == 1) + return _load(DM_DEVICE_CREATE, argv[1], NULL, NULL); + + return _load(DM_DEVICE_CREATE, argv[1], argv[2], + (argc == 3) ? argv[3] : NULL); } static int _reload(int argc, char **argv) @@ -185,7 +232,7 @@ static int _version(int argc, char **argv) return r; } -static int _simple(int task, const char *name) +static int _simple(int task, const char *name, int display) { int r = 0; @@ -200,6 +247,9 @@ static int _simple(int task, const char *name) r = dm_task_run(dmt); + if (r && display) + _display_info(dmt); + out: dm_task_destroy(dmt); return r; @@ -207,27 +257,32 @@ static int _simple(int task, const char *name) static int _remove_all(int argc, char **argv) { - return _simple(DM_DEVICE_REMOVE_ALL, ""); + return _simple(DM_DEVICE_REMOVE_ALL, "", 0); } static int _remove(int argc, char **argv) { - return _simple(DM_DEVICE_REMOVE, argv[1]); + return _simple(DM_DEVICE_REMOVE, argv[1], 0); } static int _suspend(int argc, char **argv) { - return _simple(DM_DEVICE_SUSPEND, argv[1]); + return _simple(DM_DEVICE_SUSPEND, argv[1], 1); } static int _resume(int argc, char **argv) { - return _simple(DM_DEVICE_RESUME, argv[1]); + return _simple(DM_DEVICE_RESUME, argv[1], 1); +} + +static int _clear(int argc, char **argv) +{ + return _simple(DM_DEVICE_CLEAR, argv[1], 1); } static int _wait(int argc, char **argv) { - return _simple(DM_DEVICE_WAITEVENT, argv[1]); + return _simple(DM_DEVICE_WAITEVENT, argv[1], 2); } static int _status(int argc, char **argv) @@ -254,6 +309,11 @@ static int _status(int argc, char **argv) if (!dm_task_run(dmt)) goto out; + if (cmd == DM_DEVICE_STATUS) { + _display_info(dmt); + printf("\n"); + } + /* Fetch targets and print 'em */ do { next = dm_get_next_target(dmt, next, &start, &length, @@ -275,11 +335,9 @@ static int _status(int argc, char **argv) static int _info(int argc, char **argv) { int r = 0; - const char *uuid; /* remove */ struct dm_task *dmt; - struct dm_info info; if (!(dmt = dm_task_create(DM_DEVICE_INFO))) return 0; @@ -290,33 +348,7 @@ static int _info(int argc, char **argv) if (!dm_task_run(dmt)) goto out; - if (!dm_task_get_info(dmt, &info)) - goto out; - - if (!info.exists) { - printf("Device does not exist.\n"); - r = 1; - goto out; - } - - printf("Name: %s\n", argv[1]); - - printf("State: %s%s\n", - info.suspended ? "SUSPENDED" : "ACTIVE", - info.read_only ? " (READ-ONLY)" : ""); - - if (info.open_count != -1) - printf("Open count: %d\n", info.open_count); - - printf("Event number: %" PRIu32 "\n", info.event_nr); - printf("Major, minor: %d, %d\n", info.major, info.minor); - - if (info.target_count != -1) - printf("Number of targets: %d\n", info.target_count); - - if ((uuid = dm_task_get_uuid(dmt)) && *uuid) - printf("UUID: %s\n", uuid); - + _display_info(dmt); r = 1; out: @@ -355,6 +387,8 @@ static int _deps(int argc, char **argv) goto out; } + _display_info(dmt); + printf("%d dependencies\t:", deps->count); for (i = 0; i < deps->count; i++) @@ -370,6 +404,41 @@ static int _deps(int argc, char **argv) return r; } +static int _ls(int argc, char **argv) +{ + int r = 0; + struct dm_names *names; + unsigned next = 0; + + struct dm_task *dmt; + + if (!(dmt = dm_task_create(DM_DEVICE_LIST))) + return 0; + + if (!dm_task_run(dmt)) + goto out; + + if (!(names = dm_task_get_names(dmt))) + goto out; + + r = 1; + if (!names->dev) { + printf("No devices found\n"); + goto out; + } + + do { + names = (void *) names + next; + printf("%s\t(%d, %d)\n", names->name, + (int) MAJOR(names->dev), (int) MINOR(names->dev)); + next = names->next; + } while (next); + + out: + dm_task_destroy(dmt); + return r; +} + /* * dispatch table */ @@ -384,15 +453,18 @@ struct command { }; static struct command _commands[] = { - {"create", " []", 2, 3, _create}, + {"create", " []", 1, 3, _create}, {"remove", "", 1, 1, _remove}, {"remove_all", "", 0, 0, _remove_all}, {"suspend", "", 1, 1, _suspend}, {"resume", "", 1, 1, _resume}, + {"load", " ", 2, 2, _reload}, + {"clear", "", 1, 1, _clear}, {"reload", " ", 2, 2, _reload}, + {"rename", " ", 2, 2, _rename}, + {"ls", "", 0, 0, _ls}, {"info", "", 1, 1, _info}, {"deps", "", 1, 1, _deps}, - {"rename", " ", 2, 2, _rename}, {"status", "", 1, 1, _status}, {"table", "", 1, 1, _status}, {"wait", "", 1, 1, _wait}, @@ -494,5 +566,8 @@ int main(int argc, char **argv) exit(1); } + dm_lib_release(); + dm_lib_exit(); + return 0; }