mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-12 08:13:48 +03:00
Support for v4 interface
This commit is contained in:
parent
46a68b7dd6
commit
d71bfabe39
@ -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:
|
||||
*;
|
||||
};
|
||||
|
@ -13,7 +13,10 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
/*
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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* */
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "libdm-targets.h"
|
||||
#include "libdm-common.h"
|
||||
#include "list.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -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);
|
||||
|
@ -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@
|
||||
|
||||
|
153
tools/dmsetup.c
153
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 <dev_name> */
|
||||
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", "<dev_name> <table_file> [<uuid>]", 2, 3, _create},
|
||||
{"create", "<dev_name> <table_file> [<uuid>]", 1, 3, _create},
|
||||
{"remove", "<dev_name>", 1, 1, _remove},
|
||||
{"remove_all", "", 0, 0, _remove_all},
|
||||
{"suspend", "<dev_name>", 1, 1, _suspend},
|
||||
{"resume", "<dev_name>", 1, 1, _resume},
|
||||
{"load", "<dev_name> <table_file>", 2, 2, _reload},
|
||||
{"clear", "<dev_name>", 1, 1, _clear},
|
||||
{"reload", "<dev_name> <table_file>", 2, 2, _reload},
|
||||
{"rename", "<dev_name> <new_name>", 2, 2, _rename},
|
||||
{"ls", "", 0, 0, _ls},
|
||||
{"info", "<dev_name>", 1, 1, _info},
|
||||
{"deps", "<dev_name>", 1, 1, _deps},
|
||||
{"rename", "<dev_name> <new_name>", 2, 2, _rename},
|
||||
{"status", "<dev_name>", 1, 1, _status},
|
||||
{"table", "<dev_name>", 1, 1, _status},
|
||||
{"wait", "<dev_name>", 1, 1, _wait},
|
||||
@ -494,5 +566,8 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dm_lib_release();
|
||||
dm_lib_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user