mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
dmeventd updates
This commit is contained in:
parent
774ed5fc39
commit
dd3ec4e87a
@ -1,3 +1,5 @@
|
||||
process_event
|
||||
register_device
|
||||
unregister_device
|
||||
dm_register_for_event
|
||||
dm_unregister_for_event
|
||||
dm_get_registered_device
|
||||
dm_set_event_timeout
|
||||
dm_get_event_timeout
|
||||
|
@ -1,51 +1,56 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the device-mapper userspace tools.
|
||||
#
|
||||
# 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.
|
||||
# of the GNU Lesser General Public License v.2.1.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# You should have received a copy of the GNU Lesser 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
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
interface = @interface@
|
||||
|
||||
TARGETS = dmevent dmeventd
|
||||
INSTALL_TYPE = install_dynamic
|
||||
SOURCES = libdevmapper-event.c \
|
||||
dmeventd.c
|
||||
|
||||
SOURCES = noop.c
|
||||
CLEAN_TARGETS = dmevent.o dmeventd.o
|
||||
LIB_STATIC = libdevmapper-event.a
|
||||
|
||||
ifeq ("@LIB_SUFFIX@","dylib")
|
||||
LIB_SHARED = libdmeventdnoop.dylib
|
||||
LIB_SHARED = libdevmapper-event.dylib
|
||||
else
|
||||
LIB_SHARED = libdmeventdnoop.so
|
||||
LIB_SHARED = libdevmapper-event.so
|
||||
endif
|
||||
|
||||
LDFLAGS += -ldl -ldevmapper -lmultilog
|
||||
|
||||
CLDFLAGS += -ldl -ldevmapper -lpthread
|
||||
|
||||
include ../make.tmpl
|
||||
|
||||
libdmeventdnoop.so: noop.o
|
||||
.PHONY: install_dynamic install_static
|
||||
|
||||
dmevent: dmevent.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
|
||||
$(CC) -o $@ dmevent.o $(LDFLAGS) \
|
||||
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog $(LIBS)
|
||||
INSTALL_TYPE = install_dynamic
|
||||
|
||||
dmeventd: dmeventd.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
|
||||
$(CC) -o $@ dmeventd.o $(LDFLAGS) \
|
||||
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -lpthread -ldmevent $(LIBS)
|
||||
ifeq ("@STATIC_LINK@", "yes")
|
||||
INSTALL_TYPE += install_static
|
||||
endif
|
||||
|
||||
install: $(INSTALL_TYPE)
|
||||
|
||||
.PHONY: install_dynamic
|
||||
install_dynamic: libdevmapper-event.$(LIB_SUFFIX)
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION)
|
||||
$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \
|
||||
$(libdir)/libdevmapper-event.$(LIB_SUFFIX)
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \
|
||||
$(includedir)/libdevmapper-event.h
|
||||
|
||||
install_dynamic: dmeventd
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) dmeventd $(sbindir)/dmeventd
|
||||
install_static: libdevmapper-event.a
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/libdevmapper-event.a.$(LIB_VERSION)
|
||||
$(LN_S) -f libdevmapper-event.a.$(LIB_VERSION) $(libdir)/libdevmapper-event.a
|
||||
|
||||
|
@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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 Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 "libdm-event.h"
|
||||
#include "libmultilog.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
static enum event_type events = ALL_ERRORS; /* All until we can distinguish. */
|
||||
static char default_dso_name[] = "noop"; /* default DSO is noop */
|
||||
static int default_reg = 1; /* default action is register */
|
||||
static uint32_t timeout;
|
||||
|
||||
struct event_ops {
|
||||
int (*dm_register_for_event)(char *dso_name, char *device,
|
||||
enum event_type event_types);
|
||||
int (*dm_unregister_for_event)(char *dso_name, char *device,
|
||||
enum event_type event_types);
|
||||
int (*dm_get_registered_device)(char **dso_name, char **device,
|
||||
enum event_type *event_types, int next);
|
||||
int (*dm_set_event_timeout)(char *device, uint32_t time);
|
||||
int (*dm_get_event_timeout)(char *device, uint32_t *time);
|
||||
};
|
||||
|
||||
/* Display help. */
|
||||
static void print_usage(char *name)
|
||||
{
|
||||
char *cmd = strrchr(name, '/');
|
||||
|
||||
cmd = cmd ? cmd + 1 : name;
|
||||
printf("Usage::\n"
|
||||
"%s [options] <device>\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -d <dso> Specify the DSO to use.\n"
|
||||
" -h Print this usage.\n"
|
||||
" -l List registered devices.\n"
|
||||
" -r Register for event (default).\n"
|
||||
" -t <timeout> (un)register for timeout event.\n"
|
||||
" -u Unregister for event.\n"
|
||||
"\n", cmd);
|
||||
}
|
||||
|
||||
/* Parse command line arguments. */
|
||||
static int parse_argv(int argc, char **argv, char **dso_name_arg,
|
||||
char **device_arg, int *reg, int *list)
|
||||
{
|
||||
int c;
|
||||
const char *options = "d:hlrt:u";
|
||||
|
||||
while ((c = getopt(argc, argv, options)) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
*dso_name_arg = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'l':
|
||||
*list = 1;
|
||||
break;
|
||||
case 'r':
|
||||
*reg = 1;
|
||||
break;
|
||||
case 't':
|
||||
events = TIMEOUT;
|
||||
if (sscanf(optarg, "%"SCNu32, &timeout) != 1){
|
||||
fprintf(stderr, "invalid timeout '%s'\n",
|
||||
optarg);
|
||||
timeout = 0;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
*reg = 0;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown option '%c'.\n"
|
||||
"Try '-h' for help.\n", c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
if (!*list) {
|
||||
fprintf(stderr, "You need to specify a device.\n");
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
*device_arg = argv[optind];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int lookup_symbol(void *dl, void **symbol, const char *name)
|
||||
{
|
||||
if ((*symbol = dlsym(dl, name)))
|
||||
return 1;
|
||||
|
||||
fprintf(stderr, "error looking up %s symbol: %s\n", name, dlerror());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lookup_symbols(void *dl, struct event_ops *e)
|
||||
{
|
||||
return lookup_symbol(dl, (void *) &e->dm_register_for_event,
|
||||
"dm_register_for_event") &&
|
||||
lookup_symbol(dl, (void *) &e->dm_unregister_for_event,
|
||||
"dm_unregister_for_event") &&
|
||||
lookup_symbol(dl, (void *) &e->dm_get_registered_device,
|
||||
"dm_get_registered_device") &&
|
||||
lookup_symbol(dl, (void *) &e->dm_set_event_timeout,
|
||||
"dm_set_event_timeout") &&
|
||||
lookup_symbol(dl, (void *) &e->dm_get_event_timeout,
|
||||
"dm_get_event_timeout");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
void *dl;
|
||||
struct event_ops e;
|
||||
int list = 0, next = 0, ret, reg = default_reg;
|
||||
char *device, *device_arg = NULL, *dso_name, *dso_name_arg = NULL;
|
||||
|
||||
if (!parse_argv(argc, argv, &dso_name_arg, &device_arg, ®, &list))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (device_arg) {
|
||||
if (!(device = strdup(device_arg)))
|
||||
exit(EXIT_FAILURE);
|
||||
} else
|
||||
device = NULL;
|
||||
|
||||
if (dso_name_arg) {
|
||||
if (!(dso_name = strdup(dso_name_arg)))
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
if (!(dso_name = strdup(default_dso_name)))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* FIXME: use -v/-q options to set this */
|
||||
multilog_add_type(standard, NULL);
|
||||
multilog_init_verbose(standard, _LOG_DEBUG);
|
||||
|
||||
if (!(dl = dlopen("libdmevent.so", RTLD_NOW))){
|
||||
fprintf(stderr, "Cannot dlopen libdmevent.so: %s\n", dlerror());
|
||||
goto out;
|
||||
}
|
||||
if (!(lookup_symbols(dl, &e)))
|
||||
goto out;
|
||||
if (list) {
|
||||
while (1) {
|
||||
if ((ret= e.dm_get_registered_device(&dso_name,
|
||||
&device,
|
||||
&events, next)))
|
||||
break;
|
||||
printf("%s %s 0x%x", dso_name, device, events);
|
||||
if (events & TIMEOUT){
|
||||
if ((ret = e.dm_get_event_timeout(device,
|
||||
&timeout))) {
|
||||
ret = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
printf(" %"PRIu32"\n", timeout);
|
||||
} else
|
||||
printf("\n");
|
||||
if (device_arg)
|
||||
break;
|
||||
|
||||
next = 1;
|
||||
}
|
||||
|
||||
ret = (ret && device_arg) ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((ret = reg ? e.dm_register_for_event(dso_name, device, events) :
|
||||
e.dm_unregister_for_event(dso_name, device, events))) {
|
||||
fprintf(stderr, "Failed to %sregister %s: %s\n",
|
||||
reg ? "": "un", device, strerror(-ret));
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
if (reg && (events & TIMEOUT) &&
|
||||
((ret = e.dm_set_event_timeout(device, timeout)))){
|
||||
fprintf(stderr, "Failed to set timeout for %s: %s\n",
|
||||
device, strerror(-ret));
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
printf("%s %sregistered successfully.\n",
|
||||
device, reg ? "" : "un");
|
||||
ret = EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
multilog_del_type(standard);
|
||||
|
||||
if (device)
|
||||
free(device);
|
||||
if (dso_name)
|
||||
free(dso_name);
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
12
daemons/dmeventd/dmeventd.h
Normal file
12
daemons/dmeventd/dmeventd.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef __DMEVENTD_DOT_H__
|
||||
#define __DMEVENTD_DOT_H__
|
||||
|
||||
#define EXIT_LOCKFILE_INUSE 2
|
||||
#define EXIT_DESC_CLOSE_FAILURE 3
|
||||
#define EXIT_OPEN_PID_FAILURE 4
|
||||
#define EXIT_FIFO_FAILURE 5
|
||||
#define EXIT_CHDIR_FAILURE 6
|
||||
|
||||
void dmeventd(void);
|
||||
|
||||
#endif /* __DMEVENTD_DOT_H__ */
|
465
daemons/dmeventd/libdevmapper-event.c
Normal file
465
daemons/dmeventd/libdevmapper-event.c
Normal file
@ -0,0 +1,465 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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 Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 "lib.h"
|
||||
#include "libdevmapper-event.h"
|
||||
//#include "libmultilog.h"
|
||||
#include "dmeventd.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
/* Set by any of the external fxns the first time one of them is called */
|
||||
/* FIXME Unused */
|
||||
// static int _logging = 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)
|
||||
{
|
||||
char *p, *ret;
|
||||
|
||||
if ((p = strchr(*src, delimiter)))
|
||||
*p = 0;
|
||||
|
||||
if ((ret = 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->msg;
|
||||
|
||||
if ((*dso_name = fetch_string(&p)) &&
|
||||
(*device = fetch_string(&p))) {
|
||||
*events = atoi(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Read message from daemon. */
|
||||
static int daemon_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
|
||||
{
|
||||
int bytes = 0, ret = 0;
|
||||
fd_set fds;
|
||||
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
errno = 0;
|
||||
/* FIXME Fix error handling. Check 'ret' before errno. EINTR? EAGAIN? */
|
||||
/* FIXME errno != EOF? RTFM! */
|
||||
while (bytes < sizeof(*msg) && errno != EOF) {
|
||||
do {
|
||||
/* Watch daemon read FIFO for input. */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fifos->server, &fds);
|
||||
/* FIXME Check for errors e.g. EBADF */
|
||||
} while (select(fifos->server+1, &fds, NULL, NULL, NULL) != 1);
|
||||
|
||||
ret = read(fifos->server, msg, sizeof(*msg) - bytes);
|
||||
bytes += ret > 0 ? ret : 0;
|
||||
}
|
||||
|
||||
// log_print("%s: \"%s\"\n", __func__, msg->msg);
|
||||
return bytes == sizeof(*msg);
|
||||
}
|
||||
|
||||
/* Write message to daemon. */
|
||||
static int daemon_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
|
||||
{
|
||||
int bytes = 0, ret = 0;
|
||||
fd_set fds;
|
||||
|
||||
|
||||
// log_print("%s: \"%s\"\n", __func__, msg->msg);
|
||||
errno = 0;
|
||||
/* FIXME Fix error handling. Check 'ret' before errno. EINTR? EAGAIN? */
|
||||
while (bytes < sizeof(*msg) && errno != EIO) {
|
||||
do {
|
||||
/* Watch daemon write FIFO to be ready for output. */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fifos->client, &fds);
|
||||
/* FIXME Check for errors e.g. EBADF */
|
||||
} while (select(fifos->client +1, NULL, &fds, NULL, NULL) != 1);
|
||||
|
||||
ret = write(fifos->client, msg, sizeof(*msg) - bytes);
|
||||
bytes += ret > 0 ? ret : 0;
|
||||
}
|
||||
|
||||
return bytes == sizeof(*msg);
|
||||
}
|
||||
|
||||
static int daemon_talk(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg,
|
||||
int cmd, char *dso_name, char *device,
|
||||
enum dm_event_type events, uint32_t timeout)
|
||||
{
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
|
||||
/*
|
||||
* Set command and pack the arguments
|
||||
* into ASCII message string.
|
||||
*/
|
||||
msg->opcode.cmd = cmd;
|
||||
|
||||
if (sizeof(msg->msg) <= snprintf(msg->msg, sizeof(msg->msg),
|
||||
"%s %s %u %"PRIu32,
|
||||
dso_name ? dso_name : "",
|
||||
device ? device : "",
|
||||
events, timeout)) {
|
||||
stack;
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write command and message to and
|
||||
* read status return code from daemon.
|
||||
*/
|
||||
if (!daemon_write(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!daemon_read(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return msg->opcode.status;
|
||||
}
|
||||
|
||||
static volatile sig_atomic_t daemon_running = 0;
|
||||
|
||||
static void daemon_running_signal_handler(int sig)
|
||||
{
|
||||
daemon_running = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* start_daemon
|
||||
*
|
||||
* This function forks off a process (dmeventd) that will handle
|
||||
* the events. A signal must be returned from the child to
|
||||
* indicate when it is ready to handle requests. The parent
|
||||
* (this function) returns 1 if there is a daemon running.
|
||||
*
|
||||
* Returns: 1 on success, 0 otherwise
|
||||
*/
|
||||
static int start_daemon(void)
|
||||
{
|
||||
int pid, ret=0;
|
||||
int old_mask;
|
||||
void *old_hand;
|
||||
|
||||
/* Must be able to acquire signal */
|
||||
old_hand = signal(SIGUSR1, &daemon_running_signal_handler);
|
||||
if (old_hand == SIG_ERR) {
|
||||
log_error("Unable to setup signal handler.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
/* FIXME Deprecated. Try posix sigprocmask instead. */
|
||||
old_mask = siggetmask();
|
||||
old_mask &= ~sigmask(SIGUSR1);
|
||||
old_mask = sigsetmask(old_mask);
|
||||
#endif
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0)
|
||||
log_error("Unable to fork.\n");
|
||||
else if (pid) { /* parent waits for child to get ready for requests */
|
||||
int status;
|
||||
|
||||
/* FIXME Better way to do this? */
|
||||
while (!waitpid(pid, &status, WNOHANG) && !daemon_running)
|
||||
sleep(1);
|
||||
|
||||
if (daemon_running) {
|
||||
log_print("dmeventd started.\n");
|
||||
ret = 1;
|
||||
} else {
|
||||
switch (WEXITSTATUS(status)) {
|
||||
case EXIT_LOCKFILE_INUSE:
|
||||
/*
|
||||
* Note, this is ok... we still have daemon
|
||||
* that we can communicate with...
|
||||
*/
|
||||
log_print("Starting dmeventd failed: "
|
||||
"dmeventd already running.\n");
|
||||
ret = 1;
|
||||
break;
|
||||
default:
|
||||
log_error("Unable to start dmeventd.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
signal(SIGUSR1, SIG_IGN); /* don't care about error */
|
||||
|
||||
/* dmeventd function is responsible for properly setting **
|
||||
** itself up. It must never return - only exit. This is**
|
||||
** why it is followed by an EXIT_FAILURE */
|
||||
dmeventd();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* FIXME What if old_hand is SIG_ERR? */
|
||||
if (signal(SIGUSR1, old_hand) == SIG_ERR)
|
||||
log_error("Unable to reset signal handler.");
|
||||
sigsetmask(old_mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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? */
|
||||
|
||||
/* init fifos */
|
||||
memset(fifos, 0, sizeof(*fifos));
|
||||
fifos->client_path = DM_EVENT_FIFO_CLIENT;
|
||||
fifos->server_path = DM_EVENT_FIFO_SERVER;
|
||||
|
||||
/* FIXME The server should be responsible for these, not the client. */
|
||||
/* Create fifos */
|
||||
if (((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) ||
|
||||
((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST)) {
|
||||
log_error("%s: Failed to create a fifo.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Warn/abort if perms are wrong - not something to fix silently. */
|
||||
/* If they were already there, make sure permissions are ok. */
|
||||
if (chmod(fifos->client_path, 0600)) {
|
||||
log_error("Unable to set correct file permissions on %s",
|
||||
fifos->client_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (chmod(fifos->server_path, 0600)) {
|
||||
log_error("Unable to set correct file permissions on %s",
|
||||
fifos->server_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the fifo used to read from the daemon.
|
||||
* Allows daemon to create its write fifo...
|
||||
*/
|
||||
if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
|
||||
log_error("%s: open server fifo %s\n",
|
||||
__func__, fifos->server_path);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lock out anyone else trying to do communication with the daemon. */
|
||||
/* FIXME Why failure not retry? How do multiple processes communicate? */
|
||||
if (flock(fifos->server, LOCK_EX) < 0){
|
||||
log_error("%s: flock %s\n", __func__, fifos->server_path);
|
||||
close(fifos->server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Anyone listening? If not, errno will be ENXIO */
|
||||
if ((fifos->client = open(fifos->client_path,
|
||||
O_WRONLY | O_NONBLOCK)) < 0) {
|
||||
if (errno != ENXIO) {
|
||||
log_error("%s: open client fifo %s\n",
|
||||
__func__, fifos->client_path);
|
||||
close(fifos->server);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Unnecessary if daemon was started before calling this */
|
||||
if (!start_daemon()) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Unnecessary if daemon was started before calling this */
|
||||
/* Daemon is started, retry the open */
|
||||
fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
|
||||
if (fifos->client < 0) {
|
||||
log_error("%s: open client fifo %s\n",
|
||||
__func__, fifos->client_path);
|
||||
close(fifos->server);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dtr_client(struct dm_event_fifos *fifos)
|
||||
{
|
||||
if (flock(fifos->server, LOCK_UN))
|
||||
log_error("flock unlock %s\n", fifos->server_path);
|
||||
|
||||
close(fifos->client);
|
||||
close(fifos->server);
|
||||
}
|
||||
|
||||
/* Check, if a block device exists. */
|
||||
static int device_exists(char *device)
|
||||
{
|
||||
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);
|
||||
|
||||
if (PATH_MAX <= snprintf(path2, PATH_MAX, "%s/%s", dm_dir(), device))
|
||||
return 0;
|
||||
|
||||
return !stat(path2, &st_buf) && S_ISBLK(st_buf.st_mode);
|
||||
}
|
||||
|
||||
/* Handle the event (de)registration call and return negative error codes. */
|
||||
static int do_event(int cmd, struct dm_event_daemon_message *msg,
|
||||
char *dso_name, 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 */
|
||||
|
||||
if (!init_client(&fifos)) {
|
||||
stack;
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
|
||||
|
||||
/* what is the opposite of init? */
|
||||
dtr_client(&fifos);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* External library interface. */
|
||||
int dm_event_register(char *dso_name, char *device_path,
|
||||
enum dm_event_type events)
|
||||
{
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
|
||||
return do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
|
||||
dso_name, device_path, events, 0);
|
||||
}
|
||||
|
||||
int dm_event_unregister(char *dso_name, char *device_path,
|
||||
enum dm_event_type events)
|
||||
{
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
|
||||
return do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
|
||||
dso_name, device_path, events, 0);
|
||||
}
|
||||
|
||||
int dm_event_get_registered_device(char **dso_name, char **device_path,
|
||||
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,
|
||||
&msg, *dso_name, *device_path, *events, 0)))
|
||||
ret = parse_message(&msg, &dso_name_arg, &device_path_arg,
|
||||
events);
|
||||
|
||||
if (next){
|
||||
if (*dso_name)
|
||||
free(*dso_name);
|
||||
if (*device_path)
|
||||
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;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dm_event_set_timeout(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,
|
||||
NULL, device_path, 0, timeout);
|
||||
}
|
||||
|
||||
int dm_event_get_timeout(char *device_path, uint32_t *timeout)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
if (!(ret = do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path, 0, 0)))
|
||||
*timeout = atoi(msg.msg);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
99
daemons/dmeventd/libdevmapper-event.h
Normal file
99
daemons/dmeventd/libdevmapper-event.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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 Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that this file is released only as part of a technology preview
|
||||
* and its contents may change in future updates in ways that do not
|
||||
* preserve compatibility.
|
||||
*/
|
||||
|
||||
#ifndef LIB_DMEVENT_H
|
||||
#define LIB_DMEVENT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* FIXME This stuff must be configurable. */
|
||||
|
||||
#define DM_EVENT_DAEMON "/sbin/dmeventd"
|
||||
#define DM_EVENT_LOCKFILE "/var/lock/dmeventd"
|
||||
#define DM_EVENT_FIFO_CLIENT "/var/run/dmeventd-client"
|
||||
#define DM_EVENT_FIFO_SERVER "/var/run/dmeventd-server"
|
||||
#define DM_EVENT_PIDFILE "/var/run/dmeventd.pid"
|
||||
|
||||
#define DM_EVENT_DEFAULT_TIMEOUT 10
|
||||
|
||||
/* Commands for the daemon passed in the message below. */
|
||||
enum dm_event_command {
|
||||
DM_EVENT_CMD_ACTIVE = 1,
|
||||
DM_EVENT_CMD_REGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_SET_TIMEOUT,
|
||||
DM_EVENT_CMD_GET_TIMEOUT,
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
struct dm_event_daemon_message {
|
||||
union {
|
||||
unsigned int cmd; /* FIXME Use fixed size. */
|
||||
int status; /* FIXME Use fixed size. */
|
||||
} opcode;
|
||||
char msg[252]; /* FIXME Why is this 252 ? */
|
||||
} __attribute__((packed)); /* FIXME Do this properly! */
|
||||
|
||||
/* FIXME Is this meant to be exported? I can't see where the interface uses it. */
|
||||
/* Fifos for client/daemon communication. */
|
||||
struct dm_event_fifos {
|
||||
int client;
|
||||
int server;
|
||||
const char *client_path;
|
||||
const char *server_path;
|
||||
};
|
||||
|
||||
/* 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_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_SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
|
||||
DM_EVENT_TIMEOUT = 0x80, /* Timeout has occured */
|
||||
};
|
||||
|
||||
/* 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)
|
||||
|
||||
/* Prototypes for event lib interface. */
|
||||
/* FIXME Missing consts? */
|
||||
int dm_event_register(char *dso_name, char *device, enum dm_event_type events);
|
||||
int dm_event_unregister(char *dso_name, 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(char *device, uint32_t timeout);
|
||||
int dm_event_get_timeout(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);
|
||||
|
||||
#endif
|
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Create test devices for dmeventd
|
||||
#
|
||||
|
||||
trap "rm -f /tmp/tmp.$$" 0 1 2 3 15
|
||||
|
||||
echo "0 1024 zero" > /tmp/tmp.$$
|
||||
dmsetup create test /tmp/tmp.$$
|
||||
dmsetup create test1 /tmp/tmp.$$
|
||||
|
||||
kill -15 $$
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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 Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 "libdm-event.h"
|
||||
#include "libmultilog.h"
|
||||
|
||||
|
||||
void process_event(char *device, enum event_type event)
|
||||
{
|
||||
log_err("[%s] %s(%d) - Device: %s, Event %d\n",
|
||||
__FILE__, __func__, __LINE__, device, event);
|
||||
}
|
||||
|
||||
int register_device(char *device)
|
||||
{
|
||||
log_err("[%s] %s(%d) - Device: %s\n",
|
||||
__FILE__, __func__, __LINE__, device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unregister_device(char *device)
|
||||
{
|
||||
log_err("[%s] %s(%d) - Device: %s\n",
|
||||
__FILE__, __func__, __LINE__, device);
|
||||
|
||||
return 1;
|
||||
}
|
@ -17,14 +17,6 @@ top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
interface = @interface@
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
SUBDIRS += event
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS += event
|
||||
endif
|
||||
|
||||
SOURCES =\
|
||||
datastruct/bitset.c \
|
||||
datastruct/hash.c \
|
||||
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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 Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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
|
||||
*/
|
||||
|
||||
#ifndef LIB_DMEVENT_H
|
||||
#define LIB_DMEVENT_H
|
||||
|
||||
#include "list.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DAEMON "/sbin/dmeventd"
|
||||
#define LOCKFILE "/var/lock/dmeventd"
|
||||
#define FIFO_CLIENT "/var/run/dmeventd-client"
|
||||
#define FIFO_SERVER "/var/run/dmeventd-server"
|
||||
#define PIDFILE "/var/run/dmeventd.pid"
|
||||
|
||||
#define DEFAULT_TIMEOUT 10
|
||||
/* Commands for the daemon passed in the message below. */
|
||||
enum dmeventd_command {
|
||||
CMD_ACTIVE = 1,
|
||||
CMD_REGISTER_FOR_EVENT,
|
||||
CMD_UNREGISTER_FOR_EVENT,
|
||||
CMD_GET_REGISTERED_DEVICE,
|
||||
CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
CMD_SET_TIMEOUT,
|
||||
CMD_GET_TIMEOUT,
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
struct daemon_message {
|
||||
union {
|
||||
unsigned int cmd;
|
||||
int status;
|
||||
} opcode;
|
||||
char msg[252];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Fifos for client/daemon communication. */
|
||||
struct fifos {
|
||||
int client;
|
||||
int server;
|
||||
const char *client_path;
|
||||
const char *server_path;
|
||||
};
|
||||
|
||||
/* Event type definitions. */
|
||||
enum event_type {
|
||||
SINGLE = 0x01, /* Report multiple errors just once. */
|
||||
MULTI = 0x02, /* Report all of them. */
|
||||
SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
|
||||
DEVICE_ERROR = 0x08, /* Device failure. */
|
||||
PATH_ERROR = 0x10, /* Failure on an io path. */
|
||||
ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
|
||||
SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
|
||||
TIMEOUT = 0x80, /* Timeout has occured */
|
||||
};
|
||||
#define ALL_ERRORS (SECTOR_ERROR | DEVICE_ERROR | PATH_ERROR | ADAPTOR_ERROR)
|
||||
|
||||
/* Prototypes for event lib interface. */
|
||||
int dm_register_for_event(char *dso_name, char *device, enum event_type events);
|
||||
int dm_unregister_for_event(char *dso_name, char *device,
|
||||
enum event_type events);
|
||||
int dm_get_registered_device(char **dso_name, char **device,
|
||||
enum event_type *events, int next);
|
||||
int dm_set_event_timeout(char *device, uint32_t timeout);
|
||||
int dm_get_event_timeout(char *device, uint32_t *timeout);
|
||||
|
||||
/* Prototypes for DSO interface. */
|
||||
void process_event(char *device, enum event_type event);
|
||||
int register_device(char *device);
|
||||
int unregister_device(char *device);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
Loading…
Reference in New Issue
Block a user