summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlasdair Kergon <agk@redhat.com>2007-01-11 21:54:53 +0000
committerAlasdair Kergon <agk@redhat.com>2007-01-11 21:54:53 +0000
commitd554b2bc94e9c7ce43527c5c3737c40ce9e8e394 (patch)
tree23a9c8896986cb5e493b3f7cd5b3c9629b958668
parentf66943de435055613a126bd03864a583a7e2996a (diff)
downloadlvm2-old-v1_02_14.tar.gz
Lots of dmeventd-related changes.v1_02_14old-v1_02_14
-rw-r--r--WHATS_NEW_DM3
-rw-r--r--daemons/dmeventd/.exported_symbols17
-rw-r--r--daemons/dmeventd/dmeventd.c433
-rw-r--r--daemons/dmeventd/libdevmapper-event.c305
-rw-r--r--daemons/dmeventd/libdevmapper-event.h94
-rw-r--r--libdm/.exported_symbols1
-rw-r--r--libdm/libdevmapper.h6
-rw-r--r--libdm/libdm-string.c30
8 files changed, 565 insertions, 324 deletions
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index fa6fc15b9..52a9fa050 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,8 +1,9 @@
Version 1.02.14 -
=============================
+ Add dm_saprintf().
Use CFLAGS when linking so mixed sparc builds can supply -m64.
Add dm_tree_use_no_flush_suspend().
- Lots of dmevent changes.
+ Lots of dmevent changes including revised interface.
Export dm_basename().
Cope with a trailing space when comparing tables prior to possible reload.
Fix dmeventd to cope if monitored device disappears.
diff --git a/daemons/dmeventd/.exported_symbols b/daemons/dmeventd/.exported_symbols
index 75779d02b..2e0af3b1b 100644
--- a/daemons/dmeventd/.exported_symbols
+++ b/daemons/dmeventd/.exported_symbols
@@ -1,5 +1,16 @@
+dm_event_handler_create
+dm_event_handler_destroy
+dm_event_handler_set_dso
+dm_event_handler_set_name
+dm_event_handler_set_uuid
+dm_event_handler_set_major
+dm_event_handler_set_minor
+dm_event_handler_set_events
+dm_event_handler_get_dso
+dm_event_handler_get_name
+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_get_registered_device
-dm_event_set_timeout
-dm_event_get_timeout
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index 2c9277984..59b058486 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -19,6 +19,7 @@
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
+#include "configure.h"
#include "libdevmapper.h"
#include "libdevmapper-event.h"
#include "list.h"
@@ -44,17 +45,17 @@
#include <sys/resource.h>
#include <unistd.h>
#include <stdarg.h>
-#include <arpa/inet.h> /* for htonl, ntohl */
+#include <arpa/inet.h> /* for htonl, ntohl */
#ifdef linux
#include <malloc.h>
#endif
-/* We must use syslog for now, because multilog is not yet implemented */
+/* FIXME We use syslog for now, because multilog is not yet implemented */
#include <syslog.h>
-static volatile sig_atomic_t _exit_now = 0; /* set to '1' when signal is given to exit */
-static volatile sig_atomic_t _thread_registries_empty = 1; /* registries are empty initially */
+static volatile sig_atomic_t _exit_now = 0; /* set to '1' when signal is given to exit */
+static volatile sig_atomic_t _thread_registries_empty = 1; /* registries are empty initially */
/* List (un)link macros. */
#define LINK(x, head) list_add(head, &(x)->list)
@@ -78,19 +79,24 @@ static pthread_mutex_t _global_mutex;
struct dso_data {
struct list list;
- char *dso_name; /* DSO name (eg, "evms", "dmraid", "lvm2"). */
+ char *dso_name; /* DSO name (eg, "evms", "dmraid", "lvm2"). */
- void *dso_handle; /* Opaque handle as returned from dlopen(). */
- unsigned int ref_count; /* Library reference count. */
+ void *dso_handle; /* Opaque handle as returned from dlopen(). */
+ unsigned int ref_count; /* Library reference count. */
/*
* Event processing.
*
- * The DSO can do whatever appropriate steps if an event happens
- * such as changing the mapping in case a mirror fails, update
- * the application metadata etc.
+ * The DSO can do whatever appropriate steps if an event
+ * happens such as changing the mapping in case a mirror
+ * fails, update the application metadata etc.
+ *
+ * This function gets a dm_task that is a result of
+ * DM_DEVICE_WAITEVENT ioctl (results equivalent to
+ * DM_DEVICE_STATUS). It should not destroy it.
+ * The caller must dispose of the task.
*/
- void (*process_event)(const char *device, enum dm_event_type event);
+ void (*process_event)(struct dm_task *dmt, enum dm_event_type event);
/*
* Device registration.
@@ -100,7 +106,8 @@ struct dso_data {
* the process_event() function is sane (eg, read metadata
* and activate a mapping).
*/
- int (*register_device)(const char *device);
+ int (*register_device)(const char *device, const char *uuid, int major,
+ int minor);
/*
* Device unregistration.
@@ -109,14 +116,15 @@ struct dso_data {
* for events, the DSO can recognize this and carry out appropriate
* steps (eg, deactivate mapping, metadata update).
*/
- int (*unregister_device)(const char *device);
+ int (*unregister_device)(const char *device, const char *uuid,
+ int major, int minor);
};
static LIST_INIT(_dso_registry);
/* Structure to keep parsed register variables from client message. */
struct message_data {
char *dso_name; /* Name of DSO. */
- char *device_path; /* Mapped device path. */
+ char *device_uuid; /* Mapped device path. */
union {
char *str; /* Events string as fetched from message. */
enum dm_event_type field; /* Events bitfield. */
@@ -139,15 +147,19 @@ struct thread_status {
pthread_t thread;
- struct dso_data *dso_data;/* DSO this thread accesses. */
-
- char *device_path; /* Mapped device path. */
+ struct dso_data *dso_data; /* DSO this thread accesses. */
+
+ struct {
+ char *uuid;
+ char *name;
+ int major, minor;
+ } device;
uint32_t event_nr; /* event number */
int processing; /* Set when event is being processed */
int status; /* running/shutdown/done */
enum dm_event_type events; /* bitfield for event filter. */
- enum dm_event_type current_events;/* bitfield for occured events. */
- enum dm_event_type processed_events;/* bitfield for processed events. */
+ enum dm_event_type current_events; /* bitfield for occured events. */
+ struct dm_task *current_task;
time_t next_time;
uint32_t timeout;
struct list timeout_list;
@@ -168,13 +180,16 @@ static struct thread_status *alloc_thread_status(struct message_data *data,
if (ret) {
if (!memset(ret, 0, sizeof(*ret)) ||
- !(ret->device_path = dm_strdup(data->device_path))) {
+ !(ret->device.uuid = dm_strdup(data->device_uuid))) {
dm_free(ret);
ret = NULL;
} else {
+ ret->current_task = NULL;
+ ret->device.name = NULL;
+ ret->device.major = ret->device.minor = 0;
ret->dso_data = dso_data;
- ret->events = data->events.field;
- ret->timeout = data->timeout.secs;
+ ret->events = data->events.field;
+ ret->timeout = data->timeout.secs;
list_init(&ret->timeout_list);
}
}
@@ -184,7 +199,8 @@ static struct thread_status *alloc_thread_status(struct message_data *data,
static void free_thread_status(struct thread_status *thread)
{
- dm_free(thread->device_path);
+ dm_free(thread->device.uuid);
+ dm_free(thread->device.name);
dm_free(thread);
}
@@ -213,9 +229,10 @@ static void free_dso_data(struct dso_data *data)
/*
* Fetch a string off src and duplicate it into *ptr.
- * Pay attention to 0 lenght strings.
+ * Pay attention to zero-length strings.
*/
-/* FIXME: move to separate module to share with the client lib. */
+/* FIXME? move to libdevmapper to share with the client lib (need to
+ make delimiter a parameter then) */
static const char delimiter = ' ';
static int fetch_string(char **ptr, char **src)
{
@@ -250,8 +267,8 @@ static void free_message(struct message_data *message_data)
if (message_data->dso_name)
dm_free(message_data->dso_name);
- if (message_data->device_path)
- dm_free(message_data->device_path);
+ if (message_data->device_uuid)
+ dm_free(message_data->device_uuid);
}
@@ -270,7 +287,7 @@ static int parse_message(struct message_data *message_data)
* path and events # string from message.
*/
if (fetch_string(&message_data->dso_name, &p) &&
- fetch_string(&message_data->device_path, &p) &&
+ fetch_string(&message_data->device_uuid, &p) &&
fetch_string(&message_data->events.str, &p) &&
fetch_string(&message_data->timeout.str, &p)) {
if (message_data->events.str) {
@@ -287,7 +304,7 @@ static int parse_message(struct message_data *message_data)
uint32_t secs = atoi(message_data->timeout.str);
dm_free(message_data->timeout.str);
message_data->timeout.secs = secs ? secs :
- DM_EVENT_DEFAULT_TIMEOUT;
+ DM_EVENT_DEFAULT_TIMEOUT;
}
ret = 1;
@@ -330,23 +347,43 @@ static int storepid(int lf)
return 1;
}
-/* FIXME This is unreliable: should use DM_DEVICE_INFO ioctl instead. */
/* Check, if a device exists. */
-static int device_exists(char *device)
+static int fill_device_data(struct thread_status *ts)
{
- struct stat st_buf;
- char path2[PATH_MAX];
+ struct dm_task *dmt;
+ struct dm_info dmi;
- if (!device || !*device)
+ if (!ts->device.uuid)
return 0;
- if (device[0] == '/') /* absolute path */
- return !stat(device, &st_buf) && S_ISBLK(st_buf.st_mode);
+ ts->device.name = NULL;
+ ts->device.major = ts->device.minor = 0;
- if (PATH_MAX <= snprintf(path2, PATH_MAX, "%s/%s", dm_dir(), device))
+ dmt = dm_task_create(DM_DEVICE_INFO);
+ if (!dmt)
return 0;
- return !stat(path2, &st_buf) && S_ISBLK(st_buf.st_mode);
+ dm_task_set_uuid(dmt, ts->device.uuid);
+ if (!dm_task_run(dmt))
+ goto fail;
+
+ ts->device.name = dm_strdup(dm_task_get_name(dmt));
+ if (!ts->device.name)
+ goto fail;
+
+ if (!dm_task_get_info(dmt, &dmi))
+ goto fail;
+
+ ts->device.major = dmi.major;
+ ts->device.minor = dmi.minor;
+
+ dm_task_destroy(dmt);
+ return 1;
+
+ fail:
+ dm_task_destroy(dmt);
+ dm_free(ts->device.name);
+ return 0;
}
/*
@@ -359,13 +396,12 @@ static struct thread_status *lookup_thread_status(struct message_data *data)
struct thread_status *thread;
list_iterate_items(thread, &_thread_registry)
- if (!strcmp(data->device_path, thread->device_path))
- return thread;
+ if (!strcmp(data->device_uuid, thread->device.uuid))
+ return thread;
return NULL;
}
-
/* Cleanup at exit. */
static void exit_dm_lib(void)
{
@@ -392,11 +428,10 @@ static void *timeout_thread(void *unused)
while (!list_empty(&timeout_registry)) {
struct thread_status *thread;
- timeout.tv_sec = (time_t)-1;
+ timeout.tv_sec = (time_t) -1;
curr_time = time(NULL);
- list_iterate_items_gen(thread, &timeout_registry,
- timeout_list) {
+ list_iterate_items_gen(thread, &timeout_registry, timeout_list) {
if (thread->next_time < curr_time) {
thread->next_time = curr_time + thread->timeout;
pthread_kill(thread->thread, SIGALRM);
@@ -406,7 +441,8 @@ static void *timeout_thread(void *unused)
timeout.tv_sec = thread->next_time;
}
- pthread_cond_timedwait(&_timeout_cond, &_timeout_mutex, &timeout);
+ pthread_cond_timedwait(&_timeout_cond, &_timeout_mutex,
+ &timeout);
}
pthread_cleanup_pop(1);
@@ -452,7 +488,7 @@ static void unregister_for_timeout(struct thread_status *thread)
}
static void no_intr_log(int level, const char *file, int line,
- const char *f, ...)
+ const char *f, ...)
{
va_list ap;
@@ -491,23 +527,22 @@ static sigset_t unblock_sigalrm(void)
#define DM_WAIT_FATAL 2
/* Wait on a device until an event occurs. */
-static int event_wait(struct thread_status *thread)
+static int event_wait(struct thread_status *thread, struct dm_task **task)
{
sigset_t set;
int ret = DM_WAIT_RETRY;
-/*
- void *next = NULL;
- char *params, *target_type;
- uint64_t start, length;
-*/
struct dm_task *dmt;
struct dm_info info;
+ *task = 0;
+
if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
return DM_WAIT_RETRY;
- if (!(ret = dm_task_set_name(dmt, dm_basename(thread->device_path))) ||
- !(ret = dm_task_set_event_nr(dmt, thread->event_nr)))
+ thread->current_task = dmt;
+
+ if (!dm_task_set_uuid(dmt, thread->device.uuid) ||
+ !dm_task_set_event_nr(dmt, thread->event_nr))
goto out;
/*
@@ -517,31 +552,21 @@ static int event_wait(struct thread_status *thread)
set = unblock_sigalrm();
dm_log_init(no_intr_log);
errno = 0;
- if ((ret = dm_task_run(dmt))) {
+ if (dm_task_run(dmt)) {
thread->current_events |= DM_EVENT_DEVICE_ERROR;
ret = DM_WAIT_INTR;
- /*
- * FIXME: I am setting processed_events to zero here
- * because it is causing problems. for example, the
- * mirror target emits a signal for INSYNC, then
- * subsequent events (device failures) are not handled
- */
- thread->processed_events = 0;
-
if ((ret = dm_task_get_info(dmt, &info)))
thread->event_nr = info.event_nr;
} else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) {
thread->current_events |= DM_EVENT_TIMEOUT;
ret = DM_WAIT_INTR;
- thread->processed_events = 0;
} else {
- /* FIXME replace with log_* macro */
syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
errno, strerror(errno));
if (errno == ENXIO) {
- /* FIXME replace with log_* macro */
- syslog(LOG_ERR, "%s disappeared, detaching", thread->device_path);
+ syslog(LOG_ERR, "%s disappeared, detaching",
+ thread->device.name);
ret = DM_WAIT_FATAL;
}
}
@@ -549,8 +574,12 @@ static int event_wait(struct thread_status *thread)
pthread_sigmask(SIG_SETMASK, &set, NULL);
dm_log_init(NULL);
- out:
- dm_task_destroy(dmt);
+ out:
+ if (ret == DM_WAIT_FATAL || ret == DM_WAIT_RETRY) {
+ dm_task_destroy(dmt);
+ thread->current_task = NULL;
+ } else
+ *task = dmt;
return ret;
}
@@ -558,20 +587,25 @@ static int event_wait(struct thread_status *thread)
/* Register a device with the DSO. */
static int do_register_device(struct thread_status *thread)
{
- return thread->dso_data->register_device(thread->device_path);
+ return thread->dso_data->register_device(thread->device.name,
+ thread->device.uuid,
+ thread->device.major,
+ thread->device.minor);
}
/* Unregister a device with the DSO. */
static int do_unregister_device(struct thread_status *thread)
{
- return thread->dso_data->unregister_device(thread->device_path);
+ return thread->dso_data->unregister_device(thread->device.name,
+ thread->device.uuid,
+ thread->device.major,
+ thread->device.minor);
}
/* Process an event in the DSO. */
-static void do_process_event(struct thread_status *thread)
+static void do_process_event(struct thread_status *thread, struct dm_task *task)
{
- thread->dso_data->process_event(thread->device_path,
- thread->current_events);
+ thread->dso_data->process_event(task, thread->current_events);
}
/* Thread cleanup handler to unregister device. */
@@ -581,7 +615,10 @@ static void monitor_unregister(void *arg)
if (!do_unregister_device(thread))
syslog(LOG_ERR, "%s: %s unregister failed\n", __func__,
- thread->device_path);
+ thread->device.name);
+ if (thread->current_task)
+ dm_task_destroy(thread->current_task);
+ thread->current_task = NULL;
}
/* Device monitoring thread. */
@@ -589,6 +626,7 @@ static void *monitor_thread(void *arg)
{
struct thread_status *thread = arg;
int wait_error = 0;
+ struct dm_task *task;
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
pthread_cleanup_push(monitor_unregister, thread);
@@ -602,25 +640,25 @@ static void *monitor_thread(void *arg)
while (1) {
thread->current_events = 0;
- wait_error = event_wait(thread);
+ wait_error = event_wait(thread, &task);
if (wait_error == DM_WAIT_RETRY)
continue;
- /* FIXME Give a DSO a chance to clean up. */
if (wait_error == DM_WAIT_FATAL)
break;
/*
+ * We know that wait succeeded and stored a
+ * pointer to dm_task with device status into task.
+ */
+
+ /*
* Check against filter.
*
* If there's current events delivered from event_wait() AND
* the device got registered for those events AND
* those events haven't been processed yet, call
* the DSO's process_event() handler.
- *
- * FIXME: when does processed_events get cleared? What if
- * the same type of event happens later... after the first
- * was handled properly?
*/
lock_mutex();
if (thread->status == DM_THREAD_SHUTDOWN) {
@@ -629,17 +667,21 @@ static void *monitor_thread(void *arg)
}
unlock_mutex();
- if (thread->events &
- thread->current_events &
- ~thread->processed_events) {
+ if (thread->events & thread->current_events) {
lock_mutex();
thread->processing = 1;
unlock_mutex();
- do_process_event(thread);
- thread->processed_events |= thread->current_events;
+
+ do_process_event(thread, task);
+ dm_task_destroy(task);
+ thread->current_task = NULL;
+
lock_mutex();
thread->processing = 0;
unlock_mutex();
+ } else {
+ dm_task_destroy(task);
+ thread->current_task = NULL;
}
}
@@ -647,12 +689,12 @@ static void *monitor_thread(void *arg)
thread->status = DM_THREAD_DONE;
unlock_mutex();
- pthread_cleanup_pop(0);
+ pthread_cleanup_pop(1);
+
return NULL;
}
/* Create a device monitoring thread. */
-/* FIXME: call this with mutex hold ? */
static int create_thread(struct thread_status *thread)
{
return pthread_create(&thread->thread, NULL, monitor_thread, thread);
@@ -691,11 +733,11 @@ static struct dso_data *lookup_dso(struct message_data *data)
lock_mutex();
list_iterate_items(dso_data, &_dso_registry)
- if (!strcmp(data->dso_name, dso_data->dso_name)) {
- lib_get(dso_data);
- ret = dso_data;
- break;
- }
+ if (!strcmp(data->dso_name, dso_data->dso_name)) {
+ lib_get(dso_data);
+ ret = dso_data;
+ break;
+ }
unlock_mutex();
@@ -714,12 +756,12 @@ static int lookup_symbol(void *dl, struct dso_data *data,
static int lookup_symbols(void *dl, struct dso_data *data)
{
- return lookup_symbol(dl, data, (void*) &data->process_event,
+ return lookup_symbol(dl, data, (void *) &data->process_event,
"process_event") &&
- lookup_symbol(dl, data, (void*) &data->register_device,
- "register_device") &&
- lookup_symbol(dl, data, (void*) &data->unregister_device,
- "unregister_device");
+ lookup_symbol(dl, data, (void *) &data->register_device,
+ "register_device") &&
+ lookup_symbol(dl, data, (void *) &data->unregister_device,
+ "unregister_device");
}
/* Load an application specific DSO. */
@@ -728,13 +770,13 @@ static struct dso_data *load_dso(struct message_data *data)
void *dl;
struct dso_data *ret = NULL;
- if (!(dl = dlopen(data->dso_name, RTLD_NOW))){
+ if (!(dl = dlopen(data->dso_name, RTLD_NOW))) {
const char *dlerr = dlerror();
- syslog(LOG_ERR, "dmeventd %s dlopen failed: %s", data->dso_name, dlerr);
- char buf[1024]; /* FIXME */
- snprintf(buf, 1024, "%s dlopen failed: %s", data->dso_name, dlerr);
- data->msg->size = strlen(buf) + 1;
- data->msg->data = dm_strdup(buf);
+ syslog(LOG_ERR, "dmeventd %s dlopen failed: %s", data->dso_name,
+ dlerr);
+ data->msg->size =
+ dm_saprintf(&(data->msg->data), "%s dlopen failed: %s",
+ data->dso_name, dlerr);
return NULL;
}
@@ -763,7 +805,6 @@ static struct dso_data *load_dso(struct message_data *data)
return ret;
}
-
/* Return success on daemon active check. */
static int active(struct message_data *message_data)
{
@@ -782,16 +823,9 @@ static int register_for_event(struct message_data *message_data)
struct thread_status *thread, *thread_new = NULL;
struct dso_data *dso_data;
- if (!device_exists(message_data->device_path)) {
- stack;
- ret = -ENODEV;
- goto out;
- }
-
if (!(dso_data = lookup_dso(message_data)) &&
!(dso_data = load_dso(message_data))) {
stack;
-/* FIXME */
#ifdef ELIBACC
ret = -ELIBACC;
#else
@@ -799,7 +833,7 @@ static int register_for_event(struct message_data *message_data)
#endif
goto out;
}
-
+
/* Preallocate thread status struct to avoid deadlock. */
if (!(thread_new = alloc_thread_status(message_data, dso_data))) {
stack;
@@ -807,15 +841,17 @@ static int register_for_event(struct message_data *message_data)
goto out;
}
+ if (!fill_device_data(thread_new)) {
+ stack;
+ ret = -ENODEV;
+ goto out;
+ }
+
lock_mutex();
if (!(thread = lookup_thread_status(message_data))) {
unlock_mutex();
- /*
- * FIXME: better do this asynchronously in the
- * monitoring thread ?
- */
if (!(ret = do_register_device(thread_new)))
goto out;
@@ -836,7 +872,7 @@ static int register_for_event(struct message_data *message_data)
/* Or event # into events bitfield. */
thread->events |= message_data->events.field;
- unlock_mutex();
+ unlock_mutex();
/* FIXME - If you fail to register for timeout events, you
still monitor all the other events. Is this the right
@@ -847,7 +883,7 @@ static int register_for_event(struct message_data *message_data)
if (thread->events & DM_EVENT_TIMEOUT)
ret = -register_for_timeout(thread);
- out:
+ out:
/*
* Deallocate thread status after releasing
* the lock in case we haven't used it.
@@ -894,7 +930,7 @@ static int unregister_for_event(struct message_data *message_data)
}
unlock_mutex();
- out:
+ out:
return ret;
}
@@ -906,42 +942,40 @@ static int unregister_for_event(struct message_data *message_data)
static int registered_device(struct message_data *message_data,
struct thread_status *thread)
{
- char test[1];
struct dm_event_daemon_message *msg = message_data->msg;
const char *fmt = "%s %s %u";
const char *dso = thread->dso_data->dso_name;
- const char *dev = thread->device_path;
- unsigned events = ((thread->status == DM_THREAD_RUNNING) && (thread->events)) ?
- thread->events : thread->events | DM_EVENT_REGISTRATION_PENDING;
+ const char *dev = thread->device.uuid;
+ unsigned events = ((thread->status == DM_THREAD_RUNNING)
+ && (thread->events)) ? thread->events : thread->
+ events | DM_EVENT_REGISTRATION_PENDING;
if (msg->data)
dm_free(msg->data);
- msg->size = snprintf(test, 1, fmt, dso, dev, events);
- msg->data = dm_malloc(msg->size);
- snprintf(msg->data, msg->size, fmt, dso, dev, events);
+ msg->size = dm_saprintf(&(msg->data), fmt, dso, dev, events);
unlock_mutex();
return 0;
}
-static int want_registered_device(char *dso_name, char *device_path,
+static int want_registered_device(char *dso_name, char *device_uuid,
struct thread_status *thread)
{
/* If DSO names and device paths are equal. */
- if (dso_name && device_path)
+ if (dso_name && device_uuid)
return !strcmp(dso_name, thread->dso_data->dso_name) &&
- !strcmp(device_path, thread->device_path);
+ !strcmp(device_uuid, thread->device.uuid);
/* If DSO names are equal. */
if (dso_name)
return !strcmp(dso_name, thread->dso_data->dso_name);
-
+
/* If device paths are equal. */
- if (device_path)
- return !strcmp(device_path, thread->device_path);
+ if (device_uuid)
+ return !strcmp(device_uuid, thread->device.uuid);
return 1;
}
@@ -955,10 +989,10 @@ static int _get_registered_device(struct message_data *message_data, int next)
/* Iterate list of threads checking if we want a particular one. */
list_iterate_items(thread, &_thread_registry)
- if ((hit = want_registered_device(message_data->dso_name,
- message_data->device_path,
- thread)))
- break;
+ if ((hit = want_registered_device(message_data->dso_name,
+ message_data->device_uuid,
+ thread)))
+ break;
/*
* If we got a registered device and want the next one ->
@@ -970,15 +1004,13 @@ static int _get_registered_device(struct message_data *message_data, int next)
do {
if (list_end(&_thread_registry, &thread->list))
goto out;
-
- thread = list_item(thread->list.n,
- struct thread_status);
- } while (!want_registered_device(message_data->dso_name,
- NULL, thread));
+
+ thread = list_item(thread->list.n, struct thread_status);
+ } while (!want_registered_device(message_data->dso_name, NULL, thread));
return registered_device(message_data, thread);
- out:
+ out:
unlock_mutex();
return -ENOENT;
@@ -1000,7 +1032,7 @@ static int set_timeout(struct message_data *message_data)
lock_mutex();
if ((thread = lookup_thread_status(message_data)))
- thread->timeout = message_data->timeout.secs;
+ thread->timeout = message_data->timeout.secs;
unlock_mutex();
return thread ? 0 : -ENODEV;
@@ -1016,9 +1048,8 @@ static int get_timeout(struct message_data *message_data)
lock_mutex();
if ((thread = lookup_thread_status(message_data))) {
- msg->data = dm_malloc(8*sizeof(uint32_t)); /* FIXME */
- msg->size = snprintf(msg->data, 8*sizeof(uint32_t),
- "%"PRIu32, thread->timeout);
+ msg->size =
+ dm_saprintf(&(msg->data), "%" PRIu32, thread->timeout);
} else {
msg->data = NULL;
msg->size = 0;
@@ -1027,7 +1058,6 @@ static int get_timeout(struct message_data *message_data)
return thread ? 0 : -ENODEV;
}
-
/* Initialize a fifos structure with path names. */
static void init_fifos(struct dm_event_fifos *fifos)
@@ -1049,17 +1079,27 @@ static int open_fifos(struct dm_event_fifos *fifos)
return -errno;
}
- /* FIXME Warn/abort if perms are wrong - not something to fix silently. */
+ struct stat st;
+
+ /* Warn about wrong permissions if applicable */
+ if ((!stat(fifos->client_path, &st)) && (st.st_mode & 0777) != 0600)
+ syslog(LOG_WARNING, "Fixing wrong permissions on %s",
+ fifos->client_path);
+
+ if ((!stat(fifos->server_path, &st)) && (st.st_mode & 0777) != 0600)
+ syslog(LOG_WARNING, "Fixing wrong permissions on %s",
+ fifos->server_path);
+
/* If they were already there, make sure permissions are ok. */
if (chmod(fifos->client_path, 0600)) {
syslog(LOG_ERR, "Unable to set correct file permissions on %s",
- fifos->client_path);
+ fifos->client_path);
return -errno;
}
if (chmod(fifos->server_path, 0600)) {
syslog(LOG_ERR, "Unable to set correct file permissions on %s",
- fifos->server_path);
+ fifos->server_path);
return -errno;
}
@@ -1083,7 +1123,8 @@ static int open_fifos(struct dm_event_fifos *fifos)
* Read message from client making sure that data is available
* and a complete message is read. Must not block indefinitely.
*/
-static int client_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
+static int client_read(struct dm_event_fifos *fifos,
+ struct dm_event_daemon_message *msg)
{
struct timeval t;
unsigned bytes = 0;
@@ -1102,22 +1143,22 @@ static int client_read(struct dm_event_fifos *fifos, struct dm_event_daemon_mess
FD_SET(fifos->client, &fds);
t.tv_sec = 1;
t.tv_usec = 0;
- ret = select(fifos->client+1, &fds, NULL, NULL, &t);
+ ret = select(fifos->client + 1, &fds, NULL, NULL, &t);
- if (!ret && !bytes) /* nothing to read */
+ if (!ret && !bytes) /* nothing to read */
return 0;
- if (!ret) /* trying to finish read */
+ if (!ret) /* trying to finish read */
continue;
- if (ret < 0) /* error */
+ if (ret < 0) /* error */
return 0;
ret = read(fifos->client, buf + bytes, size - bytes);
bytes += ret > 0 ? ret : 0;
- if (bytes == 2*sizeof(uint32_t) && header) {
- msg->cmd = ntohl(*((uint32_t *)buf));
- msg->size = ntohl(*((uint32_t *)buf + 1));
+ if (bytes == 2 * sizeof(uint32_t) && header) {
+ msg->cmd = ntohl(*((uint32_t *) buf));
+ msg->size = ntohl(*((uint32_t *) buf + 1));
buf = msg->data = dm_malloc(msg->size);
size = msg->size;
bytes = 0;
@@ -1129,6 +1170,7 @@ static int client_read(struct dm_event_fifos *fifos, struct dm_event_daemon_mess
if (msg->data)
dm_free(msg->data);
msg->data = NULL;
+ msg->size = 0;
}
return bytes == size;
@@ -1137,18 +1179,20 @@ static int client_read(struct dm_event_fifos *fifos, struct dm_event_daemon_mess
/*
* Write a message to the client making sure that it is ready to write.
*/
-static int client_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
+static int client_write(struct dm_event_fifos *fifos,
+ struct dm_event_daemon_message *msg)
{
unsigned bytes = 0;
int ret = 0;
fd_set fds;
- size_t size = 2*sizeof(uint32_t) + msg->size;
+ size_t size = 2 * sizeof(uint32_t) + msg->size;
char *buf = alloca(size);
*((uint32_t *)buf) = htonl(msg->cmd);
*((uint32_t *)buf + 1) = htonl(msg->size);
- memcpy(buf + 2*sizeof(uint32_t), msg->data, msg->size);
+ if (msg->data)
+ memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
errno = 0;
while (bytes < size && errno != EIO) {
@@ -1156,7 +1200,8 @@ static int client_write(struct dm_event_fifos *fifos, struct dm_event_daemon_mes
/* Watch client write FIFO to be ready for output. */
FD_ZERO(&fds);
FD_SET(fifos->server, &fds);
- } while (select(fifos->server +1, NULL, &fds, NULL, NULL) != 1);
+ } while (select(fifos->server + 1, NULL, &fds, NULL, NULL) !=
+ 1);
ret = write(fifos->server, buf + bytes, size - bytes);
bytes += ret > 0 ? ret : 0;
@@ -1176,15 +1221,16 @@ static int handle_request(struct dm_event_daemon_message *msg,
{
static struct {
unsigned int cmd;
- int (*f)(struct message_data*);
+ int (*f)(struct message_data *);
} requests[] = {
- { DM_EVENT_CMD_REGISTER_FOR_EVENT, register_for_event },
- { DM_EVENT_CMD_UNREGISTER_FOR_EVENT, unregister_for_event },
- { DM_EVENT_CMD_GET_REGISTERED_DEVICE, get_registered_device },
- { DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE, get_next_registered_device },
- { DM_EVENT_CMD_SET_TIMEOUT, set_timeout },
- { DM_EVENT_CMD_GET_TIMEOUT, get_timeout },
- { DM_EVENT_CMD_ACTIVE, active },
+ { DM_EVENT_CMD_REGISTER_FOR_EVENT, register_for_event},
+ { DM_EVENT_CMD_UNREGISTER_FOR_EVENT, unregister_for_event},
+ { DM_EVENT_CMD_GET_REGISTERED_DEVICE, get_registered_device},
+ { DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
+ get_next_registered_device},
+ { DM_EVENT_CMD_SET_TIMEOUT, set_timeout},
+ { DM_EVENT_CMD_GET_TIMEOUT, get_timeout},
+ { DM_EVENT_CMD_ACTIVE, active},
}, *req;
for (req = requests; req < requests + sizeof(requests); req++)
@@ -1203,8 +1249,7 @@ static int do_process_request(struct dm_event_daemon_message *msg)
/* Parse the message. */
memset(&message_data, 0, sizeof(message_data));
message_data.msg = msg;
- if (msg->cmd != DM_EVENT_CMD_ACTIVE &&
- !parse_message(&message_data)) {
+ if (msg->cmd != DM_EVENT_CMD_ACTIVE && !parse_message(&message_data)) {
stack;
ret = -EINVAL;
} else
@@ -1220,15 +1265,11 @@ static void process_request(struct dm_event_fifos *fifos)
{
struct dm_event_daemon_message msg;
- /* FIXME: better error handling */
-
memset(&msg, 0, sizeof(msg));
/*
- * Read the request from the client.
- * Of course, it's tough to tell what to do when
- * we use fucking retarded return codes like
- * 0 for error.
+ * Read the request from the client (client_read, client_write
+ * give true on success and false on failure).
*/
if (!client_read(fifos, &msg))
return;
@@ -1236,7 +1277,12 @@ static void process_request(struct dm_event_fifos *fifos)
msg.cmd = do_process_request(&msg);
if (!msg.data) {
msg.data = dm_strdup(strerror(-msg.cmd));
- msg.size = strlen(msg.data) + 1;
+ if (msg.data)
+ msg.size = strlen(msg.data) + 1;
+ else {
+ msg.size = 0;
+ stack;
+ }
}
if (!client_write(fifos, &msg))
@@ -1256,7 +1302,7 @@ static void cleanup_unused_threads(void)
while ((l = list_first(&_thread_registry_unused))) {
thread = list_item(l, struct thread_status);
if (thread->processing) {
- goto out; /* cleanup on the next round */
+ goto out; /* cleanup on the next round */
}
if (thread->status == DM_THREAD_RUNNING) {
@@ -1270,14 +1316,16 @@ static void cleanup_unused_threads(void)
if (ret == ESRCH) {
thread->status = DM_THREAD_DONE;
} else if (ret) {
- syslog(LOG_ERR, "Unable to terminate thread: %s\n",
+ syslog(LOG_ERR,
+ "Unable to terminate thread: %s\n",
strerror(-ret));
stack;
}
goto out;
} else {
list_del(l);
- syslog(LOG_ERR, "thread can't be on unused list unless !thread->events");
+ syslog(LOG_ERR,
+ "thread can't be on unused list unless !thread->events");
thread->status = DM_THREAD_RUNNING;
LINK_THREAD(thread);
}
@@ -1288,7 +1336,7 @@ static void cleanup_unused_threads(void)
free_thread_status(thread);
}
}
-out:
+ out:
unlock_mutex();
}
@@ -1302,7 +1350,7 @@ static void init_thread_signals(void)
{
sigset_t my_sigset;
struct sigaction act;
-
+
memset(&act, 0, sizeof(act));
act.sa_handler = sig_alarm;
sigaction(SIGALRM, &act, NULL);
@@ -1344,7 +1392,7 @@ static void exit_handler(int sig)
static int lock_pidfile(void)
{
int lf;
- char pidfile[] = "/var/run/dmeventd.pid"; /* FIXME Must be configurable at compile-time! */
+ char pidfile[] = DMEVENTD_PIDFILE;
if ((lf = open(pidfile, O_CREAT | O_RDWR, 0644)) < 0)
exit(EXIT_OPEN_PID_FAILURE);
@@ -1383,11 +1431,11 @@ static void daemonize(void)
/* Wait for response from child */
while (!waitpid(pid, &status, WNOHANG) && !_exit_now) {
tval.tv_sec = 0;
- tval.tv_usec = 250000; /* .25 sec */
+ tval.tv_usec = 250000; /* .25 sec */
select(0, NULL, NULL, NULL, &tval);
}
- if (_exit_now) /* Child has signaled it is ok - we can exit now */
+ if (_exit_now) /* Child has signaled it is ok - we can exit now */
exit(EXIT_SUCCESS);
/* Problem with child. Determine what it is by exit code */
@@ -1408,7 +1456,7 @@ static void daemonize(void)
break;
}
- exit(EXIT_FAILURE); /* Redundant */
+ exit(EXIT_FAILURE); /* Redundant */
}
setsid();
@@ -1416,7 +1464,7 @@ static void daemonize(void)
exit(EXIT_CHDIR_FAILURE);
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
- fd = 256; /* just have to guess */
+ fd = 256; /* just have to guess */
else
fd = rlim.rlim_cur;
@@ -1430,7 +1478,7 @@ static void daemonize(void)
openlog("dmeventd", LOG_PID, LOG_DAEMON);
- lock_pidfile(); /* exits if failure */
+ lock_pidfile(); /* exits if failure */
/* Set the rest of the signals to cause '_exit_now' to be set */
signal(SIGINT, &exit_handler);
@@ -1472,7 +1520,8 @@ int main(int argc, char *argv[])
while (!_exit_now) {
process_request(&fifos);
cleanup_unused_threads();
- if (!list_empty(&_thread_registry) || !list_empty(&_thread_registry_unused))
+ if (!list_empty(&_thread_registry)
+ || !list_empty(&_thread_registry_unused))
_thread_registries_empty = 0;
else
_thread_registries_empty = 1;
diff --git a/daemons/dmeventd/libdevmapper-event.c b/daemons/dmeventd/libdevmapper-event.c
index ccbc36fb8..ce22e6123 100644
--- a/daemons/dmeventd/libdevmapper-event.c
+++ b/daemons/dmeventd/libdevmapper-event.c
@@ -28,45 +28,112 @@
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
-#include <arpa/inet.h> /* for htonl, ntohl */
+#include <arpa/inet.h> /* for htonl, ntohl */
+
+struct dm_event_handler {
+ const char *dso;
+ const char *device;
+ const char *uuid;
+ int major;
+ int minor;
+ enum dm_event_type events;
+};
+
+static void dm_event_handler_clear_device(struct dm_event_handler *h)
+{
+ h->device = h->uuid = NULL;
+ h->major = h->minor = 0;
+}
-/* Set by any of the external fxns the first time one of them is called */
-/* FIXME Unused */
-// static int _logging = 0;
+struct dm_event_handler *dm_event_handler_create(void)
+{
+ struct dm_event_handler *ret = 0;
-/* 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)
+ if (!(ret = dm_malloc(sizeof(*ret))))
+ return NULL;
+
+ ret->dso = ret->device = ret->uuid = NULL;
+ ret->major = ret->minor = 0;
+ ret->events = 0;
+
+ return ret;
+}
+
+void dm_event_handler_destroy(struct dm_event_handler *h)
{
- char *p, *ret;
+ dm_free(h);
+}
- if ((p = strchr(*src, delimiter)))
- *p = 0;
+void dm_event_handler_set_dso(struct dm_event_handler *h, const char *path)
+{
+ h->dso = path;
+}
- if ((ret = dm_strdup(*src)))
- *src += strlen(ret) + 1;
+void dm_event_handler_set_name(struct dm_event_handler *h, const char *name)
+{
+ dm_event_handler_clear_device(h);
+ h->device = name;
+}
- if (p)
- *p = delimiter;
+void dm_event_handler_set_uuid(struct dm_event_handler *h, const char *uuid)
+{
+ dm_event_handler_clear_device(h);
+ h->uuid = uuid;
+}
- return ret;
+void dm_event_handler_set_major(struct dm_event_handler *h, int major)
+{
+ int minor = h->minor;
+
+ dm_event_handler_clear_device(h);
+ h->major = major;
+ h->minor = minor;
}
-/* 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)
+void dm_event_handler_set_minor(struct dm_event_handler *h, int minor)
{
- char *p = msg->data;
+ int major = h->major;
- if ((*dso_name = fetch_string(&p)) &&
- (*device = fetch_string(&p))) {
- *events = atoi(p);
+ dm_event_handler_clear_device(h);
- return 0;
- }
+ h->major = major;
+ h->minor = minor;
+}
- return -ENOMEM;
+void dm_event_handler_set_events(struct dm_event_handler *h,
+ enum dm_event_type event)
+{
+ h->events = event;
+}
+
+const char *dm_event_handler_get_dso(const struct dm_event_handler *h)
+{
+ return h->dso;
+}
+
+const char *dm_event_handler_get_name(const struct dm_event_handler *h)
+{
+ return h->device;
+}
+
+const char *dm_event_handler_get_uuid(const struct dm_event_handler *h)
+{
+ return h->uuid;
+}
+
+int dm_event_handler_get_major(const struct dm_event_handler *h)
+{
+ return h->major;
+}
+
+int dm_event_handler_get_minor(const struct dm_event_handler *h)
+{
+ return h->minor;
+}
+
+enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h)
+{
+ return h->events;
}
/*
@@ -78,13 +145,14 @@ static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
*
* 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;
fd_set fds;
- struct timeval tval = {0, 0};
- size_t size = 2 * sizeof(uint32_t); // status + size
+ struct timeval tval = { 0, 0 };
+ size_t size = 2 * sizeof(uint32_t); /* status + size */
char *buf = alloca(size);
int header = 1;
@@ -94,7 +162,8 @@ static int daemon_read(struct dm_event_fifos *fifos, struct dm_event_daemon_mess
FD_ZERO(&fds);
FD_SET(fifos->server, &fds);
tval.tv_sec = 1;
- ret = select(fifos->server+1, &fds, NULL, NULL, &tval);
+ ret = select(fifos->server + 1, &fds, NULL, NULL,
+ &tval);
if (ret < 0 && errno != EINTR) {
log_error("Unable to read from event server");
return 0;
@@ -116,7 +185,7 @@ static int daemon_read(struct dm_event_fifos *fifos, struct dm_event_daemon_mess
}
bytes += ret;
- if (bytes == 2*sizeof(uint32_t) && header) {
+ if (bytes == 2 * sizeof(uint32_t) && header) {
msg->cmd = ntohl(*((uint32_t *)buf));
msg->size = ntohl(*((uint32_t *)buf + 1));
buf = msg->data = dm_malloc(msg->size);
@@ -136,32 +205,34 @@ static int daemon_read(struct dm_event_fifos *fifos, struct dm_event_daemon_mess
}
/* 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;
fd_set fds;
- size_t size = 2*sizeof(uint32_t) + msg->size;
+ size_t size = 2 * sizeof(uint32_t) + msg->size;
char *buf = alloca(size);
*((uint32_t *)buf) = htonl(msg->cmd);
*((uint32_t *)buf + 1) = htonl(msg->size);
- memcpy(buf + 2*sizeof(uint32_t), msg->data, msg->size);
+ memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
while (bytes < size) {
do {
/* Watch daemon write FIFO to be ready for output. */
FD_ZERO(&fds);
FD_SET(fifos->client, &fds);
- ret = select(fifos->client +1, NULL, &fds, NULL, NULL);
+ ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
if ((ret < 0) && (errno != EINTR)) {
log_error("Unable to talk to event daemon");
return 0;
}
} while (ret < 1);
- ret = write(fifos->client, ((char *) buf) + bytes, size - bytes);
+ ret = write(fifos->client, ((char *) buf) + bytes,
+ size - bytes);
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
@@ -177,14 +248,14 @@ static int daemon_write(struct dm_event_fifos *fifos, struct dm_event_daemon_mes
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,
+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)
{
- char test[1];
const char *dso = dso_name ? dso_name : "";
const char *dev = device ? device : "";
- const char *fmt = "%s %s %u %"PRIu32;
+ const char *fmt = "%s %s %u %" PRIu32;
memset(msg, 0, sizeof(*msg));
/*
@@ -192,10 +263,7 @@ static int daemon_talk(struct dm_event_fifos *fifos, struct dm_event_daemon_mess
* into ASCII message string.
*/
msg->cmd = cmd;
- /* FIXME depends on glibc 2.1+ */
- msg->size = snprintf(test, 1, fmt, dso, dev, events, timeout);
- msg->data = alloca(msg->size);
- snprintf(msg->data, msg->size, fmt, dso, dev, events, timeout);
+ msg->size = dm_saprintf(&(msg->data), fmt, dso, dev, events, timeout);
/*
* Write command and message to and
@@ -256,7 +324,7 @@ static int start_daemon(struct dm_event_fifos *fifos)
return 0;
}
-start_server:
+ start_server:
/* server is not running */
pid = fork();
@@ -264,11 +332,13 @@ start_server:
log_error("Unable to fork.");
else if (!pid) {
- execvp("dmeventd", NULL); /* security risk if admin has bad PATH */
+ /* FIXME configure path (cf. lvm2 modprobe) */
+ execvp("dmeventd", NULL);
exit(EXIT_FAILURE);
} else {
if (waitpid(pid, &status, 0) < 0)
- log_error("Unable to start dmeventd: %s", strerror(errno));
+ log_error("Unable to start dmeventd: %s",
+ strerror(errno));
else if (WEXITSTATUS(status))
log_error("Unable to start dmeventd.");
else
@@ -281,8 +351,8 @@ start_server:
/* Initialize client. */
static int init_client(struct dm_event_fifos *fifos)
{
- /* FIXME Is fifo the most suitable method? */
- /* FIXME Why not share comms/daemon code with something else e.g. multipath? */
+ /* FIXME? Is fifo the most suitable method? Why not share
+ comms/daemon code with something else e.g. multipath? */
/* init fifos */
memset(fifos, 0, sizeof(*fifos));
@@ -297,20 +367,19 @@ static int init_client(struct dm_event_fifos *fifos)
/* Open the fifo used to read from the daemon. */
if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
log_error("%s: open server fifo %s",
- __func__, fifos->server_path);
+ __func__, fifos->server_path);
stack;
return 0;
}
/* Lock out anyone else trying to do communication with the daemon. */
- if (flock(fifos->server, LOCK_EX) < 0){
+ if (flock(fifos->server, LOCK_EX) < 0) {
log_error("%s: flock %s", __func__, fifos->server_path);
close(fifos->server);
return 0;
}
-/* if ((fifos->client = open(fifos->client_path,
- O_WRONLY | O_NONBLOCK)) < 0) {*/
+/* if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/
if ((fifos->client = open(fifos->client_path, O_RDWR | O_NONBLOCK)) < 0) {
log_error("%s: Can't open client fifo %s: %s",
__func__, fifos->client_path, strerror(errno));
@@ -318,7 +387,7 @@ static int init_client(struct dm_event_fifos *fifos)
stack;
return 0;
}
-
+
return 1;
}
@@ -331,65 +400,72 @@ static void dtr_client(struct dm_event_fifos *fifos)
close(fifos->server);
}
-/* Check, if a block device exists. */
-static int device_exists(const char *device)
+/* Get uuid of a device, if it exists (otherwise NULL). */
+static struct dm_task *get_device_info(const struct dm_event_handler *h)
{
- struct stat st_buf;
- char path2[PATH_MAX];
-
- if (!device)
- return 0;
-
- if (device[0] == '/') /* absolute path */
- return !stat(device, &st_buf) && S_ISBLK(st_buf.st_mode);
+ struct dm_task *dmt = dm_task_create(DM_DEVICE_INFO);
+ struct dm_task *ret;
+
+ if (!dmt)
+ 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 (PATH_MAX <= snprintf(path2, PATH_MAX, "%s/%s", dm_dir(), device))
- return 0;
+ if (!dm_task_run(dmt))
+ ret = NULL;
+ else
+ ret = dmt;
- return !stat(path2, &st_buf) && S_ISBLK(st_buf.st_mode);
+ return ret;
}
/* 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)
+ const char *dso_name, const char *device,
+ enum dm_event_type events, uint32_t timeout)
{
int ret;
struct dm_event_fifos fifos;
- /* FIXME Start the daemon here if it's not running e.g. exclusive lock file */
- /* FIXME Move this to separate 'dm_event_register_handler' - if no daemon here, fail */
if (!init_client(&fifos)) {
stack;
return -ESRCH;
}
- /* FIXME Use separate 'dm_event_register_handler' function to pass in dso? */
ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
/* what is the opposite of init? */
dtr_client(&fifos);
-
+
return ret;
}
-/* FIXME remove dso_name - use handle instead */
-/* FIXME Use uuid not path! */
/* External library interface. */
-int dm_event_register(const char *dso_name, const char *device_path,
- enum dm_event_type events)
+int dm_event_register(const struct dm_event_handler *h)
{
int ret, err;
+ const char *uuid;
+ struct dm_task *dmt;
struct dm_event_daemon_message msg;
- if (!device_exists(device_path)) {
- log_error("%s: device not found", device_path);
+ if (!(dmt = get_device_info(h))) {
+ log_error("%s: device not found", h->device);
return 0;
}
+ uuid = dm_task_get_uuid(dmt);
+
if ((err = do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
- dso_name, device_path, events, 0)) < 0) {
- log_error("%s: event registration failed: %s", device_path,
+ h->dso, uuid, h->events, 0)) < 0) {
+ log_error("%s: event registration failed: %s",
+ dm_task_get_name(dmt),
msg.data ? msg.data : strerror(-err));
ret = 0;
} else
@@ -398,23 +474,29 @@ int dm_event_register(const char *dso_name, const char *device_path,
if (msg.data)
dm_free(msg.data);
+ dm_task_destroy(dmt);
+
return ret;
}
-int dm_event_unregister(const char *dso_name, const char *device_path,
- enum dm_event_type events)
+int dm_event_unregister(const struct dm_event_handler *h)
{
int ret, err;
+ const char *uuid;
+ struct dm_task *dmt;
struct dm_event_daemon_message msg;
- if (!device_exists(device_path)) {
- log_error("%s: device not found", device_path);
+ if (!(dmt = get_device_info(h))) {
+ log_error("%s: device not found", dm_task_get_name(dmt));
return 0;
}
+ uuid = dm_task_get_uuid(dmt);
+
if ((err = do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
- dso_name, device_path, events, 0)) < 0) {
- log_error("%s: event deregistration failed: %s", device_path,
+ h->dso, uuid, h->events, 0)) < 0) {
+ log_error("%s: event deregistration failed: %s",
+ dm_task_get_name(dmt),
msg.data ? msg.data : strerror(-err));
ret = 0;
} else
@@ -422,9 +504,48 @@ int dm_event_unregister(const char *dso_name, const char *device_path,
if (msg.data)
dm_free(msg.data);
+
+ dm_task_destroy(dmt);
+
+ 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)
+{
+ char *p, *ret;
+
+ if ((p = strchr(*src, delimiter)))
+ *p = 0;
+
+ if ((ret = dm_strdup(*src)))
+ *src += strlen(ret) + 1;
+
+ if (p)
+ *p = delimiter;
+
return ret;
}
+/* 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)
+{
+ char *p = msg->data;
+
+ if ((*dso_name = fetch_string(&p)) && (*device = fetch_string(&p))) {
+ *events = atoi(p);
+
+ return 0;
+ }
+
+ return -ENOMEM;
+}
+
/*
* dm_event_get_registered_device
* @dso_name
@@ -437,18 +558,18 @@ int dm_event_unregister(const char *dso_name, const char *device_path,
* Returns: 1 if device found, 0 otherwise (even on error)
*/
int dm_event_get_registered_device(char **dso_name, char **device_path,
- enum dm_event_type *events, int next)
+ enum dm_event_type *events, int next)
{
int ret;
char *dso_name_arg = NULL, *device_path_arg = NULL;
struct dm_event_daemon_message msg;
if (!(ret = do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
- DM_EVENT_CMD_GET_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 */
+ } else /* FIXME: Make sure this is ENOENT */
ret = 0;
if (msg.data)
@@ -488,9 +609,11 @@ 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, 0, 0)))
+ if (!(ret = do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
+ 0, 0)))
*timeout = atoi(msg.data);
if (msg.data)
dm_free(msg.data);
return ret;
}
+#endif
diff --git a/daemons/dmeventd/libdevmapper-event.h b/daemons/dmeventd/libdevmapper-event.h
index 77460fcc6..151b17884 100644
--- a/daemons/dmeventd/libdevmapper-event.h
+++ b/daemons/dmeventd/libdevmapper-event.h
@@ -24,50 +24,70 @@
#include <stdint.h>
/* Event type definitions. */
-/* FIXME Use masks to separate the types and provide for extension. */
enum dm_event_type {
- DM_EVENT_SINGLE = 0x01, /* Report multiple errors just once. */
- DM_EVENT_MULTI = 0x02, /* Report all of them. */
+ DM_EVENT_SETTINGS_MASK = 0x0000FF,
+ DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
+ DM_EVENT_MULTI = 0x000002, /* Report all of them. */
- DM_EVENT_SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
- DM_EVENT_DEVICE_ERROR = 0x08, /* Device failure. */
- DM_EVENT_PATH_ERROR = 0x10, /* Failure on an io path. */
- DM_EVENT_ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
+ DM_EVENT_ERROR_MASK = 0x00FF00,
+ 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_SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
- DM_EVENT_TIMEOUT = 0x80, /* Timeout has occured */
- DM_EVENT_REGISTRATION_PENDING = 0X100, /* Monitor thread is setting-up/shutting-down */
+ DM_EVENT_STATUS_MASK = 0xFF0000,
+ DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
+ DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occured */
+
+ DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */
};
-/* FIXME Use a mask. */
-#define DM_EVENT_ALL_ERRORS (DM_EVENT_SECTOR_ERROR | DM_EVENT_DEVICE_ERROR | \
- DM_EVENT_PATH_ERROR | DM_EVENT_ADAPTOR_ERROR)
+#define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK
/* Prototypes for event lib interface. */
-/* FIXME Replace device with standard name/uuid/devno choice */
-/* Interface changes:
- First register a handler, passing in a unique ref for the device. */
-
-// int dm_event_register_handler(const char *dso_name, const char *device);
-// int dm_event_register(const char *dso_name, const char *name, const char *uuid, uint32_t major, uint32_t minor, enum dm_event_type events);
-
-/* Or (better?) add to task structure and use existing functions - run
- a task to register/unregister events - we may need to run task
- withe that with the new event mechanism anyway, then the dso calls
- just hook in. */
-
-int dm_event_register(const char *dso_name, const char *device, enum dm_event_type events);
-int dm_event_unregister(const char *dso_name, const char *device,
- enum dm_event_type events);
-int dm_event_get_registered_device(char **dso_name, char **device,
- enum dm_event_type *events, int next);
-int dm_event_set_timeout(const char *device, uint32_t timeout);
-int dm_event_get_timeout(const char *device, uint32_t *timeout);
-
-/* Prototypes for DSO interface. */
-void process_event(const char *device, enum dm_event_type event);
-int register_device(const char *device);
-int unregister_device(const char *device);
+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);
+
+/* 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);
+
+/* 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);
+
+/* 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);
+
+/* 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,
+ int minor);
#endif
diff --git a/libdm/.exported_symbols b/libdm/.exported_symbols
index 34a623ad9..93046fa32 100644
--- a/libdm/.exported_symbols
+++ b/libdm/.exported_symbols
@@ -115,3 +115,4 @@ dm_split_lvm_name
dm_split_words
dm_snprintf
dm_basename
+dm_saprintf
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 3fda02a7c..ece360493 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -623,4 +623,10 @@ int dm_snprintf(char *buf, size_t bufsize, const char *format, ...);
*/
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.
+ */
+int dm_saprintf(char **buf, const char *format, ...);
+
#endif /* LIB_DEVICE_MAPPER_H */
diff --git a/libdm/libdm-string.c b/libdm/libdm-string.c
index 098fc0d9d..65b1c12ad 100644
--- a/libdm/libdm-string.c
+++ b/libdm/libdm-string.c
@@ -129,3 +129,33 @@ char *dm_basename(const char *path)
return p ? p + 1 : (char *) path;
}
+int dm_saprintf(char **result, const char *format, ...)
+{
+ int n, ok = 0, size = 32;
+ va_list ap;
+ char *buf = dm_malloc(size);
+
+ *result = 0;
+
+ if (!buf)
+ return -1;
+
+ while (!ok) {
+ va_start(ap, format);
+ n = vsnprintf(buf, size, format, ap);
+ if (0 <= n && n < size)
+ ok = 1;
+ else {
+ dm_free(buf);
+ size *= 2;
+ buf = dm_malloc(size);
+ if (!buf)
+ return -1;
+ };
+ va_end(ap);
+ }
+
+ *result = dm_strdup(buf);
+ dm_free(buf);
+ return n + 1;
+}