mirror of
git://sourceware.org/git/lvm2.git
synced 2026-01-02 20:32:47 +03:00
Compare commits
24 Commits
dm_v1_02_1
...
dm_v1_02_1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5bdb0e0b5 | ||
|
|
1106b7775a | ||
|
|
ae2852156d | ||
|
|
44c6c36c43 | ||
|
|
a81926503d | ||
|
|
af13ccddda | ||
|
|
392e1bc2e8 | ||
|
|
9268d92c70 | ||
|
|
bb3366c07d | ||
|
|
d24d563ebc | ||
|
|
954bd9257b | ||
|
|
5d51a56c02 | ||
|
|
f48648552e | ||
|
|
edb9c3cc9f | ||
|
|
01dc83b936 | ||
|
|
3a8dff3a62 | ||
|
|
13b234ccba | ||
|
|
e451e93664 | ||
|
|
b4f9531475 | ||
|
|
3184ff75c4 | ||
|
|
43243f4d30 | ||
|
|
c975a100b1 | ||
|
|
02bf389425 | ||
|
|
bcb9a3dd04 |
10
WHATS_NEW
10
WHATS_NEW
@@ -1,3 +1,13 @@
|
||||
Version 2.02.19 - 17th January 2007
|
||||
===================================
|
||||
Fix a segfault if an empty config file section encountered.
|
||||
Move basic reporting functions into libdevmapper.
|
||||
Fix partition table processing after sparc changes (2.02.16).
|
||||
Fix cmdline PE range processing segfault (2.02.13).
|
||||
Some libdevmapper-event interface changes.
|
||||
Report dmeventd mirror monitoring status.
|
||||
Fix dmeventd mirror status line processing.
|
||||
|
||||
Version 2.02.18 - 11th January 2007
|
||||
===================================
|
||||
Revised libdevmapper-event interface for dmeventd.
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
Version 1.02.15 - 17th January 2007
|
||||
===================================
|
||||
Add basic reporting functions to libdevmapper.
|
||||
Fix a malloc error path in dmsetup message.
|
||||
More libdevmapper-event interface changes and fixes.
|
||||
Rename dm_saprintf() to dm_asprintf().
|
||||
Report error if NULL pointer is supplied to dm_strdup_aux().
|
||||
Reinstate dm_event_get_registered_device.
|
||||
|
||||
Version 1.02.14 - 11th January 2007
|
||||
===================================
|
||||
Add dm_saprintf().
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
dm_event_handler_create
|
||||
dm_event_handler_destroy
|
||||
dm_event_handler_set_dso
|
||||
dm_event_handler_set_name
|
||||
dm_event_handler_set_dev_name
|
||||
dm_event_handler_set_uuid
|
||||
dm_event_handler_set_major
|
||||
dm_event_handler_set_minor
|
||||
dm_event_handler_set_events
|
||||
dm_event_handler_set_event_mask
|
||||
dm_event_handler_get_dso
|
||||
dm_event_handler_get_name
|
||||
dm_event_handler_get_devname
|
||||
dm_event_handler_get_uuid
|
||||
dm_event_handler_get_major
|
||||
dm_event_handler_get_minor
|
||||
dm_event_handler_get_events
|
||||
dm_event_register
|
||||
dm_event_unregister
|
||||
dm_event_handler_get_event_mask
|
||||
dm_event_register_handler
|
||||
dm_event_unregister_handler
|
||||
dm_event_get_registered_device
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,109 +31,143 @@
|
||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||
|
||||
struct dm_event_handler {
|
||||
const char *dso;
|
||||
const char *device;
|
||||
const char *uuid;
|
||||
char *dso;
|
||||
|
||||
char *dev_name;
|
||||
|
||||
char *uuid;
|
||||
int major;
|
||||
int minor;
|
||||
enum dm_event_type events;
|
||||
|
||||
enum dm_event_mask mask;
|
||||
};
|
||||
|
||||
static void dm_event_handler_clear_device(struct dm_event_handler *h)
|
||||
static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
|
||||
{
|
||||
h->device = h->uuid = NULL;
|
||||
h->major = h->minor = 0;
|
||||
if (dmevh->dev_name)
|
||||
dm_free(dmevh->dev_name);
|
||||
if (dmevh->uuid)
|
||||
dm_free(dmevh->uuid);
|
||||
dmevh->dev_name = dmevh->uuid = NULL;
|
||||
dmevh->major = dmevh->minor = 0;
|
||||
}
|
||||
|
||||
struct dm_event_handler *dm_event_handler_create(void)
|
||||
{
|
||||
struct dm_event_handler *ret = 0;
|
||||
struct dm_event_handler *dmevh = NULL;
|
||||
|
||||
if (!(ret = dm_malloc(sizeof(*ret))))
|
||||
if (!(dmevh = dm_malloc(sizeof(*dmevh))))
|
||||
return NULL;
|
||||
|
||||
ret->dso = ret->device = ret->uuid = NULL;
|
||||
ret->major = ret->minor = 0;
|
||||
ret->events = 0;
|
||||
dmevh->dso = dmevh->dev_name = dmevh->uuid = NULL;
|
||||
dmevh->major = dmevh->minor = 0;
|
||||
dmevh->mask = 0;
|
||||
|
||||
return ret;
|
||||
return dmevh;
|
||||
}
|
||||
|
||||
void dm_event_handler_destroy(struct dm_event_handler *h)
|
||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh)
|
||||
{
|
||||
dm_free(h);
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
if (dmevh->dso)
|
||||
dm_free(dmevh->dso);
|
||||
dm_free(dmevh);
|
||||
}
|
||||
|
||||
void dm_event_handler_set_dso(struct dm_event_handler *h, const char *path)
|
||||
int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
|
||||
{
|
||||
h->dso = path;
|
||||
if (!path) /* noop */
|
||||
return 0;
|
||||
if (dmevh->dso)
|
||||
dm_free(dmevh->dso);
|
||||
|
||||
dmevh->dso = dm_strdup(path);
|
||||
if (!dmevh->dso)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_event_handler_set_name(struct dm_event_handler *h, const char *name)
|
||||
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name)
|
||||
{
|
||||
dm_event_handler_clear_device(h);
|
||||
h->device = name;
|
||||
if (!dev_name)
|
||||
return 0;
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
dmevh->dev_name = dm_strdup(dev_name);
|
||||
if (!dmevh->dev_name)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_event_handler_set_uuid(struct dm_event_handler *h, const char *uuid)
|
||||
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
|
||||
{
|
||||
dm_event_handler_clear_device(h);
|
||||
h->uuid = uuid;
|
||||
if (!uuid)
|
||||
return 0;
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
dmevh->uuid = dm_strdup(uuid);
|
||||
if (!dmevh->dev_name)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_event_handler_set_major(struct dm_event_handler *h, int major)
|
||||
void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major)
|
||||
{
|
||||
int minor = h->minor;
|
||||
int minor = dmevh->minor;
|
||||
|
||||
dm_event_handler_clear_device(h);
|
||||
h->major = major;
|
||||
h->minor = minor;
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
dmevh->major = major;
|
||||
dmevh->minor = minor;
|
||||
}
|
||||
|
||||
void dm_event_handler_set_minor(struct dm_event_handler *h, int minor)
|
||||
void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor)
|
||||
{
|
||||
int major = h->major;
|
||||
int major = dmevh->major;
|
||||
|
||||
dm_event_handler_clear_device(h);
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
h->major = major;
|
||||
h->minor = minor;
|
||||
dmevh->major = major;
|
||||
dmevh->minor = minor;
|
||||
}
|
||||
|
||||
void dm_event_handler_set_events(struct dm_event_handler *h,
|
||||
enum dm_event_type event)
|
||||
void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
|
||||
enum dm_event_mask evmask)
|
||||
{
|
||||
h->events = event;
|
||||
dmevh->mask = evmask;
|
||||
}
|
||||
|
||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *h)
|
||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->dso;
|
||||
return dmevh->dso;
|
||||
}
|
||||
|
||||
const char *dm_event_handler_get_name(const struct dm_event_handler *h)
|
||||
const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->device;
|
||||
return dmevh->dev_name;
|
||||
}
|
||||
|
||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *h)
|
||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->uuid;
|
||||
return dmevh->uuid;
|
||||
}
|
||||
|
||||
int dm_event_handler_get_major(const struct dm_event_handler *h)
|
||||
int dm_event_handler_get_major(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->major;
|
||||
return dmevh->major;
|
||||
}
|
||||
|
||||
int dm_event_handler_get_minor(const struct dm_event_handler *h)
|
||||
int dm_event_handler_get_minor(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->minor;
|
||||
return dmevh->minor;
|
||||
}
|
||||
|
||||
enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h)
|
||||
enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->events;
|
||||
return dmevh->mask;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -145,8 +179,8 @@ enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h)
|
||||
*
|
||||
* Returns: 0 on failure, 1 on success
|
||||
*/
|
||||
static int daemon_read(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg)
|
||||
static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg)
|
||||
{
|
||||
unsigned bytes = 0;
|
||||
int ret, i;
|
||||
@@ -205,8 +239,8 @@ static int daemon_read(struct dm_event_fifos *fifos,
|
||||
}
|
||||
|
||||
/* Write message to daemon. */
|
||||
static int daemon_write(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg)
|
||||
static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg)
|
||||
{
|
||||
unsigned bytes = 0;
|
||||
int ret = 0;
|
||||
@@ -248,14 +282,15 @@ static int daemon_write(struct dm_event_fifos *fifos,
|
||||
return bytes == size;
|
||||
}
|
||||
|
||||
static int daemon_talk(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg, int cmd,
|
||||
const char *dso_name, const char *device,
|
||||
enum dm_event_type events, uint32_t timeout)
|
||||
static int _daemon_talk(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg, int cmd,
|
||||
const char *dso_name, const char *dev_name,
|
||||
enum dm_event_mask evmask, uint32_t timeout)
|
||||
{
|
||||
const char *dso = dso_name ? dso_name : "";
|
||||
const char *dev = device ? device : "";
|
||||
const char *dev = dev_name ? dev_name : "";
|
||||
const char *fmt = "%s %s %u %" PRIu32;
|
||||
int msg_size;
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
|
||||
/*
|
||||
@@ -263,18 +298,23 @@ static int daemon_talk(struct dm_event_fifos *fifos,
|
||||
* into ASCII message string.
|
||||
*/
|
||||
msg->cmd = cmd;
|
||||
msg->size = dm_saprintf(&(msg->data), fmt, dso, dev, events, timeout);
|
||||
if ((msg_size = dm_asprintf(&(msg->data), fmt, dso, dev, evmask,
|
||||
timeout)) < 0) {
|
||||
log_error("_daemon_talk: message allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
msg->size = msg_size;
|
||||
|
||||
/*
|
||||
* Write command and message to and
|
||||
* read status return code from daemon.
|
||||
*/
|
||||
if (!daemon_write(fifos, msg)) {
|
||||
if (!_daemon_write(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!daemon_read(fifos, msg)) {
|
||||
if (!_daemon_read(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
@@ -294,7 +334,7 @@ static int daemon_talk(struct dm_event_fifos *fifos,
|
||||
*
|
||||
* Returns: 1 on success, 0 otherwise
|
||||
*/
|
||||
static int start_daemon(struct dm_event_fifos *fifos)
|
||||
static int _start_daemon(struct dm_event_fifos *fifos)
|
||||
{
|
||||
int pid, ret = 0;
|
||||
int status;
|
||||
@@ -332,8 +372,7 @@ static int start_daemon(struct dm_event_fifos *fifos)
|
||||
log_error("Unable to fork.");
|
||||
|
||||
else if (!pid) {
|
||||
/* FIXME configure path (cf. lvm2 modprobe) */
|
||||
execvp("dmeventd", NULL);
|
||||
execvp(DMEVENTD_PATH, NULL);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
if (waitpid(pid, &status, 0) < 0)
|
||||
@@ -349,7 +388,7 @@ static int start_daemon(struct dm_event_fifos *fifos)
|
||||
}
|
||||
|
||||
/* Initialize client. */
|
||||
static int init_client(struct dm_event_fifos *fifos)
|
||||
static int _init_client(struct dm_event_fifos *fifos)
|
||||
{
|
||||
/* FIXME? Is fifo the most suitable method? Why not share
|
||||
comms/daemon code with something else e.g. multipath? */
|
||||
@@ -359,7 +398,7 @@ static int init_client(struct dm_event_fifos *fifos)
|
||||
fifos->client_path = DM_EVENT_FIFO_CLIENT;
|
||||
fifos->server_path = DM_EVENT_FIFO_SERVER;
|
||||
|
||||
if (!start_daemon(fifos)) {
|
||||
if (!_start_daemon(fifos)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -391,7 +430,7 @@ static int init_client(struct dm_event_fifos *fifos)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dtr_client(struct dm_event_fifos *fifos)
|
||||
static void _dtr_client(struct dm_event_fifos *fifos)
|
||||
{
|
||||
if (flock(fifos->server, LOCK_UN))
|
||||
log_error("flock unlock %s", fifos->server_path);
|
||||
@@ -400,76 +439,92 @@ static void dtr_client(struct dm_event_fifos *fifos)
|
||||
close(fifos->server);
|
||||
}
|
||||
|
||||
/* Get uuid of a device, if it exists (otherwise NULL). */
|
||||
static struct dm_task *get_device_info(const struct dm_event_handler *h)
|
||||
/* Get uuid of a device */
|
||||
static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
struct dm_task *dmt = dm_task_create(DM_DEVICE_INFO);
|
||||
struct dm_task *ret;
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
|
||||
if (!dmt)
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
|
||||
log_error("_get_device_info: dm_task creation for info failed");
|
||||
return NULL;
|
||||
|
||||
if (h->uuid)
|
||||
dm_task_set_uuid(dmt, h->uuid);
|
||||
else if (h->device)
|
||||
dm_task_set_name(dmt, h->device);
|
||||
else if (h->major && h->minor) {
|
||||
dm_task_set_major(dmt, h->major);
|
||||
dm_task_set_minor(dmt, h->minor);
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt))
|
||||
ret = NULL;
|
||||
else
|
||||
ret = dmt;
|
||||
if (dmevh->uuid)
|
||||
dm_task_set_uuid(dmt, dmevh->uuid);
|
||||
else if (dmevh->dev_name)
|
||||
dm_task_set_name(dmt, dmevh->dev_name);
|
||||
else if (dmevh->major && dmevh->minor) {
|
||||
dm_task_set_major(dmt, dmevh->major);
|
||||
dm_task_set_minor(dmt, dmevh->minor);
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* FIXME Add name or uuid or devno to messages */
|
||||
if (!dm_task_run(dmt)) {
|
||||
log_error("_get_device_info: dm_task_run() failed");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (!dm_task_get_info(dmt, &info)) {
|
||||
log_error("_get_device_info: failed to get info for device");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (!info.exists) {
|
||||
log_error("_get_device_info: device not found");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return dmt;
|
||||
|
||||
failed:
|
||||
dm_task_destroy(dmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Handle the event (de)registration call and return negative error codes. */
|
||||
static int do_event(int cmd, struct dm_event_daemon_message *msg,
|
||||
const char *dso_name, const char *device,
|
||||
enum dm_event_type events, uint32_t timeout)
|
||||
static int _do_event(int cmd, struct dm_event_daemon_message *msg,
|
||||
const char *dso_name, const char *dev_name,
|
||||
enum dm_event_mask evmask, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_fifos fifos;
|
||||
|
||||
if (!init_client(&fifos)) {
|
||||
if (!_init_client(&fifos)) {
|
||||
stack;
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
|
||||
ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
|
||||
|
||||
/* what is the opposite of init? */
|
||||
dtr_client(&fifos);
|
||||
_dtr_client(&fifos);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* External library interface. */
|
||||
int dm_event_register(const struct dm_event_handler *h)
|
||||
int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
int ret, err;
|
||||
int ret = 1, err;
|
||||
const char *uuid;
|
||||
struct dm_task *dmt;
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!(dmt = get_device_info(h))) {
|
||||
log_error("%s: device not found", h->device);
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uuid = dm_task_get_uuid(dmt);
|
||||
|
||||
if ((err = do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
|
||||
h->dso, uuid, h->events, 0)) < 0) {
|
||||
if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
|
||||
dmevh->dso, uuid, dmevh->mask, 0)) < 0) {
|
||||
log_error("%s: event registration failed: %s",
|
||||
dm_task_get_name(dmt),
|
||||
msg.data ? msg.data : strerror(-err));
|
||||
ret = 0;
|
||||
} else
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
@@ -479,28 +534,27 @@ int dm_event_register(const struct dm_event_handler *h)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dm_event_unregister(const struct dm_event_handler *h)
|
||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
int ret, err;
|
||||
int ret = 1, err;
|
||||
const char *uuid;
|
||||
struct dm_task *dmt;
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!(dmt = get_device_info(h))) {
|
||||
log_error("%s: device not found", dm_task_get_name(dmt));
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uuid = dm_task_get_uuid(dmt);
|
||||
|
||||
if ((err = do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
|
||||
h->dso, uuid, h->events, 0)) < 0) {
|
||||
if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
|
||||
dmevh->dso, uuid, dmevh->mask, 0)) < 0) {
|
||||
log_error("%s: event deregistration failed: %s",
|
||||
dm_task_get_name(dmt),
|
||||
msg.data ? msg.data : strerror(-err));
|
||||
ret = 0;
|
||||
} else
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
@@ -510,12 +564,9 @@ int dm_event_unregister(const struct dm_event_handler *h)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0 /* left out for now */
|
||||
|
||||
/* Fetch a string off src and duplicate it into *dest. */
|
||||
/* FIXME: move to seperate module to share with the daemon. */
|
||||
static const char delimiter = ' ';
|
||||
static char *fetch_string(char **src)
|
||||
/* FIXME: move to separate module to share with the daemon. */
|
||||
static char *_fetch_string(char **src, const int delimiter)
|
||||
{
|
||||
char *p, *ret;
|
||||
|
||||
@@ -532,13 +583,14 @@ static char *fetch_string(char **src)
|
||||
}
|
||||
|
||||
/* Parse a device message from the daemon. */
|
||||
static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
char **device, enum dm_event_type *events)
|
||||
static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
char **uuid, enum dm_event_mask *evmask)
|
||||
{
|
||||
char *p = msg->data;
|
||||
|
||||
if ((*dso_name = fetch_string(&p)) && (*device = fetch_string(&p))) {
|
||||
*events = atoi(p);
|
||||
if ((*dso_name = _fetch_string(&p, ' ')) &&
|
||||
(*uuid = _fetch_string(&p, ' '))) {
|
||||
*evmask = atoi(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -550,55 +602,95 @@ static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
* dm_event_get_registered_device
|
||||
* @dso_name
|
||||
* @device_path
|
||||
* @events
|
||||
* @mask
|
||||
* @next
|
||||
*
|
||||
* FIXME: This function sucks.
|
||||
*
|
||||
* Returns: 1 if device found, 0 otherwise (even on error)
|
||||
* Returns: 0 if handler found, error (-ENOMEM, -ENOENT) otherwise
|
||||
*/
|
||||
int dm_event_get_registered_device(char **dso_name, char **device_path,
|
||||
enum dm_event_type *events, int next)
|
||||
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
{
|
||||
int ret;
|
||||
char *dso_name_arg = NULL, *device_path_arg = NULL;
|
||||
const char *uuid = NULL;
|
||||
char *reply_dso = NULL, *reply_uuid = NULL;
|
||||
enum dm_event_mask reply_mask;
|
||||
struct dm_task *dmt;
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!(ret = do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
&msg, *dso_name, *device_path, *events, 0))) {
|
||||
ret = !parse_message(&msg, &dso_name_arg, &device_path_arg,
|
||||
events);
|
||||
} else /* FIXME: Make sure this is ENOENT */
|
||||
ret = 0;
|
||||
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
|
||||
if (next) {
|
||||
if (*dso_name)
|
||||
dm_free(*dso_name);
|
||||
if (*device_path)
|
||||
dm_free(*device_path);
|
||||
*dso_name = dso_name_arg;
|
||||
*device_path = device_path_arg;
|
||||
} else {
|
||||
if (!(*dso_name))
|
||||
*dso_name = dso_name_arg;
|
||||
if (!(*device_path))
|
||||
*device_path = device_path_arg;
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uuid = dm_task_get_uuid(dmt);
|
||||
|
||||
if (!(ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
&msg, dmevh->dso, uuid, dmevh->mask, 0))) {
|
||||
/* FIXME this will probably horribly break if we get
|
||||
ill-formatted reply */
|
||||
ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask);
|
||||
} else {
|
||||
ret = -ENOENT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
if (msg.data) {
|
||||
dm_free(msg.data);
|
||||
msg.data = NULL;
|
||||
}
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
dmevh->uuid = dm_strdup(reply_uuid);
|
||||
if (!dmevh->uuid) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dm_event_handler_set_dso(dmevh, reply_dso);
|
||||
dm_event_handler_set_event_mask(dmevh, reply_mask);
|
||||
dmevh->dev_name = dm_strdup(dm_task_get_name(dmt));
|
||||
if (!dmevh->dev_name) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
struct dm_info info;
|
||||
if (!dm_task_get_info(dmt, &info)) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dmevh->major = info.major;
|
||||
dmevh->minor = info.minor;
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
dm_task_destroy(dmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0 /* left out for now */
|
||||
|
||||
int dm_event_set_timeout(const char *device_path, uint32_t timeout)
|
||||
{
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
return do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
|
||||
return _do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
|
||||
NULL, device_path, 0, timeout);
|
||||
}
|
||||
|
||||
@@ -609,7 +701,7 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
if (!(ret = do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
|
||||
if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
|
||||
0, 0)))
|
||||
*timeout = atoi(msg.data);
|
||||
if (msg.data)
|
||||
|
||||
@@ -23,8 +23,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Event type definitions. */
|
||||
enum dm_event_type {
|
||||
/*
|
||||
* Event library interface.
|
||||
*/
|
||||
|
||||
enum dm_event_mask {
|
||||
DM_EVENT_SETTINGS_MASK = 0x0000FF,
|
||||
DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
|
||||
DM_EVENT_MULTI = 0x000002, /* Report all of them. */
|
||||
@@ -33,7 +36,7 @@ enum dm_event_type {
|
||||
DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */
|
||||
DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */
|
||||
DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */
|
||||
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure off a host adaptor. */
|
||||
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */
|
||||
|
||||
DM_EVENT_STATUS_MASK = 0xFF0000,
|
||||
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
|
||||
@@ -44,50 +47,58 @@ enum dm_event_type {
|
||||
|
||||
#define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK
|
||||
|
||||
/* Prototypes for event lib interface. */
|
||||
|
||||
struct dm_event_handler;
|
||||
|
||||
/* Create and destroy dm_event_handler struct, which is passed to
|
||||
register/unregister functions below */
|
||||
struct dm_event_handler *dm_event_handler_create(void);
|
||||
void dm_event_handler_destroy(struct dm_event_handler *h);
|
||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh);
|
||||
|
||||
/* Set parameters of a handler:
|
||||
- dso - shared library path to handle the events
|
||||
(only one of the following three needs to be set)
|
||||
- name - device name or path
|
||||
- uuid - device uuid
|
||||
- major and minor - device major/minor numbers
|
||||
- events - a bitfield defining which events to handle (see
|
||||
enum dm_event_type above)
|
||||
*/
|
||||
void dm_event_handler_set_dso(struct dm_event_handler *h, const char *path);
|
||||
void dm_event_handler_set_name(struct dm_event_handler *h, const char *name);
|
||||
void dm_event_handler_set_uuid(struct dm_event_handler *h, const char *uuid);
|
||||
void dm_event_handler_set_major(struct dm_event_handler *h, int major);
|
||||
void dm_event_handler_set_minor(struct dm_event_handler *h, int minor);
|
||||
void dm_event_handler_set_events(struct dm_event_handler *h,
|
||||
enum dm_event_type event);
|
||||
/*
|
||||
* Path of shared library to handle events.
|
||||
*
|
||||
* All of dso, dev_name and uuid strings are duplicated, you do not
|
||||
* need to keep the pointers valid after the call succeeds. Thes may
|
||||
* return -ENOMEM though.
|
||||
*/
|
||||
int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path);
|
||||
|
||||
/* Get parameters of a handler, same as above */
|
||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *h);
|
||||
const char *dm_event_handler_get_name(const struct dm_event_handler *h);
|
||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *h);
|
||||
int dm_event_handler_get_major(const struct dm_event_handler *h);
|
||||
int dm_event_handler_get_minor(const struct dm_event_handler *h);
|
||||
enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h);
|
||||
/*
|
||||
* Identify the device to monitor by exactly one of dev_name, uuid or
|
||||
* device number. String arguments are duplicated, see above.
|
||||
*/
|
||||
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name);
|
||||
|
||||
/* Call out to dmeventd to register or unregister a handler. If
|
||||
dmeventd is not running, it is spawned first. */
|
||||
int dm_event_register(const struct dm_event_handler *h);
|
||||
int dm_event_unregister(const struct dm_event_handler *h);
|
||||
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid);
|
||||
|
||||
void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major);
|
||||
void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor);
|
||||
|
||||
/*
|
||||
* Specify mask for events to monitor.
|
||||
*/
|
||||
void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
|
||||
enum dm_event_mask evmask);
|
||||
|
||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh);
|
||||
const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh);
|
||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_major(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_minor(const struct dm_event_handler *dmevh);
|
||||
enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh);
|
||||
|
||||
/* FIXME Review interface (what about this next thing?) */
|
||||
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next);
|
||||
|
||||
/*
|
||||
* Initiate monitoring using dmeventd.
|
||||
*/
|
||||
int dm_event_register_handler(const struct dm_event_handler *dmevh);
|
||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
|
||||
|
||||
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
|
||||
detailed descriptions. */
|
||||
void process_event(struct dm_task *dmt, enum dm_event_type event);
|
||||
int register_device(const char *device, const char *uuid, int major, int minor);
|
||||
int unregister_device(const char *device, const char *uuid, int major,
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask evmask);
|
||||
int register_device(const char *dev_name, const char *uuid, int major, int minor);
|
||||
int unregister_device(const char *dev_name, const char *uuid, int major,
|
||||
int minor);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
@@ -62,8 +61,12 @@ static int _get_mirror_event(char *params)
|
||||
int log_argc, num_devs;
|
||||
|
||||
/*
|
||||
* Unused: 0 409600 mirror
|
||||
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
|
||||
* dm core parms: 0 409600 mirror
|
||||
* Mirror core parms: 2 253:4 253:5 400/400
|
||||
* New-style failure params: 1 AA
|
||||
* New-style log params: 3 cluster 253:3 A
|
||||
* or 3 disk 253:3 A
|
||||
* or 1 core
|
||||
*/
|
||||
|
||||
/* number of devices */
|
||||
@@ -74,9 +77,9 @@ static int _get_mirror_event(char *params)
|
||||
goto out_parse;
|
||||
p += strlen(p) + 1;
|
||||
|
||||
/* devices names + max log parameters */
|
||||
args = dm_malloc((num_devs + 8) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 8, 0, args) < num_devs + 8)
|
||||
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
|
||||
args = dm_malloc((num_devs + 7) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
|
||||
goto out_parse;
|
||||
|
||||
dev_status_str = args[2 + num_devs];
|
||||
@@ -161,7 +164,7 @@ static int _remove_failed_devices(const char *device)
|
||||
return (r == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt, enum dm_event_type event)
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask event)
|
||||
{
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
@@ -62,8 +61,12 @@ static int _get_mirror_event(char *params)
|
||||
int log_argc, num_devs;
|
||||
|
||||
/*
|
||||
* Unused: 0 409600 mirror
|
||||
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
|
||||
* dm core parms: 0 409600 mirror
|
||||
* Mirror core parms: 2 253:4 253:5 400/400
|
||||
* New-style failure params: 1 AA
|
||||
* New-style log params: 3 cluster 253:3 A
|
||||
* or 3 disk 253:3 A
|
||||
* or 1 core
|
||||
*/
|
||||
|
||||
/* number of devices */
|
||||
@@ -74,9 +77,9 @@ static int _get_mirror_event(char *params)
|
||||
goto out_parse;
|
||||
p += strlen(p) + 1;
|
||||
|
||||
/* devices names + max log parameters */
|
||||
args = dm_malloc((num_devs + 8) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 8, 0, args) < num_devs + 8)
|
||||
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
|
||||
args = dm_malloc((num_devs + 7) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
|
||||
goto out_parse;
|
||||
|
||||
dev_status_str = args[2 + num_devs];
|
||||
@@ -161,7 +164,7 @@ static int _remove_failed_devices(const char *device)
|
||||
return (r == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt, enum dm_event_type event)
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask event)
|
||||
{
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
|
||||
@@ -655,10 +655,11 @@ int register_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int do_reg)
|
||||
{
|
||||
#ifdef DMEVENTD
|
||||
int i, pending = 0, registered;
|
||||
int r = 0;
|
||||
struct list *tmp;
|
||||
struct lv_segment *seg;
|
||||
int (*reg) (struct lv_segment *, int events);
|
||||
int (*reg) (struct cmd_context *c, struct lv_segment *s, int e);
|
||||
|
||||
if (do_reg && !dmeventd_register_mode())
|
||||
return 1;
|
||||
@@ -666,24 +667,59 @@ int register_dev_for_events(struct cmd_context *cmd,
|
||||
list_iterate(tmp, &lv->segments) {
|
||||
seg = list_item(tmp, struct lv_segment);
|
||||
|
||||
if (!seg_monitored(seg) || (seg->status & PVMOVE))
|
||||
continue;
|
||||
reg = NULL;
|
||||
|
||||
if (do_reg) {
|
||||
if (seg->segtype->ops->target_register_events)
|
||||
reg = seg->segtype->ops->target_register_events;
|
||||
} else if (seg->segtype->ops->target_unregister_events)
|
||||
reg = seg->segtype->ops->target_unregister_events;
|
||||
/* Check monitoring status */
|
||||
if (seg->segtype->ops->target_registered)
|
||||
registered = seg->segtype->ops->target_registered(seg, &pending);
|
||||
else
|
||||
continue; /* segtype doesn't support registration */
|
||||
|
||||
/*
|
||||
* FIXME: We should really try again if pending
|
||||
*/
|
||||
registered = (pending) ? 0 : registered;
|
||||
|
||||
if (do_reg) {
|
||||
if (registered)
|
||||
log_verbose("%s/%s already monitored.", lv->vg->name, lv->name);
|
||||
else if (seg->segtype->ops->target_register_events)
|
||||
reg = seg->segtype->ops->target_register_events;
|
||||
} else {
|
||||
if (!registered)
|
||||
log_verbose("%s/%s already not monitored.", lv->vg->name, lv->name);
|
||||
else if (seg->segtype->ops->target_unregister_events)
|
||||
reg = seg->segtype->ops->target_unregister_events;
|
||||
}
|
||||
|
||||
/* Do [un]monitor */
|
||||
if (!reg)
|
||||
continue;
|
||||
|
||||
/* FIXME specify events */
|
||||
if (!reg(seg, 0)) {
|
||||
if (!reg(cmd, seg, 0)) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
/* Check [un]monitor results */
|
||||
/* Try a couple times if pending, but not forever... */
|
||||
for (i = 0; i < 10; i++) {
|
||||
pending = 0;
|
||||
registered = seg->segtype->ops->target_registered(seg, &pending);
|
||||
if (pending ||
|
||||
(!registered && do_reg) ||
|
||||
(registered && !do_reg))
|
||||
log_very_verbose("%s/%s %smonitoring still pending.",
|
||||
lv->vg->name, lv->name, do_reg ? "" : "un");
|
||||
else
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
r = (registered && do_reg) || (!registered && !do_reg);
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -728,7 +764,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
}
|
||||
}
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 0) != 1)
|
||||
if (register_dev_for_events(cmd, lv, 0) < 0)
|
||||
/* FIXME Consider aborting here */
|
||||
stack;
|
||||
|
||||
@@ -786,7 +822,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 1) != 1)
|
||||
if (register_dev_for_events(cmd, lv, 1) < 0)
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
@@ -832,7 +868,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 0) != 1)
|
||||
if (register_dev_for_events(cmd, lv, 0) < 0)
|
||||
stack;
|
||||
|
||||
memlock_inc();
|
||||
@@ -905,7 +941,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (!register_dev_for_events(cmd, lv, 1) != 1)
|
||||
if (!register_dev_for_events(cmd, lv, 1) < 0)
|
||||
stack;
|
||||
|
||||
return r;
|
||||
|
||||
@@ -853,7 +853,7 @@ static const char *_find_config_str(const struct config_node *cn1,
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
/* Empty strings are ignored */
|
||||
if ((n && n->v->type == CFG_STRING) && (*n->v->v.str)) {
|
||||
if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
|
||||
log_very_verbose("Setting %s to %s", path, n->v->v.str);
|
||||
return n->v->v.str;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ static int _has_partition_table(struct device *dev)
|
||||
/* Check for msdos partition table */
|
||||
part_magic = buf + PART_MAGIC_OFFSET/sizeof(buf[0]);
|
||||
if ((*part_magic == xlate16(PART_MAGIC))) {
|
||||
part = (struct partition *) (buf + PART_OFFSET);
|
||||
part = (struct partition *) (buf + PART_OFFSET/sizeof(buf[0]));
|
||||
for (p = 0; p < 4; p++, part++) {
|
||||
/* Table is invalid if boot indicator not 0 or 0x80 */
|
||||
if ((part->boot_ind & 0x7f)) {
|
||||
|
||||
@@ -32,6 +32,7 @@ struct dev_manager;
|
||||
#define SEG_FORMAT1_SUPPORT 0x00000010U
|
||||
#define SEG_VIRTUAL 0x00000020U
|
||||
#define SEG_CANNOT_BE_ZEROED 0x00000040U
|
||||
#define SEG_MONITORED 0x00000080U
|
||||
|
||||
#define seg_is_mirrored(seg) ((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
#define seg_is_striped(seg) ((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
@@ -39,6 +40,7 @@ struct dev_manager;
|
||||
#define seg_is_virtual(seg) ((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0)
|
||||
#define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
|
||||
#define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
|
||||
#define seg_monitored(seg) ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
|
||||
|
||||
#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
@@ -81,8 +83,11 @@ struct segtype_handler {
|
||||
const struct lv_segment *seg,
|
||||
struct list *modules);
|
||||
void (*destroy) (const struct segment_type * segtype);
|
||||
int (*target_register_events) (struct lv_segment *seg, int events);
|
||||
int (*target_unregister_events) (struct lv_segment *seg, int events);
|
||||
int (*target_registered) (struct lv_segment *seg, int *pending);
|
||||
int (*target_register_events) (struct cmd_context *cmd,
|
||||
struct lv_segment *seg, int events);
|
||||
int (*target_unregister_events) (struct cmd_context *cmd,
|
||||
struct lv_segment *seg, int events);
|
||||
};
|
||||
|
||||
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
|
||||
|
||||
@@ -368,13 +368,12 @@ static int _mirrored_target_present(const struct lv_segment *seg __attribute((un
|
||||
}
|
||||
|
||||
#ifdef DMEVENTD
|
||||
static int _setup_registration(struct dm_pool *mem, struct cmd_context *cmd,
|
||||
char **dso)
|
||||
static int _get_mirror_dso_path(struct cmd_context *cmd, char **dso)
|
||||
{
|
||||
char *path;
|
||||
const char *libpath;
|
||||
|
||||
if (!(path = dm_pool_alloc(mem, PATH_MAX))) {
|
||||
if (!(path = dm_pool_alloc(cmd->mem, PATH_MAX))) {
|
||||
log_error("Failed to allocate dmeventd library path.");
|
||||
return 0;
|
||||
}
|
||||
@@ -389,78 +388,111 @@ static int _setup_registration(struct dm_pool *mem, struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME This gets run while suspended and performs banned operations. */
|
||||
/* FIXME Merge these two functions */
|
||||
static int _target_register_events(struct lv_segment *seg,
|
||||
int events)
|
||||
static struct dm_event_handler *_create_dm_event_handler(const char *dmname,
|
||||
const char *dso,
|
||||
enum dm_event_mask mask)
|
||||
{
|
||||
struct dm_event_handler *dmevh;
|
||||
|
||||
if (!(dmevh = dm_event_handler_create()))
|
||||
return_0;
|
||||
|
||||
if (dm_event_handler_set_dso(dmevh, dso))
|
||||
goto fail;
|
||||
|
||||
if (dm_event_handler_set_dev_name(dmevh, dmname))
|
||||
goto fail;
|
||||
|
||||
dm_event_handler_set_event_mask(dmevh, mask);
|
||||
return dmevh;
|
||||
|
||||
fail:
|
||||
dm_event_handler_destroy(dmevh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _target_registered(struct lv_segment *seg, int *pending)
|
||||
{
|
||||
char *dso, *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
struct dm_event_handler *handler;
|
||||
enum dm_event_mask evmask = 0;
|
||||
struct dm_event_handler *dmevh;
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
if (!_setup_registration(vg->cmd->mem, vg->cmd, &dso)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
*pending = 0;
|
||||
if (!_get_mirror_dso_path(vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(handler = dm_event_handler_create()))
|
||||
if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
|
||||
return_0;
|
||||
|
||||
dm_event_handler_set_dso(handler, dso);
|
||||
dm_event_handler_set_name(handler, name);
|
||||
dm_event_handler_set_events(handler, DM_EVENT_ALL_ERRORS);
|
||||
if (!dm_event_register(handler)) {
|
||||
dm_event_handler_destroy(handler);
|
||||
return_0;
|
||||
if (dm_event_get_registered_device(dmevh, 0)) {
|
||||
dm_event_handler_destroy(dmevh);
|
||||
return 0;
|
||||
}
|
||||
dm_event_handler_destroy(handler);
|
||||
|
||||
log_info("Registered %s for events", name);
|
||||
evmask = dm_event_handler_get_event_mask(dmevh);
|
||||
if (evmask & DM_EVENT_REGISTRATION_PENDING) {
|
||||
*pending = 1;
|
||||
evmask &= ~DM_EVENT_REGISTRATION_PENDING;
|
||||
}
|
||||
|
||||
dm_event_handler_destroy(dmevh);
|
||||
|
||||
return evmask;
|
||||
}
|
||||
|
||||
/* FIXME This gets run while suspended and performs banned operations. */
|
||||
static int _target_set_events(struct cmd_context *cmd,
|
||||
struct lv_segment *seg,
|
||||
int evmask, int set)
|
||||
{
|
||||
char *dso, *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
struct dm_event_handler *dmevh;
|
||||
int r;
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
if (!_get_mirror_dso_path(cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(cmd->mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
|
||||
return_0;
|
||||
|
||||
r = set ? dm_event_register_handler(dmevh) : dm_event_unregister_handler(dmevh);
|
||||
dm_event_handler_destroy(dmevh);
|
||||
if (!r)
|
||||
return_0;
|
||||
|
||||
log_info("%s %s for events", set ? "Registered" : "Unregistered", name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _target_unregister_events(struct lv_segment *seg,
|
||||
static int _target_register_events(struct cmd_context *cmd,
|
||||
struct lv_segment *seg,
|
||||
int events)
|
||||
{
|
||||
char *dso;
|
||||
char *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
struct dm_event_handler *handler;
|
||||
return _target_set_events(cmd, seg, events, 1);
|
||||
}
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
/* FIXME Remove this and use handle to avoid config file race */
|
||||
if (!_setup_registration(vg->cmd->mem, vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(handler = dm_event_handler_create()))
|
||||
return_0;
|
||||
|
||||
dm_event_handler_set_dso(handler, dso);
|
||||
dm_event_handler_set_name(handler, name);
|
||||
dm_event_handler_set_events(handler, DM_EVENT_ALL_ERRORS);
|
||||
if (!dm_event_unregister(handler)) {
|
||||
dm_event_handler_destroy(handler);
|
||||
return_0;
|
||||
}
|
||||
dm_event_handler_destroy(handler);
|
||||
|
||||
log_info("Unregistered %s for events", name);
|
||||
|
||||
return 1;
|
||||
static int _target_unregister_events(struct cmd_context *cmd,
|
||||
struct lv_segment *seg,
|
||||
int events)
|
||||
{
|
||||
return _target_set_events(cmd, seg, events, 0);
|
||||
}
|
||||
|
||||
#endif /* DMEVENTD */
|
||||
@@ -504,6 +536,7 @@ static struct segtype_handler _mirrored_ops = {
|
||||
.target_percent = _mirrored_target_percent,
|
||||
.target_present = _mirrored_target_present,
|
||||
#ifdef DMEVENTD
|
||||
.target_registered = _target_registered,
|
||||
.target_register_events = _target_register_events,
|
||||
.target_unregister_events = _target_unregister_events,
|
||||
#endif
|
||||
@@ -530,7 +563,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
segtype->ops = &_mirrored_ops;
|
||||
segtype->name = "mirror";
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_AREAS_MIRRORED;
|
||||
segtype->flags = SEG_AREAS_MIRRORED | SEG_MONITORED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
|
||||
1183
lib/report/report.c
1183
lib/report/report.c
File diff suppressed because it is too large
Load Diff
@@ -115,4 +115,15 @@ dm_split_lvm_name
|
||||
dm_split_words
|
||||
dm_snprintf
|
||||
dm_basename
|
||||
dm_saprintf
|
||||
dm_asprintf
|
||||
dm_report_init
|
||||
dm_report_object
|
||||
dm_report_output
|
||||
dm_report_free
|
||||
dm_report_get_private
|
||||
dm_report_field_string
|
||||
dm_report_field_int
|
||||
dm_report_field_int32
|
||||
dm_report_field_uint32
|
||||
dm_report_field_uint64
|
||||
dm_report_field_set_value
|
||||
|
||||
@@ -24,6 +24,7 @@ SOURCES =\
|
||||
libdm-file.c \
|
||||
libdm-deptree.c \
|
||||
libdm-string.c \
|
||||
libdm-report.c \
|
||||
mm/dbg_malloc.c \
|
||||
mm/pool.c \
|
||||
$(interface)/libdm-iface.c
|
||||
|
||||
@@ -124,10 +124,10 @@ struct dm_names {
|
||||
};
|
||||
|
||||
struct dm_versions {
|
||||
uint32_t next; /* Offset to next struct from start of this struct */
|
||||
uint32_t version[3];
|
||||
uint32_t next; /* Offset to next struct from start of this struct */
|
||||
uint32_t version[3];
|
||||
|
||||
char name[0];
|
||||
char name[0];
|
||||
};
|
||||
|
||||
int dm_get_library_version(char *version, size_t size);
|
||||
@@ -236,12 +236,12 @@ int dm_tree_add_dev(struct dm_tree *tree, uint32_t major, uint32_t minor);
|
||||
* Add a new node to the tree if it doesn't already exist.
|
||||
*/
|
||||
struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *tree,
|
||||
const char *name,
|
||||
const char *uuid,
|
||||
uint32_t major, uint32_t minor,
|
||||
int read_only,
|
||||
int clear_inactive,
|
||||
void *context);
|
||||
const char *name,
|
||||
const char *uuid,
|
||||
uint32_t major, uint32_t minor,
|
||||
int read_only,
|
||||
int clear_inactive,
|
||||
void *context);
|
||||
|
||||
/*
|
||||
* Search for a node in the tree.
|
||||
@@ -289,16 +289,16 @@ int dm_tree_deactivate_children(struct dm_tree_node *dnode,
|
||||
* Ignores devices that don't have a uuid starting with uuid_prefix.
|
||||
*/
|
||||
int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
|
||||
/*
|
||||
* Resume a device plus all dependencies.
|
||||
* Ignores devices that don't have a uuid starting with uuid_prefix.
|
||||
*/
|
||||
int dm_tree_activate_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
|
||||
/*
|
||||
* Suspend a device plus all dependencies.
|
||||
@@ -626,7 +626,85 @@ char *dm_basename(const char *path);
|
||||
/*
|
||||
* Returns size of a buffer which is allocated with dm_malloc.
|
||||
* Pointer to the buffer is stored in *buf.
|
||||
* Returns -1 on failure leaving buf undefined.
|
||||
*/
|
||||
int dm_saprintf(char **buf, const char *format, ...);
|
||||
int dm_asprintf(char **buf, const char *format, ...);
|
||||
|
||||
/*********************
|
||||
* reporting functions
|
||||
*********************/
|
||||
|
||||
struct dm_report_object_type {
|
||||
uint32_t id; /* Powers of 2 */
|
||||
const char *desc;
|
||||
const char *prefix; /* field id string prefix (optional) */
|
||||
void *(*data_fn)(void *object); /* callback from report_object() */
|
||||
};
|
||||
|
||||
struct dm_report_field;
|
||||
|
||||
/*
|
||||
* dm_report_field_type flags
|
||||
*/
|
||||
#define DM_REPORT_FIELD_MASK 0x0000000F
|
||||
#define DM_REPORT_FIELD_ALIGN_LEFT 0x00000001
|
||||
#define DM_REPORT_FIELD_ALIGN_RIGHT 0x00000002
|
||||
#define DM_REPORT_FIELD_STRING 0x00000004
|
||||
#define DM_REPORT_FIELD_NUMBER 0x00000008
|
||||
|
||||
struct dm_report;
|
||||
struct dm_report_field_type {
|
||||
uint32_t type; /* object type id */
|
||||
const char id[32]; /* string used to specify the field */
|
||||
unsigned int offset; /* byte offset in the object */
|
||||
const char heading[32]; /* string printed in header */
|
||||
int width; /* default width */
|
||||
uint32_t flags; /* DM_REPORT_FIELD_* */
|
||||
int (*report_fn)(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data,
|
||||
void *private);
|
||||
};
|
||||
|
||||
/*
|
||||
* dm_report_init output_flags
|
||||
*/
|
||||
#define DM_REPORT_OUTPUT_MASK 0x00000007
|
||||
#define DM_REPORT_OUTPUT_ALIGNED 0x00000001
|
||||
#define DM_REPORT_OUTPUT_BUFFERED 0x00000002
|
||||
#define DM_REPORT_OUTPUT_HEADINGS 0x00000004
|
||||
|
||||
struct dm_report *dm_report_init(uint32_t *report_types,
|
||||
const struct dm_report_object_type *types,
|
||||
const struct dm_report_field_type *fields,
|
||||
const char *output_fields,
|
||||
const char *output_separator,
|
||||
uint32_t output_flags,
|
||||
const char *sort_keys,
|
||||
void *private);
|
||||
int dm_report_object(struct dm_report *rh, void *object);
|
||||
int dm_report_output(struct dm_report *rh);
|
||||
void dm_report_free(struct dm_report *rh);
|
||||
|
||||
/* report functions for common types */
|
||||
int dm_report_field_string(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data);
|
||||
int dm_report_field_int32(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data);
|
||||
int dm_report_field_uint32(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data);
|
||||
int dm_report_field_int(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data);
|
||||
int dm_report_field_uint64(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data);
|
||||
|
||||
/*
|
||||
* Helper function for custom reporting functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* sortvalue may be NULL if it's the same as value
|
||||
*/
|
||||
void dm_report_field_set_value(struct dm_report_field *field,
|
||||
const void *value, const void *sortvalue);
|
||||
|
||||
#endif /* LIB_DEVICE_MAPPER_H */
|
||||
|
||||
811
libdm/libdm-report.c
Normal file
811
libdm/libdm-report.c
Normal file
@@ -0,0 +1,811 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of device-mapper userspace tools.
|
||||
* The code is based on LVM2 report function.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
* Internal flags
|
||||
*/
|
||||
#define RH_SORT_REQUIRED 0x00000100
|
||||
#define RH_HEADINGS_PRINTED 0x00000200
|
||||
|
||||
struct dm_report {
|
||||
struct dm_pool *mem;
|
||||
|
||||
uint32_t report_types;
|
||||
const char *field_prefix;
|
||||
uint32_t flags;
|
||||
const char *separator;
|
||||
|
||||
uint32_t keys_count;
|
||||
|
||||
/* Ordered list of fields needed for this report */
|
||||
struct list field_props;
|
||||
|
||||
/* Rows of report data */
|
||||
struct list rows;
|
||||
|
||||
/* Array of field definitions */
|
||||
const struct dm_report_field_type *fields;
|
||||
const struct dm_report_object_type *types;
|
||||
|
||||
/* To store caller private data */
|
||||
void *private;
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal per-field flags
|
||||
*/
|
||||
#define FLD_HIDDEN 0x00000100
|
||||
#define FLD_SORT_KEY 0x00000200
|
||||
#define FLD_ASCENDING 0x00000400
|
||||
#define FLD_DESCENDING 0x00000800
|
||||
|
||||
struct field_properties {
|
||||
struct list list;
|
||||
uint32_t field_num;
|
||||
uint32_t sort_posn;
|
||||
unsigned width;
|
||||
const struct dm_report_object_type *type;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Report data field
|
||||
*/
|
||||
struct dm_report_field {
|
||||
struct list list;
|
||||
struct field_properties *props;
|
||||
|
||||
const char *report_string; /* Formatted ready for display */
|
||||
const void *sort_value; /* Raw value for sorting */
|
||||
};
|
||||
|
||||
struct row {
|
||||
struct list list;
|
||||
struct dm_report *rh;
|
||||
struct list fields; /* Fields in display order */
|
||||
struct dm_report_field *(*sort_fields)[]; /* Fields in sort order */
|
||||
};
|
||||
|
||||
static const struct dm_report_object_type *_find_type(struct dm_report *rh,
|
||||
uint32_t report_type)
|
||||
{
|
||||
const struct dm_report_object_type *t;
|
||||
|
||||
for (t = rh->types; t->data_fn; t++)
|
||||
if (t->id == report_type)
|
||||
return t;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data-munging functions to prepare each data type for display and sorting
|
||||
*/
|
||||
|
||||
int dm_report_field_string(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data)
|
||||
{
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_strdup(rh->mem, *(const char **) data))) {
|
||||
log_error("dm_report_field_string: dm_pool_strdup failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
field->report_string = repstr;
|
||||
field->sort_value = (const void *) field->report_string;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_int(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data)
|
||||
{
|
||||
const int value = *(const int *) data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
|
||||
log_error("dm_report_field_int: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
|
||||
log_error("dm_report_field_int: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 12, "%d", value) < 0) {
|
||||
log_error("dm_report_field_int: int too big: %d", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_uint32(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data)
|
||||
{
|
||||
const uint32_t value = *(const uint32_t *) data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
|
||||
log_error("dm_report_field_uint32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
|
||||
log_error("dm_report_field_uint32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 11, "%u", value) < 0) {
|
||||
log_error("dm_report_field_uint32: uint32 too big: %u", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_int32(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data)
|
||||
{
|
||||
const int32_t value = *(const int32_t *) data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
|
||||
log_error("dm_report_field_int32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
|
||||
log_error("dm_report_field_int32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 12, "%d", value) < 0) {
|
||||
log_error("dm_report_field_int32: int32 too big: %d", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_uint64(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data)
|
||||
{
|
||||
const int value = *(const uint64_t *) data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 22))) {
|
||||
log_error("dm_report_field_uint64: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
|
||||
log_error("dm_report_field_uint64: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 21, "%d", value) < 0) {
|
||||
log_error("dm_report_field_uint64: uint64 too big: %d", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper functions for custom report functions
|
||||
*/
|
||||
void dm_report_field_set_value(struct dm_report_field *field, const void *value, const void *sortvalue)
|
||||
{
|
||||
field->report_string = (const char *) value;
|
||||
field->sort_value = sortvalue ? : value;
|
||||
}
|
||||
|
||||
/*
|
||||
* show help message
|
||||
*/
|
||||
static void _display_fields(struct dm_report *rh)
|
||||
{
|
||||
uint32_t f;
|
||||
const struct dm_report_object_type *type;
|
||||
const char *desc, *last_desc = "";
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||
if ((type = _find_type(rh, rh->fields[f].type)) && type->desc)
|
||||
desc = type->desc;
|
||||
else
|
||||
desc = " ";
|
||||
if (desc != last_desc) {
|
||||
if (*last_desc)
|
||||
log_print(" ");
|
||||
log_print("%s Fields", desc);
|
||||
}
|
||||
|
||||
log_print("- %s", rh->fields[f].id);
|
||||
last_desc = desc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise report handle
|
||||
*/
|
||||
static int _copy_field(struct dm_report *rh, struct field_properties *dest,
|
||||
uint32_t field_num)
|
||||
{
|
||||
dest->field_num = field_num;
|
||||
dest->width = rh->fields[field_num].width;
|
||||
dest->flags = rh->fields[field_num].flags & DM_REPORT_FIELD_MASK;
|
||||
|
||||
/* set object type method */
|
||||
dest->type = _find_type(rh, rh->fields[field_num].type);
|
||||
if (!dest->type) {
|
||||
log_error("dm_report: field not match: %s",
|
||||
rh->fields[field_num].id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _field_match(struct dm_report *rh, const char *field, size_t flen)
|
||||
{
|
||||
uint32_t f, l;
|
||||
struct field_properties *fp;
|
||||
|
||||
if (!flen)
|
||||
return 0;
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||
if ((!strncasecmp(rh->fields[f].id, field, flen) &&
|
||||
strlen(rh->fields[f].id) == flen) ||
|
||||
(l = strlen(rh->field_prefix),
|
||||
!strncasecmp(rh->field_prefix, rh->fields[f].id, l) &&
|
||||
!strncasecmp(rh->fields[f].id + l, field, flen) &&
|
||||
strlen(rh->fields[f].id) == l + flen)) {
|
||||
rh->report_types |= rh->fields[f].type;
|
||||
if (!(fp = dm_pool_zalloc(rh->mem, sizeof(*fp)))) {
|
||||
log_error("dm_report: "
|
||||
"struct field_properties allocation "
|
||||
"failed");
|
||||
return 0;
|
||||
}
|
||||
if (!_copy_field(rh, fp, f))
|
||||
return 0;
|
||||
|
||||
list_add(&rh->field_props, &fp->list);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct field_properties *fp, *found = NULL;
|
||||
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (fp->field_num == field_num) {
|
||||
found = fp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
rh->report_types |= rh->fields[field_num].type;
|
||||
if (!(found = dm_pool_zalloc(rh->mem, sizeof(*found)))) {
|
||||
log_error("dm_report: "
|
||||
"struct field_properties allocation failed");
|
||||
return 0;
|
||||
}
|
||||
if (!_copy_field(rh, found, field_num))
|
||||
return 0;
|
||||
|
||||
/* Add as a non-display field */
|
||||
found->flags |= FLD_HIDDEN;
|
||||
|
||||
list_add(&rh->field_props, &found->list);
|
||||
}
|
||||
|
||||
if (found->flags & FLD_SORT_KEY) {
|
||||
log_error("dm_report: Ignoring duplicate sort field: %s",
|
||||
rh->fields[field_num].id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
found->flags |= FLD_SORT_KEY;
|
||||
found->sort_posn = rh->keys_count++;
|
||||
found->flags |= flags;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _key_match(struct dm_report *rh, const char *key, size_t len)
|
||||
{
|
||||
uint32_t f, l;
|
||||
uint32_t flags;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (*key == '+') {
|
||||
key++;
|
||||
len--;
|
||||
flags = FLD_ASCENDING;
|
||||
} else if (*key == '-') {
|
||||
key++;
|
||||
len--;
|
||||
flags = FLD_DESCENDING;
|
||||
} else
|
||||
flags = FLD_ASCENDING;
|
||||
|
||||
if (!len) {
|
||||
log_error("dm_report: Missing sort field name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||
if ((!strncasecmp(rh->fields[f].id, key, len) &&
|
||||
strlen(rh->fields[f].id) == len) ||
|
||||
(l = strlen(rh->field_prefix),
|
||||
!strncasecmp(rh->field_prefix, rh->fields[f].id, l) &&
|
||||
!strncasecmp(rh->fields[f].id + l, key, len) &&
|
||||
strlen(rh->fields[f].id) == l + len)) {
|
||||
return _add_sort_key(rh, f, flags);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _parse_options(struct dm_report *rh, const char *format)
|
||||
{
|
||||
const char *ws; /* Word start */
|
||||
const char *we = format; /* Word end */
|
||||
|
||||
while (*we) {
|
||||
/* Allow consecutive commas */
|
||||
while (*we && *we == ',')
|
||||
we++;
|
||||
|
||||
/* start of the field name */
|
||||
ws = we;
|
||||
while (*we && *we != ',')
|
||||
we++;
|
||||
|
||||
if (!_field_match(rh, ws, (size_t) (we - ws))) {
|
||||
_display_fields(rh);
|
||||
log_print(" ");
|
||||
log_error("dm_report: Unrecognised field: %.*s",
|
||||
(int) (we - ws), ws);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _parse_keys(struct dm_report *rh, const char *keys)
|
||||
{
|
||||
const char *ws; /* Word start */
|
||||
const char *we = keys; /* Word end */
|
||||
|
||||
while (*we) {
|
||||
/* Allow consecutive commas */
|
||||
while (*we && *we == ',')
|
||||
we++;
|
||||
ws = we;
|
||||
while (*we && *we != ',')
|
||||
we++;
|
||||
if (!_key_match(rh, ws, (size_t) (we - ws))) {
|
||||
log_error("dm_report: Unrecognised field: %.*s",
|
||||
(int) (we - ws), ws);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dm_report *dm_report_init(uint32_t *report_types,
|
||||
const struct dm_report_object_type *types,
|
||||
const struct dm_report_field_type *fields,
|
||||
const char *output_fields,
|
||||
const char *output_separator,
|
||||
uint32_t output_flags,
|
||||
const char *sort_keys,
|
||||
void *private)
|
||||
{
|
||||
struct dm_report *rh;
|
||||
const struct dm_report_object_type *type;
|
||||
|
||||
if (!(rh = dm_malloc(sizeof(*rh)))) {
|
||||
log_error("dm_report_init: dm_malloc failed");
|
||||
return 0;
|
||||
}
|
||||
memset(rh, 0, sizeof(*rh));
|
||||
|
||||
/*
|
||||
* rh->report_types is updated in _parse_options() and _parse_keys()
|
||||
* to contain all types corresponding to the fields specified by
|
||||
* options or keys.
|
||||
*/
|
||||
if (report_types)
|
||||
rh->report_types = *report_types;
|
||||
|
||||
rh->separator = output_separator;
|
||||
rh->fields = fields;
|
||||
rh->types = types;
|
||||
rh->private = private;
|
||||
|
||||
rh->flags |= output_flags & DM_REPORT_OUTPUT_MASK;
|
||||
|
||||
if (output_flags & DM_REPORT_OUTPUT_BUFFERED)
|
||||
rh->flags |= RH_SORT_REQUIRED;
|
||||
|
||||
list_init(&rh->field_props);
|
||||
list_init(&rh->rows);
|
||||
|
||||
if ((type = _find_type(rh, rh->report_types)) && type->prefix)
|
||||
rh->field_prefix = type->prefix;
|
||||
else
|
||||
rh->field_prefix = "";
|
||||
|
||||
if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
|
||||
log_error("dm_report_init: allocation of memory pool failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Generate list of fields for output based on format string & flags */
|
||||
if (!_parse_options(rh, output_fields))
|
||||
return NULL;
|
||||
|
||||
if (!_parse_keys(rh, sort_keys))
|
||||
return NULL;
|
||||
|
||||
/* Return updated types value for further compatility check by caller */
|
||||
if (report_types)
|
||||
*report_types = rh->report_types;
|
||||
|
||||
return rh;
|
||||
}
|
||||
|
||||
void dm_report_free(struct dm_report *rh)
|
||||
{
|
||||
dm_pool_destroy(rh->mem);
|
||||
dm_free(rh);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a row of data for an object
|
||||
*/
|
||||
static void * _report_get_field_data(struct dm_report *rh,
|
||||
struct field_properties *fp, void *object)
|
||||
{
|
||||
void *ret = fp->type->data_fn(object);
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
return ret + rh->fields[fp->field_num].offset;
|
||||
}
|
||||
|
||||
int dm_report_object(struct dm_report *rh, void *object)
|
||||
{
|
||||
struct field_properties *fp;
|
||||
struct row *row;
|
||||
struct dm_report_field *field;
|
||||
void *data = NULL;
|
||||
|
||||
if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
|
||||
log_error("dm_report_object: struct row allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
row->rh = rh;
|
||||
|
||||
if ((rh->flags & RH_SORT_REQUIRED) &&
|
||||
!(row->sort_fields =
|
||||
dm_pool_zalloc(rh->mem, sizeof(struct dm_report_field *) *
|
||||
rh->keys_count))) {
|
||||
log_error("dm_report_object: "
|
||||
"row sort value structure allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(&row->fields);
|
||||
list_add(&rh->rows, &row->list);
|
||||
|
||||
/* For each field to be displayed, call its report_fn */
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
|
||||
log_error("dm_report_object: "
|
||||
"struct dm_report_field allocation failed");
|
||||
return 0;
|
||||
}
|
||||
field->props = fp;
|
||||
|
||||
data = _report_get_field_data(rh, fp, object);
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
|
||||
field, data,
|
||||
rh->private)) {
|
||||
log_error("dm_report_object: "
|
||||
"report function failed for field %s",
|
||||
rh->fields[fp->field_num].id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((strlen(field->report_string) > field->props->width))
|
||||
field->props->width = strlen(field->report_string);
|
||||
|
||||
if ((rh->flags & RH_SORT_REQUIRED) &&
|
||||
(field->props->flags & FLD_SORT_KEY)) {
|
||||
(*row->sort_fields)[field->props->sort_posn] = field;
|
||||
}
|
||||
list_add(&row->fields, &field->list);
|
||||
}
|
||||
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
|
||||
return dm_report_output(rh);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print row of headings
|
||||
*/
|
||||
static int _report_headings(struct dm_report *rh)
|
||||
{
|
||||
struct field_properties *fp;
|
||||
const char *heading;
|
||||
char buf[1024];
|
||||
|
||||
if (rh->flags & RH_HEADINGS_PRINTED)
|
||||
return 1;
|
||||
|
||||
rh->flags |= RH_HEADINGS_PRINTED;
|
||||
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_HEADINGS))
|
||||
return 1;
|
||||
|
||||
if (!dm_pool_begin_object(rh->mem, 128)) {
|
||||
log_error("dm_report: "
|
||||
"dm_pool_begin_object failed for headings");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First heading line */
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (fp->flags & FLD_HIDDEN)
|
||||
continue;
|
||||
|
||||
heading = rh->fields[fp->field_num].heading;
|
||||
if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
|
||||
fp->width, fp->width, heading) < 0) {
|
||||
log_error("dm_report: snprintf heading failed");
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, buf, fp->width)) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
} else if (!dm_pool_grow_object(rh->mem, heading,
|
||||
strlen(heading))) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!list_end(&rh->field_props, &fp->list))
|
||||
if (!dm_pool_grow_object(rh->mem, rh->separator,
|
||||
strlen(rh->separator))) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
log_print("%s", (char *) dm_pool_end_object(rh->mem));
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
dm_pool_abandon_object(rh->mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort rows of data
|
||||
*/
|
||||
static int _row_compare(const void *a, const void *b)
|
||||
{
|
||||
const struct row *rowa = *(const struct row **) a;
|
||||
const struct row *rowb = *(const struct row **) b;
|
||||
const struct dm_report_field *sfa, *sfb;
|
||||
uint32_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
|
||||
sfa = (*rowa->sort_fields)[cnt];
|
||||
sfb = (*rowb->sort_fields)[cnt];
|
||||
if (sfa->props->flags & DM_REPORT_FIELD_NUMBER) {
|
||||
const uint64_t numa =
|
||||
*(const uint64_t *) sfa->sort_value;
|
||||
const uint64_t numb =
|
||||
*(const uint64_t *) sfb->sort_value;
|
||||
|
||||
if (numa == numb)
|
||||
continue;
|
||||
|
||||
if (sfa->props->flags & FLD_ASCENDING) {
|
||||
return (numa > numb) ? 1 : -1;
|
||||
} else { /* FLD_DESCENDING */
|
||||
return (numa < numb) ? 1 : -1;
|
||||
}
|
||||
} else { /* DM_REPORT_FIELD_STRING */
|
||||
const char *stra = (const char *) sfa->sort_value;
|
||||
const char *strb = (const char *) sfb->sort_value;
|
||||
int cmp = strcmp(stra, strb);
|
||||
|
||||
if (!cmp)
|
||||
continue;
|
||||
|
||||
if (sfa->props->flags & FLD_ASCENDING) {
|
||||
return (cmp > 0) ? 1 : -1;
|
||||
} else { /* FLD_DESCENDING */
|
||||
return (cmp < 0) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* Identical */
|
||||
}
|
||||
|
||||
static int _sort_rows(struct dm_report *rh)
|
||||
{
|
||||
struct row *(*rows)[];
|
||||
uint32_t count = 0;
|
||||
struct row *row;
|
||||
|
||||
if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
|
||||
list_size(&rh->rows)))) {
|
||||
log_error("dm_report: sort array allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(row, &rh->rows)
|
||||
(*rows)[count++] = row;
|
||||
|
||||
qsort(rows, count, sizeof(**rows), _row_compare);
|
||||
|
||||
list_init(&rh->rows);
|
||||
while (count--)
|
||||
list_add_h(&rh->rows, &(*rows)[count]->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Produce report output
|
||||
*/
|
||||
int dm_report_output(struct dm_report *rh)
|
||||
{
|
||||
struct list *fh, *rowh, *ftmp, *rtmp;
|
||||
struct row *row = NULL;
|
||||
struct dm_report_field *field;
|
||||
const char *repstr;
|
||||
char buf[4096];
|
||||
unsigned width;
|
||||
|
||||
if (list_empty(&rh->rows))
|
||||
return 1;
|
||||
|
||||
/* Sort rows */
|
||||
if ((rh->flags & RH_SORT_REQUIRED))
|
||||
_sort_rows(rh);
|
||||
|
||||
/* If headings not printed yet, calculate field widths and print them */
|
||||
if (!(rh->flags & RH_HEADINGS_PRINTED))
|
||||
_report_headings(rh);
|
||||
|
||||
/* Print and clear buffer */
|
||||
list_iterate_safe(rowh, rtmp, &rh->rows) {
|
||||
if (!dm_pool_begin_object(rh->mem, 512)) {
|
||||
log_error("dm_report: "
|
||||
"dm_pool_begin_object failed for row");
|
||||
return 0;
|
||||
}
|
||||
row = list_item(rowh, struct row);
|
||||
list_iterate_safe(fh, ftmp, &row->fields) {
|
||||
field = list_item(fh, struct dm_report_field);
|
||||
if (field->props->flags & FLD_HIDDEN)
|
||||
continue;
|
||||
|
||||
repstr = field->report_string;
|
||||
width = field->props->width;
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
|
||||
if (!dm_pool_grow_object(rh->mem, repstr,
|
||||
strlen(repstr)))
|
||||
goto bad_grow;
|
||||
} else if (field->props->flags & DM_REPORT_FIELD_ALIGN_LEFT) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
|
||||
width, width, repstr) < 0)
|
||||
goto bad_snprintf;
|
||||
if (!dm_pool_grow_object(rh->mem, buf, width))
|
||||
goto bad_grow;
|
||||
} else if (field->props->flags & DM_REPORT_FIELD_ALIGN_RIGHT) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%*.*s",
|
||||
width, width, repstr) < 0)
|
||||
goto bad_snprintf;
|
||||
if (!dm_pool_grow_object(rh->mem, buf, width))
|
||||
goto bad_grow;
|
||||
}
|
||||
|
||||
if (!list_end(&row->fields, fh))
|
||||
if (!dm_pool_grow_object(rh->mem, rh->separator,
|
||||
strlen(rh->separator)))
|
||||
goto bad_grow;
|
||||
list_del(&field->list);
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, "\0", 1))
|
||||
goto bad_grow;
|
||||
log_print("%s", (char *) dm_pool_end_object(rh->mem));
|
||||
list_del(&row->list);
|
||||
}
|
||||
|
||||
if (row)
|
||||
dm_pool_free(rh->mem, row);
|
||||
|
||||
return 1;
|
||||
|
||||
bad_snprintf:
|
||||
log_error("dm_report: snprintf row failed");
|
||||
bad_grow:
|
||||
log_error("dm_report: Failed to generate row for printing");
|
||||
dm_pool_abandon_object(rh->mem);
|
||||
return 0;
|
||||
}
|
||||
@@ -129,7 +129,7 @@ char *dm_basename(const char *path)
|
||||
return p ? p + 1 : (char *) path;
|
||||
}
|
||||
|
||||
int dm_saprintf(char **result, const char *format, ...)
|
||||
int dm_asprintf(char **result, const char *format, ...)
|
||||
{
|
||||
int n, ok = 0, size = 32;
|
||||
va_list ap;
|
||||
|
||||
@@ -20,9 +20,14 @@
|
||||
|
||||
char *dm_strdup_aux(const char *str, const char *file, int line)
|
||||
{
|
||||
char *ret = dm_malloc_aux_debug(strlen(str) + 1, file, line);
|
||||
char *ret;
|
||||
|
||||
if (ret)
|
||||
if (!str) {
|
||||
log_error("Internal error: dm_strdup called with NULL pointer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ret = dm_malloc_aux_debug(strlen(str) + 1, file, line)))
|
||||
strcpy(ret, str);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -533,7 +533,11 @@ static int _message(int argc, char **argv, void *data __attribute((unused)))
|
||||
for (i = 0; i < argc; i++)
|
||||
sz += strlen(argv[i]) + 1;
|
||||
|
||||
str = dm_malloc(sz);
|
||||
if (!(str = dm_malloc(sz))) {
|
||||
err("message string allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(str, 0, sz);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
@@ -1669,7 +1673,7 @@ static char *parse_loop_device_name(char *dev)
|
||||
char *buf;
|
||||
char *device;
|
||||
|
||||
if (!(buf = dm_malloc(PATH_MAX)));
|
||||
if (!(buf = dm_malloc(PATH_MAX)))
|
||||
return NULL;
|
||||
|
||||
if (dev[0] == '/') {
|
||||
|
||||
@@ -104,8 +104,10 @@ static int lvchange_registration(struct cmd_context *cmd,
|
||||
(dmeventd_register_mode()) ? "" : "un", lv->name);
|
||||
r = 0;
|
||||
} else if (!r) {
|
||||
log_verbose("Logical volume %s needs no monitoring.",
|
||||
lv->name);
|
||||
log_verbose("Logical volume %s needs no %smonitoring, or is already %smonitored",
|
||||
(dmeventd_register_mode()) ? "" : "un",
|
||||
lv->name,
|
||||
(dmeventd_register_mode()) ? "" : "un");
|
||||
r = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "tools.h"
|
||||
#include "lvm2cmdline.h"
|
||||
#include "label.h"
|
||||
#include "memlock.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "lvm2cmd.h"
|
||||
|
||||
@@ -152,6 +152,14 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((lv->status & MIRRORED) ||
|
||||
(lv->status & MIRROR_LOG) ||
|
||||
(lv->status & MIRROR_IMAGE)) {
|
||||
log_error("Mirrored LV, \"%s\" cannot be renamed: %s",
|
||||
lv->name, strerror(ENOSYS));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!archive(lv->vg)) {
|
||||
stack;
|
||||
goto error;
|
||||
|
||||
@@ -25,7 +25,7 @@ static int _vgs_single(struct cmd_context *cmd __attribute((unused)),
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!report_object(handle, vg, NULL, NULL, NULL, NULL))
|
||||
if (!report_object(handle, vg, NULL, NULL, NULL, NULL));
|
||||
return ECMD_FAILED;
|
||||
|
||||
check_current_backup(vg);
|
||||
@@ -39,7 +39,7 @@ static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL))
|
||||
if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL));
|
||||
return ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
@@ -48,7 +48,7 @@ static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
static int _segs_single(struct cmd_context *cmd __attribute((unused)),
|
||||
struct lv_segment *seg, void *handle)
|
||||
{
|
||||
if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL))
|
||||
if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL));
|
||||
return ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
@@ -78,7 +78,7 @@ static int _pvsegs_sub_single(struct cmd_context *cmd, struct volume_group *vg,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!report_object(handle, vg, NULL, pv, NULL, pvseg))
|
||||
if (!report_object(handle, vg, NULL, pv, NULL, pvseg));
|
||||
ret = ECMD_FAILED;
|
||||
|
||||
out:
|
||||
@@ -128,7 +128,7 @@ static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
|
||||
}
|
||||
}
|
||||
|
||||
if (!report_object(handle, vg, NULL, pv, NULL, NULL))
|
||||
if (!report_object(handle, vg, NULL, pv, NULL, NULL));
|
||||
ret = ECMD_FAILED;
|
||||
|
||||
out:
|
||||
@@ -262,6 +262,26 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
|
||||
headings)))
|
||||
return 0;
|
||||
|
||||
/* Ensure options selected are compatible */
|
||||
if (report_type & SEGS)
|
||||
report_type |= LVS;
|
||||
if (report_type & PVSEGS)
|
||||
report_type |= PVS;
|
||||
if ((report_type & LVS) && (report_type & PVS)) {
|
||||
log_error("Can't report LV and PV fields at the same time");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Change report type if fields specified makes this necessary */
|
||||
if (report_type & SEGS)
|
||||
report_type = SEGS;
|
||||
else if (report_type & LVS)
|
||||
report_type = LVS;
|
||||
else if (report_type & PVSEGS)
|
||||
report_type = PVSEGS;
|
||||
else if (report_type & PVS)
|
||||
report_type = PVS;
|
||||
|
||||
switch (report_type) {
|
||||
case LVS:
|
||||
r = process_each_lv(cmd, argc, argv, LCK_VG_READ, report_handle,
|
||||
@@ -285,9 +305,9 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
|
||||
break;
|
||||
}
|
||||
|
||||
report_output(report_handle);
|
||||
dm_report_output(report_handle);
|
||||
|
||||
report_free(report_handle);
|
||||
dm_report_free(report_handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -993,7 +993,7 @@ static int _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl,
|
||||
}
|
||||
|
||||
/* Determine selected physical extents */
|
||||
if (!_parse_pes(mem, colon, pe_ranges, dev_name(pvl->pv->dev),
|
||||
if (!_parse_pes(mem, colon, new_pvl->pe_ranges, dev_name(pvl->pv->dev),
|
||||
pvl->pv->pe_count)) {
|
||||
stack;
|
||||
return 0;
|
||||
|
||||
@@ -53,8 +53,7 @@ static int _register_lvs_in_vg(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the number of monitored devices, not the number
|
||||
* of _new_ monitored devices
|
||||
* returns the number of _new_ monitored devices
|
||||
*/
|
||||
|
||||
return count;
|
||||
@@ -117,7 +116,7 @@ static int _vgchange_monitoring(struct cmd_context *cmd, struct volume_group *vg
|
||||
if ((active = lvs_in_vg_activated(vg))) {
|
||||
monitored = _register_lvs_in_vg(cmd, vg, dmeventd_register_mode());
|
||||
log_print("%d logical volume(s) in volume group "
|
||||
"\"%s\" now %smonitored",
|
||||
"\"%s\" %smonitored",
|
||||
monitored, vg->name, (dmeventd_register_mode()) ? "" : "un");
|
||||
}
|
||||
|
||||
@@ -157,7 +156,7 @@ static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
|
||||
"already active", active, vg->name);
|
||||
monitored = _register_lvs_in_vg(cmd, vg, dmeventd_register_mode());
|
||||
log_verbose("%d existing logical volume(s) in volume "
|
||||
"group \"%s\" now %smonitored",
|
||||
"group \"%s\" %smonitored",
|
||||
monitored, vg->name,
|
||||
dmeventd_register_mode() ? "" : "un");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user