r408 - in devmapper/trunk: . dmeventd dmsetup include lib
lib/datastruct lib/ioctl lib/mm man po
Bastian Blank
waldi at alioth.debian.org
Sat Apr 7 09:09:51 UTC 2007
Author: waldi
Date: Sat Apr 7 09:09:48 2007
New Revision: 408
Added:
devmapper/trunk/lib/libdm-common.h
devmapper/trunk/lib/libdm-report.c
Removed:
devmapper/trunk/lib/libdm-common.h.in
Modified:
devmapper/trunk/ (props changed)
devmapper/trunk/VERSION
devmapper/trunk/WHATS_NEW
devmapper/trunk/configure
devmapper/trunk/configure.in
devmapper/trunk/dmeventd/.exported_symbols
devmapper/trunk/dmeventd/Makefile.in
devmapper/trunk/dmeventd/dmeventd.c
devmapper/trunk/dmeventd/dmeventd.h
devmapper/trunk/dmeventd/libdevmapper-event.c
devmapper/trunk/dmeventd/libdevmapper-event.h
devmapper/trunk/dmsetup/Makefile.in
devmapper/trunk/dmsetup/dmsetup.c
devmapper/trunk/include/configure.h.in
devmapper/trunk/lib/.exported_symbols
devmapper/trunk/lib/Makefile.in
devmapper/trunk/lib/datastruct/hash.c
devmapper/trunk/lib/ioctl/libdm-iface.c
devmapper/trunk/lib/libdevmapper.h
devmapper/trunk/lib/libdm-common.c
devmapper/trunk/lib/libdm-deptree.c
devmapper/trunk/lib/libdm-string.c
devmapper/trunk/lib/mm/dbg_malloc.c
devmapper/trunk/make.tmpl.in
devmapper/trunk/man/dmsetup.8
devmapper/trunk/po/device-mapper.po
Log:
Merge /devmapper/upstream/current (1.02.18).
Modified: devmapper/trunk/VERSION
==============================================================================
--- devmapper/trunk/VERSION (original)
+++ devmapper/trunk/VERSION Sat Apr 7 09:09:48 2007
@@ -1 +1 @@
-1.02.12 (2006-10-13)
+1.02.18 (2007-02-13)
Modified: devmapper/trunk/WHATS_NEW
==============================================================================
--- devmapper/trunk/WHATS_NEW (original)
+++ devmapper/trunk/WHATS_NEW Sat Apr 7 09:09:48 2007
@@ -1,3 +1,53 @@
+Version 1.02.18 - 13th February 2007
+====================================
+ Improve dmeventd messaging protocol: drain pipe and tag messages.
+
+Version 1.02.17 - 29th January 2007
+===================================
+ Add recent reporting options to dmsetup man page.
+ Revise some report fields names.
+ Add dmsetup 'help' command and update usage text.
+ Use fixed-size fields in report interface and reorder.
+
+Version 1.02.16 - 25th January 2007
+===================================
+ Add some missing close() and fclose() return value checks.
+ Migrate dmsetup column-based output over to new libdevmapper report framework.
+ Add descriptions to reporting field definitions.
+ Add a dso-private variable to dmeventd dso interface.
+ Add dm_event_handler_[gs]et_timeout functions.
+ Streamline dm_report_field_* interface.
+ Add cmdline debug & version options to dmeventd.
+ Add DM_LIB_VERSION definition to configure.h.
+ Suppress 'Unrecognised field' error if report field is 'help'.
+ Add --separator and --sort to dmsetup (unused).
+ Make alignment flag optional when specifying report fields.
+
+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().
+ Use CFLAGS when linking so mixed sparc builds can supply -m64.
+ Add dm_tree_use_no_flush_suspend().
+ 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.
+
+Version 1.02.13 - 28 Nov 2006
+=============================
+ Update dmsetup man page (setgeometry & message).
+ Fix dmsetup free after getline with debug.
+ Suppress encryption key in 'dmsetup table' output unless --showkeys supplied.
+
Version 1.02.12 - 13 Oct 2006
=============================
Avoid deptree attempting to suspend a device that's already suspended.
Modified: devmapper/trunk/configure
==============================================================================
--- devmapper/trunk/configure (original)
+++ devmapper/trunk/configure Sat Apr 7 09:09:48 2007
@@ -865,12 +865,14 @@
--with-device-uid=UID Set the owner used for new device nodes [UID=0]
--with-device-gid=UID Set the group used for new device nodes [GID=0]
--with-device-mode=MODE Set the mode used for new device nodes [MODE=0600]
- --with-optimisation=OPT C optimisation flag OPT=-O2
- --with-localedir=DIR Translation files in DIR PREFIX/share/locale
+ --with-optimisation=OPT C optimisation flag [OPT=-O2]
+ --with-localedir=DIR Translation files in DIR [PREFIX/share/locale]
--with-kernel-dir=DIR linux kernel source in DIR
--with-kernel-version=VERSION linux kernel version
- --with-tmp-dir=DIR temp directory to make kernel patches /tmp/kerndiff
- --with-interface=IFACE Choose kernel interface (ioctl or fs) ioctl
+ --with-tmp-dir=DIR temp dir to make kernel patches [/tmp/kerndiff]
+ --with-interface=IFACE Choose kernel interface (ioctl or fs) [ioctl]
+ --with-dmeventd-pidfile=PATH dmeventd pidfile [/var/run/dmeventd.pid]
+ --with-dmeventd-path=PATH dmeventd path [${exec_prefix}/sbin/dmeventd]
Some influential environment variables:
CC C compiler command
@@ -6036,6 +6038,56 @@
fi
+cat >>confdefs.h <<_ACEOF
+#define DM_LIB_VERSION $DM_LIB_VERSION
+_ACEOF
+
+
+################################################################################
+
+
+if test "$DMEVENTD" = yes; then
+
+# Check whether --with-dmeventd-pidfile or --without-dmeventd-pidfile was given.
+if test "${with_dmeventd_pidfile+set}" = set; then
+ withval="$with_dmeventd_pidfile"
+ cat >>confdefs.h <<_ACEOF
+#define DMEVENTD_PIDFILE "$withval"
+_ACEOF
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define DMEVENTD_PIDFILE "/var/run/dmeventd.pid"
+_ACEOF
+
+fi;
+fi
+
+
+
+if test "$DMEVENTD" = yes; then
+ dmeventd_prefix="$exec_prefix"
+ if test "x$dmeventd_prefix" = "xNONE"; then
+ dmeventd_prefix="$prefix"
+ fi
+ if test "x$dmeventd_prefix" = "xNONE"; then
+ dmeventd_prefix=""
+ fi
+
+# Check whether --with-dmeventd-path or --without-dmeventd-path was given.
+if test "${with_dmeventd_path+set}" = set; then
+ withval="$with_dmeventd_path"
+ cat >>confdefs.h <<_ACEOF
+#define DMEVENTD_PATH "$withval"
+_ACEOF
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define DMEVENTD_PATH "$dmeventd_pref/sbin/dmeventd"
+_ACEOF
+
+fi;
+fi
################################################################################
@@ -6068,7 +6120,7 @@
################################################################################
- ac_config_files="$ac_config_files Makefile make.tmpl include/Makefile dmsetup/Makefile lib/Makefile lib/libdevmapper.pc lib/libdm-common.h dmeventd/Makefile dmeventd/libdevmapper-event.pc kernel/Makefile man/Makefile po/Makefile"
+ ac_config_files="$ac_config_files Makefile make.tmpl include/Makefile dmsetup/Makefile lib/Makefile lib/libdevmapper.pc dmeventd/Makefile dmeventd/libdevmapper-event.pc kernel/Makefile man/Makefile po/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@@ -6600,7 +6652,6 @@
"dmsetup/Makefile" ) CONFIG_FILES="$CONFIG_FILES dmsetup/Makefile" ;;
"lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
"lib/libdevmapper.pc" ) CONFIG_FILES="$CONFIG_FILES lib/libdevmapper.pc" ;;
- "lib/libdm-common.h" ) CONFIG_FILES="$CONFIG_FILES lib/libdm-common.h" ;;
"dmeventd/Makefile" ) CONFIG_FILES="$CONFIG_FILES dmeventd/Makefile" ;;
"dmeventd/libdevmapper-event.pc" ) CONFIG_FILES="$CONFIG_FILES dmeventd/libdevmapper-event.pc" ;;
"kernel/Makefile" ) CONFIG_FILES="$CONFIG_FILES kernel/Makefile" ;;
Modified: devmapper/trunk/configure.in
==============================================================================
--- devmapper/trunk/configure.in (original)
+++ devmapper/trunk/configure.in Sat Apr 7 09:09:48 2007
@@ -168,7 +168,7 @@
dnl -- Override optimisation
AC_MSG_CHECKING(for C optimisation flag)
AC_ARG_WITH(optimisation,
- [ --with-optimisation=OPT C optimisation flag [OPT=-O2] ],
+ [ --with-optimisation=OPT C optimisation flag [[OPT=-O2]] ],
[ COPTIMISE_FLAG="$withval" ])
AC_MSG_RESULT($COPTIMISE_FLAG)
@@ -262,7 +262,7 @@
fi;
AC_ARG_WITH(localedir,
- [ --with-localedir=DIR Translation files in DIR [PREFIX/share/locale]],
+ [ --with-localedir=DIR Translation files in DIR [[PREFIX/share/locale]] ],
[ LOCALEDIR="$withval" ],
[ LOCALEDIR='${prefix}/share/locale' ])
fi
@@ -328,7 +328,7 @@
################################################################################
dnl -- Temporary directory for kernel diffs
AC_ARG_WITH(tmp-dir,
- [ --with-tmp-dir=DIR temp directory to make kernel patches [/tmp/kerndiff]],
+ [ --with-tmp-dir=DIR temp dir to make kernel patches [[/tmp/kerndiff]] ],
[ tmpdir="$withval" ],
[ tmpdir=/tmp/kerndiff ])
if test "${with_tmp_dir+set}" = set; then
@@ -342,7 +342,7 @@
dnl -- which kernel interface to use (ioctl or fs)
AC_MSG_CHECKING(for kernel interface choice)
AC_ARG_WITH(interface,
- [ --with-interface=IFACE Choose kernel interface (ioctl or fs) [ioctl]],
+ [ --with-interface=IFACE Choose kernel interface (ioctl or fs) [[ioctl]] ],
[ interface="$withval" ],
[ interface=ioctl ])
if [[ "x$interface" != xfs -a "x$interface" != xioctl ]];
@@ -357,8 +357,33 @@
DM_LIB_VERSION="Unknown version ($interface)"
fi
+AC_DEFINE_UNQUOTED(DM_LIB_VERSION, $DM_LIB_VERSION, [Library version])
################################################################################
+dnl -- dmeventd pidfile and executable path
+AH_TEMPLATE(DMEVENTD_PIDFILE, [Path to dmeventd pidfile.])
+if test "$DMEVENTD" = yes; then
+ AC_ARG_WITH(dmeventd-pidfile,
+ [ --with-dmeventd-pidfile=PATH dmeventd pidfile [[/var/run/dmeventd.pid]] ],
+ [ AC_DEFINE_UNQUOTED(DMEVENTD_PIDFILE,"$withval") ],
+ [ AC_DEFINE_UNQUOTED(DMEVENTD_PIDFILE,"/var/run/dmeventd.pid") ])
+fi
+
+AH_TEMPLATE(DMEVENTD_PATH, [Path to dmeventd binary.])
+if test "$DMEVENTD" = yes; then
+ dmeventd_prefix="$exec_prefix"
+ if test "x$dmeventd_prefix" = "xNONE"; then
+ dmeventd_prefix="$prefix"
+ fi
+ if test "x$dmeventd_prefix" = "xNONE"; then
+ dmeventd_prefix=""
+ fi
+ AC_ARG_WITH(dmeventd-path,
+ [ --with-dmeventd-path=PATH dmeventd path [[${exec_prefix}/sbin/dmeventd]] ],
+ [ AC_DEFINE_UNQUOTED(DMEVENTD_PATH,"$withval") ],
+ [ AC_DEFINE_UNQUOTED(DMEVENTD_PATH,"$dmeventd_pref/sbin/dmeventd") ])
+fi
+################################################################################
AC_SUBST(usrlibdir)
AC_SUBST(JOBS)
AC_SUBST(STATIC_LINK)
@@ -399,7 +424,6 @@
dmsetup/Makefile \
lib/Makefile \
lib/libdevmapper.pc \
-lib/libdm-common.h \
dmeventd/Makefile \
dmeventd/libdevmapper-event.pc \
kernel/Makefile \
Modified: devmapper/trunk/dmeventd/.exported_symbols
==============================================================================
--- devmapper/trunk/dmeventd/.exported_symbols (original)
+++ devmapper/trunk/dmeventd/.exported_symbols Sat Apr 7 09:09:48 2007
@@ -1,5 +1,19 @@
-dm_event_register
-dm_event_unregister
+dm_event_handler_create
+dm_event_handler_destroy
+dm_event_handler_set_dso
+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_event_mask
+dm_event_handler_get_dso
+dm_event_handler_get_devname
+dm_event_handler_get_uuid
+dm_event_handler_get_major
+dm_event_handler_get_minor
+dm_event_handler_get_event_mask
+dm_event_register_handler
+dm_event_unregister_handler
dm_event_get_registered_device
-dm_event_set_timeout
-dm_event_get_timeout
+dm_event_handler_set_timeout
+dm_event_handler_get_timeout
Modified: devmapper/trunk/dmeventd/Makefile.in
==============================================================================
--- devmapper/trunk/dmeventd/Makefile.in (original)
+++ devmapper/trunk/dmeventd/Makefile.in Sat Apr 7 09:09:48 2007
@@ -15,8 +15,7 @@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
-SOURCES = libdevmapper-event.c \
- dmeventd.c
+SOURCES = libdevmapper-event.c
LIB_STATIC = libdevmapper-event.a
@@ -26,12 +25,20 @@
LIB_SHARED = libdevmapper-event.so
endif
+TARGETS = dmeventd
+CLEAN_TARGETS = dmeventd.o
+
include ../make.tmpl
+LDFLAGS += -ldl -ldevmapper -lpthread
CLDFLAGS += -ldl -ldevmapper -lpthread
+dmeventd: $(LIB_SHARED) dmeventd.o
+ $(CC) -o $@ dmeventd.o $(CFLAGS) $(LDFLAGS) \
+ -L. -ldevmapper-event $(LIBS) -rdynamic
+
.PHONY: install_dynamic install_static install_include \
- install_pkgconfig
+ install_pkgconfig install_dmeventd
INSTALL_TYPE = install_dynamic
@@ -43,7 +50,7 @@
INSTALL_TYPE += install_pkgconfig
endif
-install: $(INSTALL_TYPE) install_include
+install: $(INSTALL_TYPE) install_include install_dmeventd
install_include:
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \
@@ -55,6 +62,9 @@
$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \
$(libdir)/libdevmapper-event.$(LIB_SUFFIX)
+install_dmeventd: dmeventd
+ $(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< $(sbindir)/$<
+
install_pkgconfig:
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.pc \
$(usrlibdir)/pkgconfig/devmapper-event.pc
Modified: devmapper/trunk/dmeventd/dmeventd.c
==============================================================================
--- devmapper/trunk/dmeventd/dmeventd.c (original)
+++ devmapper/trunk/dmeventd/dmeventd.c Sat Apr 7 09:09:48 2007
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
@@ -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"
@@ -28,29 +29,37 @@
#include <dlfcn.h>
#include <errno.h>
-#include <fcntl.h>
-#include <libgen.h>
#include <pthread.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include <sys/file.h>
-#include <sys/mman.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include <unistd.h>
-#include <stdarg.h>
+#include <arpa/inet.h> /* for htonl, ntohl */
#ifdef linux
-#include <malloc.h>
+# include <malloc.h>
+
+# define OOM_ADJ_FILE "/proc/self/oom_adj"
+
+/* From linux/oom.h */
+# define OOM_DISABLE (-17)
+# define OOM_ADJUST_MIN (-16)
+
#endif
+/* 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 int _debug = 0;
+
/* List (un)link macros. */
#define LINK(x, head) list_add(head, &(x)->list)
-#define LINK_DSO(dso) LINK(dso, &dso_registry)
-#define LINK_THREAD(thread) LINK(thread, &thread_registry)
+#define LINK_DSO(dso) LINK(dso, &_dso_registry)
+#define LINK_THREAD(thread) LINK(thread, &_thread_registry)
#define UNLINK(x) list_del(&(x)->list)
#define UNLINK_DSO(x) UNLINK(x)
@@ -58,26 +67,59 @@
#define DAEMON_NAME "dmeventd"
-/* Global mutex for list accesses. */
-static pthread_mutex_t mutex;
+/*
+ Global mutex for thread list access. Has to be held when:
+ - iterating thread list
+ - adding or removing elements from thread list
+ - changing or reading thread_status's fields:
+ processing, status, events
+ Use _lock_mutex() and _unlock_mutex() to hold/release it
+*/
+static pthread_mutex_t _global_mutex;
+
+/*
+ There are three states a thread can attain (see struct
+ thread_status, field int status):
+
+ - DM_THREAD_RUNNING: thread has started up and is either working or
+ waiting for events... transitions to either SHUTDOWN or DONE
+ - DM_THREAD_SHUTDOWN: thread is still doing something, but it is
+ supposed to terminate (and transition to DONE) as soon as it
+ finishes whatever it was doing at the point of flipping state to
+ SHUTDOWN... the thread is still on the thread list
+ - DM_THREAD_DONE: thread has terminated and has been moved over to
+ unused thread list, cleanup pending
+ */
+#define DM_THREAD_RUNNING 0
+#define DM_THREAD_SHUTDOWN 1
+#define DM_THREAD_DONE 2
+
+#define THREAD_STACK_SIZE (300*1024)
+
+#define DEBUGLOG(fmt, args...) _debuglog(fmt, ## args)
/* Data kept about a DSO. */
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_mask event, void **user);
/*
* Device registration.
@@ -87,7 +129,8 @@
* 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, void **user);
/*
* Device unregistration.
@@ -96,17 +139,19 @@
* 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, void **user);
};
-static LIST_INIT(dso_registry);
+static LIST_INIT(_dso_registry);
/* Structure to keep parsed register variables from client message. */
struct message_data {
+ char *id;
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. */
+ enum dm_event_mask field; /* Events bitfield. */
} events;
union {
char *str;
@@ -122,95 +167,131 @@
* occurs and the event processing function of the DSO gets called.
*/
struct thread_status {
- struct list list;
+ struct list list;
- pthread_t thread;
+ pthread_t thread;
- struct dso_data *dso_data;/* DSO this thread accesses. */
-
- char *device_path; /* Mapped device path. */
- uint32_t event_nr; /* event number */
- int processing; /* Set when event is being processed */
- 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. */
+ 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; /* see DM_THREAD_{RUNNING,SHUTDOWN,DONE}
+ constants above */
+ enum dm_event_mask events; /* bitfield for event filter. */
+ enum dm_event_mask current_events; /* bitfield for occured events. */
+ struct dm_task *current_task;
time_t next_time;
uint32_t timeout;
struct list timeout_list;
+ void *dso_private; /* dso per-thread status variable */
};
-static LIST_INIT(thread_registry);
-static LIST_INIT(thread_registry_unused);
+static LIST_INIT(_thread_registry);
+static LIST_INIT(_thread_registry_unused);
+
+static int _timeout_running;
+static LIST_INIT(_timeout_registry);
+static pthread_mutex_t _timeout_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t _timeout_cond = PTHREAD_COND_INITIALIZER;
+
+static void _debuglog(const char *fmt, ...)
+{
+ time_t P;
+ va_list ap;
+
+ if (!_debug)
+ return;
+
+ va_start(ap,fmt);
+
+ time(&P);
+ fprintf(stderr, "dmeventd[%p]: %.15s ", (void *) pthread_self(), ctime(&P)+4 );
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
-static int timeout_running;
-static LIST_INIT(timeout_registry);
-static pthread_mutex_t timeout_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t timeout_cond = PTHREAD_COND_INITIALIZER;
+ va_end(ap);
+}
/* Allocate/free the status structure for a monitoring thread. */
-static struct thread_status *alloc_thread_status(struct message_data *data,
- struct dso_data *dso_data)
+static struct thread_status *_alloc_thread_status(struct message_data *data,
+ struct dso_data *dso_data)
{
struct thread_status *ret = (typeof(ret)) dm_malloc(sizeof(*ret));
- if (ret) {
- if (!memset(ret, 0, sizeof(*ret)) ||
- !(ret->device_path = dm_strdup(data->device_path))) {
- dm_free(ret);
- ret = NULL;
- } else {
- ret->dso_data = dso_data;
- ret->events = data->events.field;
- ret->timeout = data->timeout.secs;
- list_init(&ret->timeout_list);
- }
+ if (!ret)
+ return NULL;
+
+ if (!memset(ret, 0, sizeof(*ret)) ||
+ !(ret->device.uuid = dm_strdup(data->device_uuid))) {
+ dm_free(ret);
+ return NULL;
}
+ 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;
+ list_init(&ret->timeout_list);
+
return ret;
}
-static void free_thread_status(struct thread_status *thread)
+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);
}
/* Allocate/free DSO data. */
-static struct dso_data *alloc_dso_data(struct message_data *data)
+static struct dso_data *_alloc_dso_data(struct message_data *data)
{
struct dso_data *ret = (typeof(ret)) dm_malloc(sizeof(*ret));
- if (ret) {
- if (!memset(ret, 0, sizeof(*ret)) ||
- !(ret->dso_name = dm_strdup(data->dso_name))) {
- dm_free(ret);
- ret = NULL;
- }
+ if (!ret)
+ return NULL;
+
+ if (!memset(ret, 0, sizeof(*ret)) ||
+ !(ret->dso_name = dm_strdup(data->dso_name))) {
+ dm_free(ret);
+ return NULL;
}
return ret;
}
-static void free_dso_data(struct dso_data *data)
+/* Create a device monitoring thread. */
+static int _pthread_create_smallstack(pthread_t *t, void *(*fun)(void *), void *arg)
{
- dm_free(data->dso_name);
- dm_free(data);
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ /*
+ * We use a smaller stack since it gets preallocated in its entirety
+ */
+ pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
+ return pthread_create(t, &attr, fun, arg);
}
-/* FIXME: Factor out. */
-static char *dm_basename(char *str)
+static void _free_dso_data(struct dso_data *data)
{
- char *p = strrchr(str, '/');
-
- return p ? p + 1 : str;
+ dm_free(data->dso_name);
+ dm_free(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. */
-static const char delimiter = ' ';
-static int fetch_string(char **ptr, char **src)
+/* FIXME? move to libdevmapper to share with the client lib (need to
+ make delimiter a parameter then) */
+static int _fetch_string(char **ptr, char **src, const int delimiter)
{
int ret = 0;
char *p;
@@ -238,30 +319,39 @@
}
/* Free message memory. */
-static void free_message(struct message_data *message_data)
+static void _free_message(struct message_data *message_data)
{
+ if (message_data->id)
+ dm_free(message_data->id);
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);
+
}
/* Parse a register message from the client. */
-static int parse_message(struct message_data *message_data)
+static int _parse_message(struct message_data *message_data)
{
- char *p = message_data->msg->msg;
+ int ret = 0;
+ char *p = message_data->msg->data;
+ struct dm_event_daemon_message *msg = message_data->msg;
+
+ if (!msg->data)
+ return 0;
/*
* Retrieve application identifier, mapped device
* 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->events.str, &p) &&
- fetch_string(&message_data->timeout.str, &p)) {
+ if (_fetch_string(&message_data->id, &p, ' ') &&
+ _fetch_string(&message_data->dso_name, &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) {
- enum dm_event_type i = atoi(message_data->events.str);
+ enum dm_event_mask i = atoi(message_data->events.str);
/*
* Free string representaion of events.
@@ -274,28 +364,32 @@
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;
}
- return 1;
+ ret = 1;
}
- return 0;
+ dm_free(msg->data);
+ msg->data = NULL;
+ msg->size = 0;
+ return ret;
};
-/* Global mutex to lock access to lists et al. */
-static int lock_mutex(void)
+/* Global mutex to lock access to lists et al. See _global_mutex
+ above. */
+static int _lock_mutex(void)
{
- return pthread_mutex_lock(&mutex);
+ return pthread_mutex_lock(&_global_mutex);
}
-static int unlock_mutex(void)
+static int _unlock_mutex(void)
{
- return pthread_mutex_unlock(&mutex);
+ return pthread_mutex_unlock(&_global_mutex);
}
/* Store pid in pidfile. */
-static int storepid(int lf)
+static int _storepid(int lf)
{
int len;
char pid[8];
@@ -314,23 +408,43 @@
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;
}
/*
@@ -338,79 +452,58 @@
*
* Mutex must be held when calling this.
*/
-static struct thread_status *lookup_thread_status(struct message_data *data)
+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;
- }
+ list_iterate_items(thread, &_thread_registry)
+ if (!strcmp(data->device_uuid, thread->device.uuid))
+ return thread;
return NULL;
}
-
/* Cleanup at exit. */
-static void exit_dm_lib(void)
+static void _exit_dm_lib(void)
{
dm_lib_release();
dm_lib_exit();
}
-/* Derive error case from target parameter string. */
-/* FIXME Remove? */
-static int error_detected(struct thread_status *thread, char *params) __attribute__ ((unused));
-static int error_detected(struct thread_status *thread, char *params)
-{
- size_t len;
-/*
- Leave it to the DSO to decide how to interpret the status info
- if ((len = strlen(params)) &&
- params[len - 1] == 'F') {
-*/
- if (params && (len = strlen(params))) {
- thread->current_events |= DM_EVENT_DEVICE_ERROR;
- return 1;
- }
-
- return 0;
-}
-
-static void exit_timeout(void *unused)
+static void _exit_timeout(void *unused __attribute((unused)))
{
- timeout_running = 0;
- pthread_mutex_unlock(&timeout_mutex);
+ _timeout_running = 0;
+ pthread_mutex_unlock(&_timeout_mutex);
}
/* Wake up monitor threads every so often. */
-static void *timeout_thread(void *unused)
+static void *_timeout_thread(void *unused __attribute((unused)))
{
struct timespec timeout;
time_t curr_time;
timeout.tv_nsec = 0;
- pthread_cleanup_push(exit_timeout, NULL);
- pthread_mutex_lock(&timeout_mutex);
+ pthread_cleanup_push(_exit_timeout, NULL);
+ pthread_mutex_lock(&_timeout_mutex);
- while (!list_empty(&timeout_registry)) {
+ while (!list_empty(&_timeout_registry)) {
struct thread_status *thread;
- timeout.tv_sec = (time_t)-1;
+ timeout.tv_sec = 0;
curr_time = time(NULL);
- list_iterate_items_gen(thread, &timeout_registry,
- timeout_list) {
- if (thread->next_time < curr_time) {
+ 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);
}
- if (thread->next_time < timeout.tv_sec)
+ if (thread->next_time < timeout.tv_sec || !timeout.tv_sec)
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);
@@ -418,45 +511,44 @@
return NULL;
}
-static int register_for_timeout(struct thread_status *thread)
+static int _register_for_timeout(struct thread_status *thread)
{
int ret = 0;
- pthread_mutex_lock(&timeout_mutex);
+ pthread_mutex_lock(&_timeout_mutex);
thread->next_time = time(NULL) + thread->timeout;
if (list_empty(&thread->timeout_list)) {
- list_add(&timeout_registry, &thread->timeout_list);
- if (timeout_running)
- pthread_cond_signal(&timeout_cond);
+ list_add(&_timeout_registry, &thread->timeout_list);
+ if (_timeout_running)
+ pthread_cond_signal(&_timeout_cond);
}
- if (!timeout_running) {
+ if (!_timeout_running) {
pthread_t timeout_id;
- if (!(ret = -pthread_create(&timeout_id, NULL,
- timeout_thread, NULL)))
- timeout_running = 1;
+ if (!(ret = -_pthread_create_smallstack(&timeout_id, _timeout_thread, NULL)))
+ _timeout_running = 1;
}
- pthread_mutex_unlock(&timeout_mutex);
+ pthread_mutex_unlock(&_timeout_mutex);
return ret;
}
-static void unregister_for_timeout(struct thread_status *thread)
+static void _unregister_for_timeout(struct thread_status *thread)
{
- pthread_mutex_lock(&timeout_mutex);
+ pthread_mutex_lock(&_timeout_mutex);
if (!list_empty(&thread->timeout_list)) {
list_del(&thread->timeout_list);
list_init(&thread->timeout_list);
}
- pthread_mutex_unlock(&timeout_mutex);
+ pthread_mutex_unlock(&_timeout_mutex);
}
-static void no_intr_log(int level, const char *file, int line,
- const char *f, ...)
+static void _no_intr_log(int level, const char *file, int line,
+ const char *f, ...)
{
va_list ap;
@@ -480,7 +572,7 @@
fprintf(stdout, "\n");
}
-static sigset_t unblock_sigalrm(void)
+static sigset_t _unblock_sigalrm(void)
{
sigset_t set, old;
@@ -490,165 +582,234 @@
return old;
}
+#define DM_WAIT_RETRY 0
+#define DM_WAIT_INTR 1
+#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 = 0;
-/*
- void *next = NULL;
- char *params, *target_type;
- uint64_t start, length;
-*/
+ int ret = DM_WAIT_RETRY;
struct dm_task *dmt;
struct dm_info info;
+ *task = 0;
+
if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
- return 0;
+ return DM_WAIT_RETRY;
+
+ thread->current_task = dmt;
- if (!(ret = dm_task_set_name(dmt, dm_basename(thread->device_path))) ||
- !(ret = dm_task_set_event_nr(dmt, thread->event_nr)))
+ if (!dm_task_set_uuid(dmt, thread->device.uuid) ||
+ !dm_task_set_event_nr(dmt, thread->event_nr))
goto out;
/*
* This is so that you can break out of waiting on an event,
* either for a timeout event, or to cancel the thread.
*/
- set = unblock_sigalrm();
- dm_log_init(no_intr_log);
+ set = _unblock_sigalrm();
+ dm_log_init(_no_intr_log);
errno = 0;
- if ((ret = dm_task_run(dmt))) {
-/*
- do {
- params = NULL;
- next = dm_get_next_target(dmt, next, &start, &length,
- &target_type, ¶ms);
-
- log_error("%s: %s\n", __func__, params);
- if ((ret = error_detected(thread, params)))
- break;
- } while(next);
-*/
+ if (dm_task_run(dmt)) {
thread->current_events |= DM_EVENT_DEVICE_ERROR;
- ret = 1;
-
- /*
- * 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;
+ ret = DM_WAIT_INTR;
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 = 1;
- thread->processed_events = 0;
+ ret = DM_WAIT_INTR;
+ } else {
+ syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
+ errno, strerror(errno));
+ if (errno == ENXIO) {
+ syslog(LOG_ERR, "%s disappeared, detaching",
+ thread->device.name);
+ ret = DM_WAIT_FATAL;
+ }
}
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;
}
/* Register a device with the DSO. */
-static int do_register_device(struct thread_status *thread)
+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,
+ &(thread->dso_private));
}
/* Unregister a device with the DSO. */
-static int do_unregister_device(struct thread_status *thread)
+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,
+ &(thread->dso_private));
}
/* 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->dso_private));
}
/* Thread cleanup handler to unregister device. */
-static void monitor_unregister(void *arg)
+static void _monitor_unregister(void *arg)
{
- struct thread_status *thread = arg;
+ struct thread_status *thread = arg, *thread_iter;
+
+ if (!_do_unregister_device(thread))
+ syslog(LOG_ERR, "%s: %s unregister failed\n", __func__,
+ thread->device.name);
+ if (thread->current_task)
+ dm_task_destroy(thread->current_task);
+ thread->current_task = NULL;
+
+ _lock_mutex();
+ if (thread->events & DM_EVENT_TIMEOUT) {
+ /* _unregister_for_timeout locks another mutex, we
+ don't want to deadlock so we release our mutex for
+ a bit */
+ _unlock_mutex();
+ _unregister_for_timeout(thread);
+ _lock_mutex();
+ }
+ /* we may have been relinked to unused registry since we were
+ called, so check that */
+ list_iterate_items(thread_iter, &_thread_registry_unused)
+ if (thread_iter == thread) {
+ thread->status = DM_THREAD_DONE;
+ _unlock_mutex();
+ return;
+ }
+ thread->status = DM_THREAD_DONE;
+ UNLINK_THREAD(thread);
+ LINK(thread, &_thread_registry_unused);
+ _unlock_mutex();
+}
+
+static struct dm_task *_get_device_status(struct thread_status *ts)
+{
+ struct dm_task *dmt = dm_task_create(DM_DEVICE_STATUS);
+
+ if (!dmt)
+ return NULL;
+
+ dm_task_set_uuid(dmt, ts->device.uuid);
+
+ if (!dm_task_run(dmt)) {
+ dm_task_destroy(dmt);
+ return NULL;
+ }
- if (!do_unregister_device(thread))
- log_error("%s: %s unregister failed\n", __func__,
- thread->device_path);
+ return dmt;
}
/* Device monitoring thread. */
-static void *monitor_thread(void *arg)
- __attribute((noreturn));
-static void *monitor_thread(void *arg)
+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);
+ pthread_cleanup_push(_monitor_unregister, thread);
/* Wait for do_process_request() to finish its task. */
- lock_mutex();
- unlock_mutex();
+ _lock_mutex();
+ thread->status = DM_THREAD_RUNNING;
+ _unlock_mutex();
/* Loop forever awaiting/analyzing device events. */
while (1) {
thread->current_events = 0;
+ wait_error = _event_wait(thread, &task);
+ if (wait_error == DM_WAIT_RETRY)
+ continue;
+
+ if (wait_error == DM_WAIT_FATAL)
+ break;
+
+ /* Timeout occurred, task is not filled properly.
+ * We get device status here for processing it in DSO.
+ */
+ if (wait_error == DM_WAIT_INTR &&
+ thread->current_events & DM_EVENT_TIMEOUT) {
+ dm_task_destroy(task);
+ task = _get_device_status(thread);
+ /* FIXME: syslog fail here ? */
+ if (!(thread->current_task = task))
+ continue;
+ }
+
/*
- * FIXME: if unrecoverable error (ENODEV) happens,
- * we loop indefinitely. event_wait should return
- * more than 0/1.
+ * We know that wait succeeded and stored a
+ * pointer to dm_task with device status into task.
*/
- if (!event_wait(thread))
- continue;
/*
* Check against filter.
*
- * If there's current events delivered from event_wait() AND
+ * 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?
*/
- if (thread->events &
- thread->current_events &
- ~thread->processed_events) {
- lock_mutex();
+ _lock_mutex();
+ if (thread->status == DM_THREAD_SHUTDOWN) {
+ _unlock_mutex();
+ break;
+ }
+ _unlock_mutex();
+
+ if (thread->events & thread->current_events) {
+ _lock_mutex();
thread->processing = 1;
- unlock_mutex();
- do_process_event(thread);
- thread->processed_events |= thread->current_events;
- lock_mutex();
+ _unlock_mutex();
+
+ _do_process_event(thread, task);
+ dm_task_destroy(task);
+ thread->current_task = NULL;
+
+ _lock_mutex();
thread->processing = 0;
- unlock_mutex();
+ _unlock_mutex();
+ } else {
+ dm_task_destroy(task);
+ thread->current_task = NULL;
}
}
- 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)
+static int _create_thread(struct thread_status *thread)
{
- return pthread_create(&thread->thread, NULL, monitor_thread, thread);
+ return _pthread_create_smallstack(&thread->thread, _monitor_thread, thread);
}
-static int terminate_thread(struct thread_status *thread)
+static int _terminate_thread(struct thread_status *thread)
{
int ret;
@@ -658,84 +819,78 @@
return pthread_kill(thread->thread, SIGALRM);
}
-/* DSO reference counting. */
-static void lib_get(struct dso_data *data)
+/* DSO reference counting. Call with _global_mutex locked! */
+static void _lib_get(struct dso_data *data)
{
data->ref_count++;
}
-static void lib_put(struct dso_data *data)
+static void _lib_put(struct dso_data *data)
{
if (!--data->ref_count) {
dlclose(data->dso_handle);
UNLINK_DSO(data);
- free_dso_data(data);
+ _free_dso_data(data);
}
}
/* Find DSO data. */
-static struct dso_data *lookup_dso(struct message_data *data)
+static struct dso_data *_lookup_dso(struct message_data *data)
{
struct dso_data *dso_data, *ret = NULL;
- 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;
- }
+ list_iterate_items(dso_data, &_dso_registry)
+ if (!strcmp(data->dso_name, dso_data->dso_name)) {
+ _lib_get(dso_data);
+ ret = dso_data;
+ break;
}
- unlock_mutex();
-
return ret;
}
/* Lookup DSO symbols we need. */
-static int lookup_symbol(void *dl, struct dso_data *data,
- void **symbol, const char *name)
+static int _lookup_symbol(void *dl, void **symbol, const char *name)
{
if ((*symbol = dlsym(dl, name)))
return 1;
- log_error("looking up %s symbol in %s\n", name, data->dso_name);
-
return 0;
}
static int lookup_symbols(void *dl, struct dso_data *data)
{
- return lookup_symbol(dl, data, (void*) &data->process_event,
+ return _lookup_symbol(dl, (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, (void *) &data->register_device,
+ "register_device") &&
+ _lookup_symbol(dl, (void *) &data->unregister_device,
+ "unregister_device");
}
/* Load an application specific DSO. */
-static struct dso_data *load_dso(struct message_data *data)
+static struct dso_data *_load_dso(struct message_data *data)
{
void *dl;
struct dso_data *ret = NULL;
- log_very_verbose("Opening shared library %s", data->dso_name);
-
- if (!(dl = dlopen(data->dso_name, RTLD_NOW))){
- log_error("dmeventd %s dlopen failed: %s", data->dso_name,
- dlerror());
+ if (!(dl = dlopen(data->dso_name, RTLD_NOW))) {
+ const char *dlerr = dlerror();
+ syslog(LOG_ERR, "dmeventd %s dlopen failed: %s", data->dso_name,
+ dlerr);
+ data->msg->size =
+ dm_asprintf(&(data->msg->data), "%s %s dlopen failed: %s",
+ data->id, data->dso_name, dlerr);
return NULL;
}
- if (!(ret = alloc_dso_data(data))) {
+ if (!(ret = _alloc_dso_data(data))) {
dlclose(dl);
return NULL;
}
if (!(lookup_symbols(dl, ret))) {
- free_dso_data(ret);
+ _free_dso_data(ret);
dlclose(dl);
return NULL;
}
@@ -745,18 +900,17 @@
* we've got no references to it any more.
*/
ret->dso_handle = dl;
- lib_get(ret);
+ _lib_get(ret);
- lock_mutex();
+ _lock_mutex();
LINK_DSO(ret);
- unlock_mutex();
+ _unlock_mutex();
return ret;
}
-
/* Return success on daemon active check. */
-static int active(struct message_data *message_data)
+static int _active(struct message_data *message_data)
{
return 0;
}
@@ -767,22 +921,15 @@
* Only one caller at a time here, because we use
* a FIFO and lock it against multiple accesses.
*/
-static int register_for_event(struct message_data *message_data)
+static int _register_for_event(struct message_data *message_data)
{
int ret = 0;
struct thread_status *thread, *thread_new = NULL;
struct dso_data *dso_data;
- if (!device_exists(message_data->device_path)) {
+ if (!(dso_data = _lookup_dso(message_data)) &&
+ !(dso_data = _load_dso(message_data))) {
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
@@ -790,35 +937,51 @@
#endif
goto out;
}
-
+
/* Preallocate thread status struct to avoid deadlock. */
- if (!(thread_new = alloc_thread_status(message_data, dso_data))) {
+ if (!(thread_new = _alloc_thread_status(message_data, dso_data))) {
stack;
ret = -ENOMEM;
goto out;
}
- lock_mutex();
+ if (!_fill_device_data(thread_new)) {
+ stack;
+ ret = -ENODEV;
+ goto out;
+ }
- if (!(thread = lookup_thread_status(message_data))) {
- unlock_mutex();
+ _lock_mutex();
- /*
- * FIXME: better do this asynchronously in the
- * monitoring thread ?
- */
- if (!(ret = do_register_device(thread_new)))
+ /* If creation of timeout thread fails (as it may), we fail
+ here completely. The client is responsible for either
+ retrying later or trying to register without timeout
+ events. However, if timeout thread cannot be started, it
+ usually means we are so starved on resources that we are
+ almost as good as dead already... */
+ if (thread_new->events & DM_EVENT_TIMEOUT) {
+ ret = -_register_for_timeout(thread_new);
+ if (ret) {
+ _unlock_mutex();
+ goto out;
+ }
+ }
+
+ if (!(thread = _lookup_thread_status(message_data))) {
+ _unlock_mutex();
+
+ if (!(ret = _do_register_device(thread_new)))
goto out;
thread = thread_new;
thread_new = NULL;
/* Try to create the monitoring thread for this device. */
- lock_mutex();
- if ((ret = -create_thread(thread))) {
- unlock_mutex();
- do_unregister_device(thread);
- free_thread_status(thread);
+ _lock_mutex();
+ if ((ret = -_create_thread(thread))) {
+ _unlock_mutex();
+ _do_unregister_device(thread);
+ _free_thread_status(thread);
goto out;
} else
LINK_THREAD(thread);
@@ -827,24 +990,15 @@
/* 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
- action for newly created devices? Also, you are still
- on the timeout registry, so if a timeout thread is
- successfully started up later, you will start receiving
- DM_EVENT_TIMEOUT events */
- 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.
*/
if (thread_new)
- free_thread_status(thread_new);
+ _free_thread_status(thread_new);
return ret;
}
@@ -854,7 +1008,7 @@
*
* Only one caller at a time here as with register_for_event().
*/
-static int unregister_for_event(struct message_data *message_data)
+static int _unregister_for_event(struct message_data *message_data)
{
int ret = 0;
struct thread_status *thread;
@@ -863,29 +1017,36 @@
* Clear event in bitfield and deactivate
* monitoring thread in case bitfield is 0.
*/
- lock_mutex();
+ _lock_mutex();
- if (!(thread = lookup_thread_status(message_data))) {
- unlock_mutex();
+ if (!(thread = _lookup_thread_status(message_data))) {
+ _unlock_mutex();
ret = -ENODEV;
goto out;
}
+ if (thread->status == DM_THREAD_DONE) {
+ /* the thread has terminated while we were not
+ watching */
+ _unlock_mutex();
+ return 0;
+ }
+
thread->events &= ~message_data->events.field;
if (!(thread->events & DM_EVENT_TIMEOUT))
- unregister_for_timeout(thread);
+ _unregister_for_timeout(thread);
/*
* In case there's no events to monitor on this device ->
* unlink and terminate its monitoring thread.
*/
if (!thread->events) {
UNLINK_THREAD(thread);
- LINK(thread, &thread_registry_unused);
+ LINK(thread, &_thread_registry_unused);
}
- unlock_mutex();
+ _unlock_mutex();
- out:
+ out:
return ret;
}
@@ -894,143 +1055,202 @@
*
* Only one caller at a time here as with register_for_event().
*/
-static int registered_device(struct message_data *message_data,
+static int _registered_device(struct message_data *message_data,
struct thread_status *thread)
{
struct dm_event_daemon_message *msg = message_data->msg;
- snprintf(msg->msg, sizeof(msg->msg), "%s %s %u",
- thread->dso_data->dso_name, thread->device_path,
- thread->events);
+ const char *fmt = "%s %s %s %u";
+ const char *id = message_data->id;
+ const char *dso = thread->dso_data->dso_name;
+ 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);
- unlock_mutex();
+ msg->size = dm_asprintf(&(msg->data), fmt, id, 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) &&
+ (thread->status == DM_THREAD_RUNNING ||
+ (thread->events & DM_EVENT_REGISTRATION_PENDING));
/* If DSO names are equal. */
if (dso_name)
- return !strcmp(dso_name, thread->dso_data->dso_name);
-
+ return !strcmp(dso_name, thread->dso_data->dso_name) &&
+ (thread->status == DM_THREAD_RUNNING ||
+ (thread->events & DM_EVENT_REGISTRATION_PENDING));
+
/* 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) &&
+ (thread->status == DM_THREAD_RUNNING ||
+ (thread->events & DM_EVENT_REGISTRATION_PENDING));
return 1;
}
-static int _get_registered_device(struct message_data *message_data, int next)
+static int _get_registered_dev(struct message_data *message_data, int next)
{
- int hit = 0;
- struct thread_status *thread;
+ struct thread_status *thread, *hit = NULL;
- lock_mutex();
+ _lock_mutex();
/* 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)))
+ list_iterate_items(thread, &_thread_registry)
+ if (_want_registered_device(message_data->dso_name,
+ message_data->device_uuid,
+ thread)) {
+ hit = thread;
break;
- }
+ }
/*
* If we got a registered device and want the next one ->
* fetch next conforming element off the list.
*/
- if (hit) {
- if (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));
- }
+ if (hit && !next) {
+ _unlock_mutex();
+ return _registered_device(message_data, hit);
+ }
+
+ if (!hit)
+ goto out;
+
+ thread = hit;
- return registered_device(message_data, thread);
+ while (1) {
+ if (list_end(&_thread_registry, &thread->list))
+ goto out;
+
+ thread = list_item(thread->list.n, struct thread_status);
+ if (_want_registered_device(message_data->dso_name, NULL, thread)) {
+ hit = thread;
+ break;
+ }
}
- out:
- unlock_mutex();
+ _unlock_mutex();
+ return _registered_device(message_data, hit);
+ out:
+ _unlock_mutex();
+
return -ENOENT;
}
-static int get_registered_device(struct message_data *message_data)
+static int _get_registered_device(struct message_data *message_data)
{
- return _get_registered_device(message_data, 0);
+ return _get_registered_dev(message_data, 0);
}
-static int get_next_registered_device(struct message_data *message_data)
+static int _get_next_registered_device(struct message_data *message_data)
{
- return _get_registered_device(message_data, 1);
+ return _get_registered_dev(message_data, 1);
}
-static int set_timeout(struct message_data *message_data)
+static int _set_timeout(struct message_data *message_data)
{
struct thread_status *thread;
- lock_mutex();
- if ((thread = lookup_thread_status(message_data)))
- thread->timeout = message_data->timeout.secs;
- unlock_mutex();
+ _lock_mutex();
+ if ((thread = _lookup_thread_status(message_data)))
+ thread->timeout = message_data->timeout.secs;
+ _unlock_mutex();
return thread ? 0 : -ENODEV;
}
-static int get_timeout(struct message_data *message_data)
+static int _get_timeout(struct message_data *message_data)
{
struct thread_status *thread;
struct dm_event_daemon_message *msg = message_data->msg;
- lock_mutex();
- if ((thread = lookup_thread_status(message_data)))
- snprintf(msg->msg, sizeof(msg->msg),
- "%"PRIu32, thread->timeout);
- unlock_mutex();
+ if (msg->data)
+ dm_free(msg->data);
+
+ _lock_mutex();
+ if ((thread = _lookup_thread_status(message_data))) {
+ msg->size =
+ dm_asprintf(&(msg->data), "%s %" PRIu32, message_data->id,
+ thread->timeout);
+ } else {
+ msg->data = NULL;
+ msg->size = 0;
+ }
+ _unlock_mutex();
return thread ? 0 : -ENODEV;
}
-
/* Initialize a fifos structure with path names. */
-static int init_fifos(struct dm_event_fifos *fifos)
+static void _init_fifos(struct dm_event_fifos *fifos)
{
- if (memset(fifos, 0, sizeof(*fifos))) {
- fifos->client_path = DM_EVENT_FIFO_CLIENT;
- fifos->server_path = DM_EVENT_FIFO_SERVER;
-
- return 0;
- }
+ memset(fifos, 0, sizeof(*fifos));
- return -ENOMEM;
+ fifos->client_path = DM_EVENT_FIFO_CLIENT;
+ fifos->server_path = DM_EVENT_FIFO_SERVER;
}
/* Open fifos used for client communication. */
-static int open_fifos(struct dm_event_fifos *fifos)
+static int _open_fifos(struct dm_event_fifos *fifos)
{
- /* Blocks until client is ready to write. */
- if ((fifos->server = open(fifos->server_path, O_WRONLY)) < 0) {
+ /* Create fifos */
+ if (((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) ||
+ ((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST)) {
+ syslog(LOG_ERR, "%s: Failed to create a fifo.\n", __func__);
stack;
- return -EXIT_FIFO_FAILURE;
+ return -errno;
+ }
+
+ 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);
+ return -errno;
+ }
+
+ if (chmod(fifos->server_path, 0600)) {
+ syslog(LOG_ERR, "Unable to set correct file permissions on %s",
+ fifos->server_path);
+ return -errno;
+ }
+
+ /* Need to open read+write or we will block or fail */
+ if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
+ stack;
+ return -errno;
}
/* Need to open read+write for select() to work. */
- if ((fifos->client = open(fifos->client_path, O_RDWR)) < 0) {
+ if ((fifos->client = open(fifos->client_path, O_RDWR)) < 0) {
stack;
close(fifos->server);
- return -EXIT_FIFO_FAILURE;
+ return -errno;
}
return 0;
@@ -1040,60 +1260,91 @@
* 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;
int ret = 0;
fd_set fds;
+ int header = 1;
+ size_t size = 2 * sizeof(uint32_t); /* status + size */
+ char *buf = alloca(size);
+
+ msg->data = NULL;
errno = 0;
- while (bytes < sizeof(*msg) && errno != EOF) {
+ while (bytes < size && errno != EOF) {
/* Watch client read FIFO for input. */
FD_ZERO(&fds);
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, msg, sizeof(*msg) - bytes);
+ 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));
+ buf = msg->data = dm_malloc(msg->size);
+ size = msg->size;
+ bytes = 0;
+ header = 0;
+ }
+ }
+
+ if (bytes != size) {
+ if (msg->data)
+ dm_free(msg->data);
+ msg->data = NULL;
+ msg->size = 0;
}
- return bytes == sizeof(*msg);
+ return bytes == size;
}
/*
* 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;
+ char *buf = alloca(size);
+
+ *((uint32_t *)buf) = htonl(msg->cmd);
+ *((uint32_t *)buf + 1) = htonl(msg->size);
+ if (msg->data)
+ memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
+
errno = 0;
- while (bytes < sizeof(*msg) && errno != EIO) {
+ while (bytes < size && errno != EIO) {
do {
/* 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, msg, sizeof(*msg) - bytes);
+ ret = write(fifos->server, buf + bytes, size - bytes);
bytes += ret > 0 ? ret : 0;
}
- return bytes == sizeof(*msg);
+ return bytes == size;
}
/*
@@ -1102,238 +1353,410 @@
* We put the request handling functions into
* a list because of the growing number.
*/
-static int handle_request(struct dm_event_daemon_message *msg,
+static int _handle_request(struct dm_event_daemon_message *msg,
struct message_data *message_data)
{
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++) {
- if (req->cmd == msg->opcode.cmd)
+ for (req = requests; req < requests + sizeof(requests); req++)
+ if (req->cmd == msg->cmd)
return req->f(message_data);
- }
return -EINVAL;
}
/* Process a request passed from the communication thread. */
-static int do_process_request(struct dm_event_daemon_message *msg)
+static int _do_process_request(struct dm_event_daemon_message *msg)
{
int ret;
+ char *answer;
static struct message_data message_data;
/* Parse the message. */
memset(&message_data, 0, sizeof(message_data));
message_data.msg = msg;
- if (msg->opcode.cmd != DM_EVENT_CMD_ACTIVE &&
- !parse_message(&message_data)) {
+ if (msg->cmd == DM_EVENT_CMD_HELLO) {
+ ret = 0;
+ answer = dm_strdup(msg->data);
+ if (answer) {
+ msg->size = dm_asprintf(&(msg->data), "%s HELLO", answer);
+ dm_free(answer);
+ } else {
+ msg->size = 0;
+ msg->data = NULL;
+ }
+ } else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
stack;
ret = -EINVAL;
- } else {
- ret = handle_request(msg, &message_data);
- }
+ } else
+ ret = _handle_request(msg, &message_data);
- free_message(&message_data);
+ msg->cmd = ret;
+ if (!msg->data)
+ msg->size = dm_asprintf(&(msg->data), "%s %s", message_data.id, strerror(-ret));
+
+ _free_message(&message_data);
return ret;
}
/* Only one caller at a time. */
-static void process_request(struct dm_event_fifos *fifos)
+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))
+ if (!_client_read(fifos, &msg))
return;
- msg.opcode.status = do_process_request(&msg);
+ /* _do_process_request fills in msg (if memory allows for
+ data, otherwise just cmd and size = 0) */
+ _do_process_request(&msg);
- if (!client_write(fifos, &msg))
+ if (!_client_write(fifos, &msg))
stack;
+
+ if (msg.data)
+ dm_free(msg.data);
}
-static void cleanup_unused_threads(void)
+static void _cleanup_unused_threads(void)
{
int ret;
struct list *l;
struct thread_status *thread;
- lock_mutex();
- while ((l = list_first(&thread_registry_unused))) {
+ _lock_mutex();
+ while ((l = list_first(&_thread_registry_unused))) {
thread = list_item(l, struct thread_status);
- if (thread->processing) {
- goto out; /* cleanup on the next round */
+ if (thread->processing)
+ break; /* cleanup on the next round */
+
+ if (thread->status == DM_THREAD_RUNNING) {
+ thread->status = DM_THREAD_SHUTDOWN;
+ break;
}
- list_del(l);
- if (!thread->events) {
- /* turn codes negative -- should we be returning this? */
- if ((ret = -terminate_thread(thread)))
- stack;
- else {
- pthread_join(thread->thread, NULL);
- lib_put(thread->dso_data);
- free_thread_status(thread);
+ if (thread->status == DM_THREAD_SHUTDOWN) {
+ if (!thread->events) {
+ /* turn codes negative -- should we be returning this? */
+ ret = _terminate_thread(thread);
+
+ if (ret == ESRCH) {
+ thread->status = DM_THREAD_DONE;
+ } else if (ret) {
+ syslog(LOG_ERR,
+ "Unable to terminate thread: %s\n",
+ strerror(-ret));
+ stack;
+ }
+ break;
}
- } else {
- log_error("thread can't be on unused list unless !thread->events");
+
+ list_del(l);
+ syslog(LOG_ERR,
+ "thread can't be on unused list unless !thread->events");
+ thread->status = DM_THREAD_RUNNING;
LINK_THREAD(thread);
+
+ continue;
}
+ if (thread->status == DM_THREAD_DONE) {
+ list_del(l);
+ pthread_join(thread->thread, NULL);
+ _lib_put(thread->dso_data);
+ _free_thread_status(thread);
+ }
}
-out:
- unlock_mutex();
+
+ _unlock_mutex();
}
-static void sig_alarm(int signum)
+static void _sig_alarm(int signum __attribute((unused)))
{
pthread_testcancel();
}
/* Init thread signal handling. */
-static void init_thread_signals(void)
+static void _init_thread_signals(void)
{
sigset_t my_sigset;
struct sigaction act;
-
+
memset(&act, 0, sizeof(act));
- act.sa_handler = sig_alarm;
+ act.sa_handler = _sig_alarm;
sigaction(SIGALRM, &act, NULL);
sigfillset(&my_sigset);
+
+ /* These are used for exiting */
+ sigdelset(&my_sigset, SIGTERM);
+ sigdelset(&my_sigset, SIGINT);
+ sigdelset(&my_sigset, SIGHUP);
+ sigdelset(&my_sigset, SIGQUIT);
+
pthread_sigmask(SIG_BLOCK, &my_sigset, NULL);
}
-static int daemonize(void)
+/*
+ * exit_handler
+ * @sig
+ *
+ * Set the global variable which the process should
+ * be watching to determine when to exit.
+ */
+static void _exit_handler(int sig __attribute((unused)))
{
- setsid();
- if (chdir("/"))
- return -EXIT_CHDIR_FAILURE;
-
-/* FIXME: activate again after we're done with tracing.
- if ((close(STDIN_FILENO) < 0) ||
- (close(STDOUT_FILENO) < 0) ||
- (close(STDERR_FILENO) < 0))
- return -EXIT_DESC_CLOSE_FAILURE;
-*/
+ /*
+ * We exit when '_exit_now' is set.
+ * That is, when a signal has been received.
+ *
+ * We can not simply set '_exit_now' unless all
+ * threads are done processing.
+ */
+ if (!_thread_registries_empty) {
+ syslog(LOG_ERR, "There are still devices being monitored.");
+ syslog(LOG_ERR, "Refusing to exit.");
+ } else
+ _exit_now = 1;
- return 0;
}
-static int lock_pidfile(void)
+static int _lock_pidfile(void)
{
int lf;
- char pidfile[] = "/var/run/dmeventd.pid";
+ char pidfile[] = DMEVENTD_PIDFILE;
if ((lf = open(pidfile, O_CREAT | O_RDWR, 0644)) < 0)
- return -EXIT_OPEN_PID_FAILURE;
+ exit(EXIT_OPEN_PID_FAILURE);
if (flock(lf, LOCK_EX | LOCK_NB) < 0)
- return -EXIT_LOCKFILE_INUSE;
+ exit(EXIT_LOCKFILE_INUSE);
- if (!storepid(lf))
- return -EXIT_FAILURE;
+ if (!_storepid(lf))
+ exit(EXIT_FAILURE);
return 0;
}
-void dmeventd(void)
+#ifdef linux
+/*
+ * Protection against OOM killer if kernel supports it
+ */
+static int _set_oom_adj(int val)
+{
+ FILE *fp;
+
+ struct stat st;
+
+ if (stat(OOM_ADJ_FILE, &st) == -1) {
+ if (errno == ENOENT)
+ DEBUGLOG(OOM_ADJ_FILE " not found");
+ else
+ perror(OOM_ADJ_FILE ": stat failed");
+ return 1;
+ }
+
+ if (!(fp = fopen(OOM_ADJ_FILE, "w"))) {
+ perror(OOM_ADJ_FILE ": fopen failed");
+ return 0;
+ }
+
+ fprintf(fp, "%i", val);
+ if (fclose(fp))
+ perror(OOM_ADJ_FILE ": fclose failed");
+
+ return 1;
+}
+#endif
+
+static void _daemonize(void)
+{
+ int child_status;
+ int fd;
+ pid_t pid;
+ struct rlimit rlim;
+ struct timeval tval;
+ sigset_t my_sigset;
+
+ sigemptyset(&my_sigset);
+ if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) {
+ fprintf(stderr, "Unable to restore signals.\n");
+ exit(EXIT_FAILURE);
+ }
+ signal(SIGTERM, &_exit_handler);
+
+ switch (pid = fork()) {
+ case -1:
+ perror("fork failed:");
+ exit(EXIT_FAILURE);
+
+ case 0: /* Child */
+ break;
+
+ default:
+ /* Wait for response from child */
+ while (!waitpid(pid, &child_status, WNOHANG) && !_exit_now) {
+ tval.tv_sec = 0;
+ 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 */
+ exit(EXIT_SUCCESS);
+
+ /* Problem with child. Determine what it is by exit code */
+ switch (WEXITSTATUS(child_status)) {
+ case EXIT_LOCKFILE_INUSE:
+ fprintf(stderr, "Another dmeventd daemon is already running\n");
+ break;
+ case EXIT_DESC_CLOSE_FAILURE:
+ case EXIT_DESC_OPEN_FAILURE:
+ case EXIT_OPEN_PID_FAILURE:
+ case EXIT_FIFO_FAILURE:
+ case EXIT_CHDIR_FAILURE:
+ default:
+ fprintf(stderr, "Child exited with code %d\n", WEXITSTATUS(child_status));
+ break;
+ }
+
+ exit(WEXITSTATUS(child_status));
+ }
+
+ if (chdir("/"))
+ exit(EXIT_CHDIR_FAILURE);
+
+ if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
+ fd = 256; /* just have to guess */
+ else
+ fd = rlim.rlim_cur;
+
+ for (--fd; fd >= 0; fd--)
+ close(fd);
+
+ if ((open("/dev/null", O_RDONLY) < 0) ||
+ (open("/dev/null", O_WRONLY) < 0) ||
+ (open("/dev/null", O_WRONLY) < 0))
+ exit(EXIT_DESC_OPEN_FAILURE);
+
+ setsid();
+}
+
+static void usage(char *prog, FILE *file)
+{
+ fprintf(file, "Usage:\n");
+ fprintf(file, "%s [Vhd]\n", prog);
+ fprintf(file, "\n");
+ fprintf(file, " -V Show version of dmeventd\n");
+ fprintf(file, " -h Show this help information\n");
+ fprintf(file, " -d Don't fork, run in the foreground\n");
+ fprintf(file, "\n");
+}
+
+int main(int argc, char *argv[])
{
int ret;
+ signed char opt;
struct dm_event_fifos fifos;
- // struct sys_log logdata = {DAEMON_NAME, LOG_DAEMON};
+ //struct sys_log logdata = {DAEMON_NAME, LOG_DAEMON};
- if ((ret = daemonize()))
- exit(-ret);
+ opterr = 0;
+ optind = 0;
- /* FIXME: set daemon name. */
- // set_name();
+ while ((opt = getopt(argc, argv, "?hVd")) != EOF) {
+ switch (opt) {
+ case 'h':
+ usage(argv[0], stdout);
+ exit(0);
+ case '?':
+ usage(argv[0], stderr);
+ exit(0);
+ case 'd':
+ _debug++;
+ break;
+ case 'V':
+ printf("dmeventd version: %s\n", DM_LIB_VERSION);
+ exit(1);
+ break;
+ }
+ }
+
+ if (!_debug)
+ _daemonize();
- if ((ret = lock_pidfile()))
- exit(-ret);
+ openlog("dmeventd", LOG_PID, LOG_DAEMON);
- init_thread_signals();
+ _lock_pidfile(); /* exits if failure */
+
+ /* Set the rest of the signals to cause '_exit_now' to be set */
+ signal(SIGINT, &_exit_handler);
+ signal(SIGHUP, &_exit_handler);
+ signal(SIGQUIT, &_exit_handler);
+
+#ifdef linux
+ if (!_set_oom_adj(OOM_DISABLE) && !_set_oom_adj(OOM_ADJUST_MIN))
+ syslog(LOG_ERR, "Failed to set oom_adj to protect against OOM killer");
+#endif
+
+ _init_thread_signals();
//multilog_clear_logging();
//multilog_add_type(std_syslog, &logdata);
//multilog_init_verbose(std_syslog, _LOG_DEBUG);
//multilog_async(1);
- if ((ret = init_fifos(&fifos)))
- exit(-ret);
+ _init_fifos(&fifos);
- pthread_mutex_init(&mutex, NULL);
+ pthread_mutex_init(&_global_mutex, NULL);
#ifdef MCL_CURRENT
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1)
exit(EXIT_FAILURE);
#endif
- if ((ret = open_fifos(&fifos)))
- exit(-ret);
+ if ((ret = _open_fifos(&fifos)))
+ exit(EXIT_FIFO_FAILURE);
/* Signal parent, letting them know we are ready to go. */
- kill(getppid(), SIGUSR1);
+ kill(getppid(), SIGTERM);
+ syslog(LOG_NOTICE, "dmeventd ready for processing.");
- /*
- * We exit when there are no more devices to watch.
- * That is, when the last unregister happens.
- *
- * We must be careful though. One of our threads which is
- * watching a device may receive an event and:
- * 1) Alter the device and unregister it
- * or
- * 2) Alter the device, unregister, [alter again,] and reregister
- *
- * We must be capable of answering a request to unregister
- * that comes from the very thread that must be unregistered.
- * Additionally, if that thread unregisters itself and it was the
- * only thread being monitored, we must also handle the case where
- * that thread may perform a register before exiting. (In other
- * words, we can not simply exit if all threads have been unregistered
- * unless all threads are done processing.
- */
- do {
- process_request(&fifos);
- cleanup_unused_threads();
- } while(!list_empty(&thread_registry) || !list_empty(&thread_registry_unused));
+ while (!_exit_now) {
+ _process_request(&fifos);
+ _cleanup_unused_threads();
+ if (!list_empty(&_thread_registry)
+ || !list_empty(&_thread_registry_unused))
+ _thread_registries_empty = 0;
+ else
+ _thread_registries_empty = 1;
+ }
- exit_dm_lib();
+ _exit_dm_lib();
#ifdef MCL_CURRENT
munlockall();
#endif
- pthread_mutex_destroy(&mutex);
+ pthread_mutex_destroy(&_global_mutex);
+
+ syslog(LOG_NOTICE, "dmeventd shutting down.");
+ closelog();
exit(EXIT_SUCCESS);
}
-
-/*
- * 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:
- */
Modified: devmapper/trunk/dmeventd/dmeventd.h
==============================================================================
--- devmapper/trunk/dmeventd/dmeventd.h (original)
+++ devmapper/trunk/dmeventd/dmeventd.h Sat Apr 7 09:09:48 2007
@@ -1,13 +1,52 @@
#ifndef __DMEVENTD_DOT_H__
#define __DMEVENTD_DOT_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,
+ DM_EVENT_CMD_HELLO,
+};
+
+/* Message passed between client and daemon. */
+struct dm_event_daemon_message {
+ uint32_t cmd;
+ uint32_t size;
+ char *data;
+};
+
+/* 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;
+};
+
+/* EXIT_SUCCESS 0 -- stdlib.h */
+/* EXIT_FAILURE 1 -- stdlib.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)
- __attribute((noreturn));
+#define EXIT_DESC_OPEN_FAILURE 4
+#define EXIT_OPEN_PID_FAILURE 5
+#define EXIT_FIFO_FAILURE 6
+#define EXIT_CHDIR_FAILURE 7
#endif /* __DMEVENTD_DOT_H__ */
Modified: devmapper/trunk/dmeventd/libdevmapper-event.c
==============================================================================
--- devmapper/trunk/dmeventd/libdevmapper-event.c (original)
+++ devmapper/trunk/dmeventd/libdevmapper-event.c Sat Apr 7 09:09:48 2007
@@ -1,4 +1,4 @@
- /*
+/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
@@ -27,46 +27,176 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <signal.h>
#include <sys/wait.h>
+#include <arpa/inet.h> /* for htonl, ntohl */
-/* Set by any of the external fxns the first time one of them is called */
-/* FIXME Unused */
-// static int _logging = 0;
+static int _sequence_nr = 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)
+struct dm_event_handler {
+ char *dso;
+
+ char *dev_name;
+
+ char *uuid;
+ int major;
+ int minor;
+ uint32_t timeout;
+
+ enum dm_event_mask mask;
+};
+
+static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
{
- char *p, *ret;
+ 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;
+}
- if ((p = strchr(*src, delimiter)))
- *p = 0;
+struct dm_event_handler *dm_event_handler_create(void)
+{
+ struct dm_event_handler *dmevh = NULL;
- if ((ret = dm_strdup(*src)))
- *src += strlen(ret) + 1;
+ if (!(dmevh = dm_malloc(sizeof(*dmevh))))
+ return NULL;
- if (p)
- *p = delimiter;
+ dmevh->dso = dmevh->dev_name = dmevh->uuid = NULL;
+ dmevh->major = dmevh->minor = 0;
+ dmevh->mask = 0;
+ dmevh->timeout = 0;
- return ret;
+ return dmevh;
}
-/* 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_destroy(struct dm_event_handler *dmevh)
+{
+ _dm_event_handler_clear_dev_info(dmevh);
+ if (dmevh->dso)
+ dm_free(dmevh->dso);
+ dm_free(dmevh);
+}
+
+int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *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;
+}
+
+int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_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;
+}
+
+int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *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 *dmevh, int major)
+{
+ int minor = dmevh->minor;
+
+ _dm_event_handler_clear_dev_info(dmevh);
+
+ dmevh->major = major;
+ dmevh->minor = minor;
+}
+
+void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor)
+{
+ int major = dmevh->major;
+
+ _dm_event_handler_clear_dev_info(dmevh);
+
+ dmevh->major = major;
+ dmevh->minor = minor;
+}
+
+void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
+ enum dm_event_mask evmask)
+{
+ dmevh->mask = evmask;
+}
+
+void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout)
+{
+ dmevh->timeout = timeout;
+}
+
+const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh)
+{
+ return dmevh->dso;
+}
+
+const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh)
+{
+ return dmevh->dev_name;
+}
+
+const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh)
+{
+ return dmevh->uuid;
+}
+
+int dm_event_handler_get_major(const struct dm_event_handler *dmevh)
+{
+ return dmevh->major;
+}
+
+int dm_event_handler_get_minor(const struct dm_event_handler *dmevh)
+{
+ return dmevh->minor;
+}
+
+int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh)
{
- char *p = msg->msg;
+ return dmevh->timeout;
+}
- if ((*dso_name = fetch_string(&p)) &&
- (*device = fetch_string(&p))) {
- *events = atoi(p);
+enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh)
+{
+ return dmevh->mask;
+}
+static int _check_message_id(struct dm_event_daemon_message *msg)
+{
+ int pid, seq_nr;
+
+ if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
+ (pid != getpid()) || (seq_nr != _sequence_nr)) {
+ log_error("Ignoring out-of-sequence reply from dmeventd. "
+ "Expected %d:%d but received %s", getpid(),
+ _sequence_nr, msg->data);
return 0;
}
- return -ENOMEM;
+ return 1;
}
/*
@@ -78,66 +208,116 @@
*
* 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 = 0;
+ int ret, i;
fd_set fds;
+ struct timeval tval = { 0, 0 };
+ size_t size = 2 * sizeof(uint32_t); /* status + size */
+ char *buf = alloca(size);
+ int header = 1;
- memset(msg, 0, sizeof(*msg));
- while (bytes < sizeof(*msg)) {
- do {
+ while (bytes < size) {
+ for (i = 0, ret = 0; (i < 20) && (ret < 1); i++) {
/* Watch daemon read FIFO for input. */
FD_ZERO(&fds);
FD_SET(fifos->server, &fds);
- ret = select(fifos->server+1, &fds, NULL, NULL, NULL);
+ tval.tv_sec = 1;
+ ret = select(fifos->server + 1, &fds, NULL, NULL,
+ &tval);
if (ret < 0 && errno != EINTR) {
- /* FIXME Log error */
+ log_error("Unable to read from event server");
return 0;
}
- } while (ret < 1);
+ }
+ if (ret < 1) {
+ log_error("Unable to read from event server.");
+ return 0;
+ }
- ret = read(fifos->server, msg, sizeof(*msg) - bytes);
+ ret = read(fifos->server, buf + bytes, size);
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
else {
- /* FIXME Log error */
+ log_error("Unable to read from event server.");
return 0;
}
}
bytes += ret;
+ 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;
+ header = 0;
+ }
+ }
+
+ if (bytes != size) {
+ if (msg->data)
+ dm_free(msg->data);
+ msg->data = NULL;
}
- return bytes == sizeof(*msg);
+ return bytes == size;
}
/* 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;
- while (bytes < sizeof(*msg)) {
+ size_t size = 2 * sizeof(uint32_t) + msg->size;
+ char *buf = alloca(size);
+ char drainbuf[128];
+ struct timeval tval = { 0, 0 };
+
+ *((uint32_t *)buf) = htonl(msg->cmd);
+ *((uint32_t *)buf + 1) = htonl(msg->size);
+ memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
+
+ /* drain the answer fifo */
+ while (1) {
+ FD_ZERO(&fds);
+ FD_SET(fifos->server, &fds);
+ tval.tv_usec = 100;
+ ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
+ if ((ret < 0) && (errno != EINTR)) {
+ log_error("Unable to talk to event daemon");
+ return 0;
+ }
+ if (ret == 0)
+ break;
+ read(fifos->server, drainbuf, 127);
+ }
+
+ 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)) {
- /* FIXME Log error */
+ log_error("Unable to talk to event daemon");
return 0;
}
} while (ret < 1);
- ret = write(fifos->client, msg, sizeof(*msg) - bytes);
+ ret = write(fifos->client, ((char *) buf) + bytes,
+ size - bytes);
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
else {
- /* fixme: log error */
+ log_error("Unable to talk to event daemon");
return 0;
}
}
@@ -145,366 +325,462 @@
bytes += ret;
}
- return bytes == sizeof(*msg);
+ return bytes == size;
}
-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)
-{
+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 = dev_name ? dev_name : "";
+ const char *fmt = "%d:%d %s %s %u %" PRIu32;
+ int msg_size;
memset(msg, 0, sizeof(*msg));
/*
* Set command and pack the arguments
* into ASCII message string.
*/
- msg->opcode.cmd = cmd;
-
- if (sizeof(msg->msg) <= (unsigned) snprintf(msg->msg, sizeof(msg->msg),
- "%s %s %u %"PRIu32,
- dso_name ? dso_name : "",
- device ? device : "",
- events, timeout)) {
- stack;
- return -ENAMETOOLONG;
+ msg->cmd = cmd;
+ if (cmd == DM_EVENT_CMD_HELLO)
+ fmt = "%d:%d HELLO";
+ if ((msg_size = dm_asprintf(&(msg->data), fmt, getpid(), _sequence_nr,
+ 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)) {
- stack;
- return -EIO;
- }
-
- if (!daemon_read(fifos, msg)) {
+ if (!_daemon_write(fifos, msg)) {
stack;
return -EIO;
}
- return msg->opcode.status;
-}
+ do {
+ if (!_daemon_read(fifos, msg)) {
+ stack;
+ return -EIO;
+ }
+ } while (!_check_message_id(msg));
-static volatile sig_atomic_t daemon_running = 0;
+ _sequence_nr++;
-static void daemon_running_signal_handler(int sig)
-{
- daemon_running = 1;
+ return (int32_t) msg->cmd;
}
/*
* 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.
+ * the events. I am currently test opening one of the fifos to
+ * ensure that the daemon is running and listening... I thought
+ * this would be less expensive than fork/exec'ing every time.
+ * Perhaps there is an even quicker/better way (no, checking the
+ * lock file is _not_ a better way).
*
* Returns: 1 on success, 0 otherwise
*/
-static int start_daemon(void)
+static int _start_daemon(struct dm_event_fifos *fifos)
{
- int pid, ret=0;
- void *old_hand;
- sigset_t set, oset;
+ int pid, ret = 0;
+ int status;
+ struct stat statbuf;
- /* 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.");
+ if (stat(fifos->client_path, &statbuf))
+ goto start_server;
+
+ if (!S_ISFIFO(statbuf.st_mode)) {
+ log_error("%s is not a fifo.", fifos->client_path);
return 0;
}
- if (sigemptyset(&set) || sigaddset(&set, SIGUSR1)) {
- log_error("Unable to fill signal set.");
- } else if (sigprocmask(SIG_UNBLOCK, &set, &oset)) {
- log_error("Can't unblock the potentially blocked signal SIGUSR1");
+ /* Anyone listening? If not, errno will be ENXIO */
+ fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
+ if (fifos->client >= 0) {
+ /* server is running and listening */
+
+ close(fifos->client);
+ return 1;
+ } else if (errno != ENXIO) {
+ /* problem */
+
+ log_error("%s: Can't open client fifo %s: %s",
+ __func__, fifos->client_path, strerror(errno));
+ stack;
+ return 0;
}
-
+
+ start_server:
+ /* server is not running */
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) {
- 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;
- }
- }
- /*
- * Sometimes, a single process may perform multiple calls
- * that result in a daemon starting and exiting. If we
- * don't reset this, the second (or greater) time the daemon
- * is started will cause this logic not to work.
- */
- daemon_running = 0;
- } else {
- signal(SIGUSR1, SIG_IGN); /* don't care about error */
+ log_error("Unable to fork.");
- /* 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();
+ else if (!pid) {
+ execvp(DMEVENTD_PATH, NULL);
exit(EXIT_FAILURE);
+ } else {
+ if (waitpid(pid, &status, 0) < 0)
+ log_error("Unable to start dmeventd: %s",
+ strerror(errno));
+ else if (WEXITSTATUS(status))
+ log_error("Unable to start dmeventd.");
+ else
+ ret = 1;
}
- /* FIXME What if old_hand is SIG_ERR? */
- if (signal(SIGUSR1, old_hand) == SIG_ERR)
- log_error("Unable to reset signal handler.");
-
- if (sigprocmask(SIG_SETMASK, &oset, NULL))
- log_error("Unable to reset signal mask.");
-
return ret;
}
/* 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? */
- /* 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));
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);
+ if (!_start_daemon(fifos)) {
+ stack;
return 0;
}
- /*
- * Open the fifo used to read from the daemon.
- * Allows daemon to create its write fifo...
- */
+ /* 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\n",
- __func__, fifos->server_path);
+ log_error("%s: open server fifo %s",
+ __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);
+ if (flock(fifos->server, LOCK_EX) < 0) {
+ log_error("%s: flock %s", __func__, fifos->server_path);
close(fifos->server);
return 0;
}
- /* Anyone listening? If not, errno will be ENXIO */
- while ((fifos->client = open(fifos->client_path,
- O_WRONLY | O_NONBLOCK)) < 0) {
- if (errno != ENXIO) {
- log_error("%s: Can't open client fifo %s: %s\n",
- __func__, fifos->client_path, strerror(errno));
- close(fifos->server);
- stack;
- return 0;
- }
-
- /* FIXME Unnecessary if daemon was started before calling this */
- if (!start_daemon()) {
- stack;
- return 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));
+ close(fifos->server);
+ stack;
+ return 0;
}
-
+
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\n", fifos->server_path);
+ log_error("flock unlock %s", fifos->server_path);
close(fifos->client);
close(fifos->server);
}
-/* Check, if a block device exists. */
-static int device_exists(char *device)
+/* Get uuid of a device */
+static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
{
- struct stat st_buf;
- char path2[PATH_MAX];
+ struct dm_task *dmt;
+ struct dm_info info;
- if (!device)
- return 0;
+ if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
+ log_error("_get_device_info: dm_task creation for info failed");
+ return NULL;
+ }
- if (device[0] == '/') /* absolute path */
- return !stat(device, &st_buf) && S_ISBLK(st_buf.st_mode);
+ 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);
+ }
- if (PATH_MAX <= snprintf(path2, PATH_MAX, "%s/%s", dm_dir(), device))
- return 0;
+ /* 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;
- return !stat(path2, &st_buf) && S_ISBLK(st_buf.st_mode);
+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,
- char *dso_name, 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;
- /* 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)) {
+ 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);
+ ret = _daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, 0, 0, 0, 0);
+ if (!ret)
+ 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;
}
-/* FIXME remove dso_name - use handle instead */
-/* FIXME Use uuid not path! */
/* External library interface. */
-int dm_event_register(char *dso_name, char *device_path,
- enum dm_event_type events)
+int dm_event_register_handler(const struct dm_event_handler *dmevh)
{
- int ret;
- struct dm_event_daemon_message msg;
+ int ret = 1, err;
+ const char *uuid;
+ struct dm_task *dmt;
+ struct dm_event_daemon_message msg = { 0, 0, NULL };
- if (!device_exists(device_path)) {
- log_error("%s: device not found", device_path);
+ if (!(dmt = _get_device_info(dmevh))) {
+ stack;
return 0;
}
- if ((ret = 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,
- strerror(-ret));
- return 0;
+ uuid = dm_task_get_uuid(dmt);
+
+ if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
+ dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
+ log_error("%s: event registration failed: %s",
+ dm_task_get_name(dmt),
+ msg.data ? msg.data : strerror(-err));
+ ret = 0;
}
- return 1;
+ if (msg.data)
+ dm_free(msg.data);
+
+ dm_task_destroy(dmt);
+
+ return ret;
}
-int dm_event_unregister(char *dso_name, char *device_path,
- enum dm_event_type events)
+int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
{
- int ret;
- struct dm_event_daemon_message msg;
+ int ret = 1, err;
+ const char *uuid;
+ struct dm_task *dmt;
+ struct dm_event_daemon_message msg = { 0, 0, NULL };
- if (!device_exists(device_path)) {
- log_error("%s: device not found", device_path);
+ if (!(dmt = _get_device_info(dmevh))) {
+ stack;
return 0;
}
- if ((ret = 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,
- strerror(-ret));
+ uuid = dm_task_get_uuid(dmt);
+
+ if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
+ dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
+ log_error("%s: event deregistration failed: %s",
+ dm_task_get_name(dmt),
+ msg.data ? msg.data : strerror(-err));
+ ret = 0;
+ }
+
+ if (msg.data)
+ dm_free(msg.data);
+
+ dm_task_destroy(dmt);
+
+ return ret;
+}
+
+/* Fetch a string off src and duplicate it into *dest. */
+/* FIXME: move to separate module to share with the daemon. */
+static char *_fetch_string(char **src, const int delimiter)
+{
+ 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 **uuid, enum dm_event_mask *evmask)
+{
+ char *id = NULL;
+ char *p = msg->data;
+
+ if ((id = _fetch_string(&p, ' ')) &&
+ (*dso_name = _fetch_string(&p, ' ')) &&
+ (*uuid = _fetch_string(&p, ' '))) {
+ *evmask = atoi(p);
+
+ dm_free(id);
return 0;
}
- return 1;
+ if (id)
+ dm_free(id);
+ return -ENOMEM;
}
-int dm_event_get_registered_device(char **dso_name, char **device_path,
- enum dm_event_type *events, int next)
+/*
+ * dm_event_get_registered_device
+ * @dso_name
+ * @device_path
+ * @mask
+ * @next
+ *
+ * Returns: 0 if handler found, error (-ENOMEM, -ENOENT) otherwise
+ */
+int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
{
- int ret;
- char *dso_name_arg = NULL, *device_path_arg = NULL;
- struct dm_event_daemon_message msg;
+ int ret = 0;
+ const char *uuid = NULL;
+ char *reply_dso = NULL, *reply_uuid = NULL;
+ enum dm_event_mask reply_mask = 0;
+ struct dm_task *dmt = NULL;
+ struct dm_event_daemon_message msg = { 0, 0, NULL };
- 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)
- dm_free(*dso_name);
- if (*device_path)
- dm_free(*device_path);
- *dso_name = dso_name_arg;
- *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 {
- if (!(*dso_name))
- *dso_name = dso_name_arg;
- if (!(*device_path))
- *device_path = device_path_arg;
+ 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;
}
-int dm_event_set_timeout(char *device_path, uint32_t timeout)
+#if 0 /* left out for now */
+
+static char *_skip_string(char *src, const int delimiter)
{
- struct dm_event_daemon_message msg;
+ src = srtchr(src, delimiter);
+ if (src && *(src + 1))
+ return src + 1;
+ return NULL;
+}
+
+int dm_event_set_timeout(const char *device_path, uint32_t timeout)
+{
+ struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!device_exists(device_path))
return -ENODEV;
- return do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
- NULL, device_path, 0, timeout);
+
+ 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 dm_event_get_timeout(const char *device_path, uint32_t *timeout)
{
int ret;
- struct dm_event_daemon_message msg;
+ struct dm_event_daemon_message msg = { 0, 0, NULL };
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);
+ if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
+ 0, 0))) {
+ char *p = _skip_string(msg.data, ' ');
+ if (!p) {
+ log_error("malformed reply from dmeventd '%s'\n",
+ msg.data);
+ return -EIO;
+ }
+ *timeout = atoi(p);
+ }
+ if (msg.data)
+ dm_free(msg.data);
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:
- */
+#endif
Modified: devmapper/trunk/dmeventd/libdevmapper-event.h
==============================================================================
--- devmapper/trunk/dmeventd/libdevmapper-event.h (original)
+++ devmapper/trunk/dmeventd/libdevmapper-event.h Sat Apr 7 09:09:48 2007
@@ -23,86 +23,84 @@
#include <stdint.h>
-/* FIXME This stuff must be configurable. */
+/*
+ * 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. */
+
+ 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 of a host adaptor. */
+
+ DM_EVENT_STATUS_MASK = 0xFF0000,
+ DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
+ DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occured */
-#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,
+ DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */
};
-/* 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;
-};
+#define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK
-/* 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. */
+struct dm_event_handler;
- DM_EVENT_SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
- DM_EVENT_TIMEOUT = 0x80, /* Timeout has occured */
-};
+struct dm_event_handler *dm_event_handler_create(void);
+void dm_event_handler_destroy(struct dm_event_handler *dmevh);
-/* 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 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.
-*/
-
-/* 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);
+/*
+ * Path of shared library to handle events.
+ *
+ * All of dso, device_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);
+
+/*
+ * Identify the device to monitor by exactly one of device_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 *device_name);
+
+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);
+void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout);
+
+/*
+ * 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);
+int dm_event_handler_get_timeout(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_mask evmask, void **user);
+int register_device(const char *device_name, const char *uuid, int major, int minor, void **user);
+int unregister_device(const char *device_name, const char *uuid, int major,
+ int minor, void **user);
#endif
Modified: devmapper/trunk/dmsetup/Makefile.in
==============================================================================
--- devmapper/trunk/dmsetup/Makefile.in (original)
+++ devmapper/trunk/dmsetup/Makefile.in Sat Apr 7 09:09:48 2007
@@ -30,11 +30,11 @@
include ../make.tmpl
dmsetup: $(OBJECTS) $(interfacedir)/libdevmapper.$(LIB_SUFFIX)
- $(CC) -o $@ $(OBJECTS) $(LDFLAGS) \
+ $(CC) -o $@ $(OBJECTS) $(CFLAGS) $(LDFLAGS) \
-L$(interfacedir) -L$(DESTDIR)/lib -ldevmapper $(LIBS)
dmsetup.static: $(OBJECTS) $(interfacedir)/libdevmapper.a
- $(CC) -o $@ $(OBJECTS) $(LDFLAGS) -static \
+ $(CC) -o $@ $(OBJECTS) $(CFLAGS) $(LDFLAGS) -static \
-L$(interfacedir) -L$(DESTDIR)/lib -ldevmapper $(LIBS)
install: $(INSTALL_TYPE)
Modified: devmapper/trunk/dmsetup/dmsetup.c
==============================================================================
--- devmapper/trunk/dmsetup/dmsetup.c (original)
+++ devmapper/trunk/dmsetup/dmsetup.c Sat Apr 7 09:09:48 2007
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2005 NEC Corperation
+ * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2005-2007 NEC Corperation
*
* This file is part of the device-mapper userspace tools.
*
@@ -114,6 +114,9 @@
NOOPENCOUNT_ARG,
NOTABLE_ARG,
OPTIONS_ARG,
+ SEPARATOR_ARG,
+ SHOWKEYS_ARG,
+ SORT_ARG,
TABLE_ARG,
TARGET_ARG,
TREE_ARG,
@@ -125,18 +128,30 @@
};
static int _switches[NUM_SWITCHES];
-static int _values[NUM_SWITCHES];
+static int _int_args[NUM_SWITCHES];
+static char *_string_args[NUM_SWITCHES];
static int _num_devices;
static char *_uuid;
-static char *_fields;
static char *_table;
static char *_target;
static char *_command;
static struct dm_tree *_dtree;
+static struct dm_report *_report;
/*
* Commands
*/
+
+typedef int (*command_fn) (int argc, char **argv, void *data);
+
+struct command {
+ const char *name;
+ const char *help;
+ int min_args;
+ int max_args;
+ command_fn fn;
+};
+
static int _parse_line(struct dm_task *dmt, char *buffer, const char *file,
int line)
{
@@ -211,72 +226,38 @@
r = 1;
out:
+#ifndef HAVE_GETLINE
dm_free(buffer);
- if (file)
- fclose(fp);
+#else
+ free(buffer);
+#endif
+ if (file && fclose(fp))
+ fprintf(stderr, "%s: fclose failed: %s", file, strerror(errno));
+
return r;
}
-static void _display_info_cols_noheadings(struct dm_task *dmt,
- struct dm_info *info)
-{
- const char *uuid;
-
- if (!info->exists)
- return;
-
- uuid = dm_task_get_uuid(dmt);
-
- if (_switches[OPTIONS_ARG])
- printf("%s\n", dm_task_get_name(dmt));
- else
- printf("%s:%d:%d:%s%s%s%s:%d:%d:%" PRIu32 ":%s\n",
- dm_task_get_name(dmt),
- info->major, info->minor,
- info->live_table ? "L" : "-",
- info->inactive_table ? "I" : "-",
- info->suspended ? "s" : "-",
- info->read_only ? "r" : "w",
- info->open_count, info->target_count, info->event_nr,
- uuid && *uuid ? uuid : "");
-}
+struct dmsetup_report_obj {
+ struct dm_task *task;
+ struct dm_info *info;
+};
-static void _display_info_cols(struct dm_task *dmt, struct dm_info *info)
+static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
{
- static int _headings = 0;
- const char *uuid;
+ struct dmsetup_report_obj obj;
if (!info->exists) {
- printf("Device does not exist.\n");
- return;
- }
-
- if (!_headings) {
- if (_switches[OPTIONS_ARG])
- printf("Name\n");
- else
- printf("Name Maj Min Stat Open Targ "
- "Event UUID\n");
- _headings = 1;
+ fprintf(stderr, "Device does not exist.\n");
+ return 0;
}
- if (_switches[OPTIONS_ARG])
- printf("%s\n", dm_task_get_name(dmt));
- else {
- printf("%-16s %3d %3d %s%s%s%s %4d %4d %6" PRIu32 " ",
- dm_task_get_name(dmt),
- info->major, info->minor,
- info->live_table ? "L" : "-",
- info->inactive_table ? "I" : "-",
- info->suspended ? "s" : "-",
- info->read_only ? "r" : "w",
- info->open_count, info->target_count, info->event_nr);
+ obj.task = dmt;
+ obj.info = info;
- if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
- printf("%s", uuid);
+ if (!dm_report_object(_report, &obj))
+ return 0;
- printf("\n");
- }
+ return 1;
}
static void _display_info_long(struct dm_task *dmt, struct dm_info *info)
@@ -326,9 +307,8 @@
if (!_switches[COLS_ARG])
_display_info_long(dmt, &info);
- else if (_switches[NOHEADINGS_ARG])
- _display_info_cols_noheadings(dmt, &info);
else
+ /* FIXME return code */
_display_info_cols(dmt, &info);
return info.exists ? 1 : 0;
@@ -343,8 +323,8 @@
if (!dm_task_set_uuid(dmt, _uuid))
return 0;
} else if (_switches[MAJOR_ARG] && _switches[MINOR_ARG]) {
- if (!dm_task_set_major(dmt, _values[MAJOR_ARG]) ||
- !dm_task_set_minor(dmt, _values[MINOR_ARG]))
+ if (!dm_task_set_major(dmt, _int_args[MAJOR_ARG]) ||
+ !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
return 0;
} else if (!optional) {
fprintf(stderr, "No device specified.\n");
@@ -435,19 +415,19 @@
if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
goto out;
- if (_switches[MAJOR_ARG] && !dm_task_set_major(dmt, _values[MAJOR_ARG]))
+ if (_switches[MAJOR_ARG] && !dm_task_set_major(dmt, _int_args[MAJOR_ARG]))
goto out;
- if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _values[MINOR_ARG]))
+ if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
goto out;
- if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _values[UID_ARG]))
+ if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _int_args[UID_ARG]))
goto out;
- if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _values[GID_ARG]))
+ if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _int_args[GID_ARG]))
goto out;
- if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _values[MODE_ARG]))
+ if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _int_args[MODE_ARG]))
goto out;
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
@@ -528,7 +508,11 @@
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++) {
@@ -915,7 +899,7 @@
void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
- char *params;
+ char *params, *c;
int cmd;
struct dm_names *names = (struct dm_names *) data;
const char *name = NULL;
@@ -978,6 +962,17 @@
if (data && !_switches[VERBOSE_ARG])
printf("%s: ", name);
if (target_type) {
+
+ /* Suppress encryption key */
+ if (!_switches[SHOWKEYS_ARG] &&
+ !strcmp(target_type, "crypt")) {
+ c = params;
+ while (*c && *c != ' ')
+ c++;
+ c++;
+ while (*c && *c != ' ')
+ *c++ = '0';
+ }
printf("%" PRIu64 " %" PRIu64 " %s %s",
start, length, target_type, params);
}
@@ -1477,6 +1472,194 @@
}
/*
+ * Report device information
+ */
+
+/* dm specific display functions */
+
+static int _int32_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute((unused)),
+ struct dm_report_field *field, const void *data,
+ void *private __attribute((unused)))
+{
+ const int32_t value = *(const int32_t *)data;
+
+ return dm_report_field_int32(rh, field, &value);
+}
+
+static int _uint32_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute((unused)),
+ struct dm_report_field *field, const void *data,
+ void *private __attribute((unused)))
+{
+ const uint32_t value = *(const int32_t *)data;
+
+ return dm_report_field_uint32(rh, field, &value);
+}
+
+static int _dm_name_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute((unused)),
+ struct dm_report_field *field, const void *data,
+ void *private __attribute((unused)))
+{
+ const char *name = dm_task_get_name((struct dm_task *) data);
+
+ return dm_report_field_string(rh, field, &name);
+}
+
+static int _dm_uuid_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute((unused)),
+ struct dm_report_field *field,
+ const void *data, void *private __attribute((unused)))
+{
+ const char *uuid = dm_task_get_uuid((struct dm_task *) data);
+
+ if (!uuid || !*uuid)
+ uuid = "";
+
+ return dm_report_field_string(rh, field, &uuid);
+}
+
+static int _dm_info_status_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute((unused)),
+ struct dm_report_field *field, const void *data,
+ void *private __attribute((unused)))
+{
+ char buf[5];
+ const char *s = buf;
+ struct dm_info *info = (struct dm_info *) data;
+
+ buf[0] = info->live_table ? 'L' : '-';
+ buf[1] = info->inactive_table ? 'I' : '-';
+ buf[2] = info->suspended ? 's' : '-';
+ buf[3] = info->read_only ? 'r' : 'w';
+ buf[4] = '\0';
+
+ return dm_report_field_string(rh, field, &s);
+}
+
+/* Report types */
+enum { DR_TASK = 1, DR_INFO = 2 };
+
+static void *_task_get_obj(void *obj)
+{
+ return ((struct dmsetup_report_obj *)obj)->task;
+}
+
+static void *_info_get_obj(void *obj)
+{
+ return ((struct dmsetup_report_obj *)obj)->info;
+}
+
+static const struct dm_report_object_type _report_types[] = {
+ { DR_TASK, "Mapped Device Name", "", _task_get_obj },
+ { DR_INFO, "Mapped Device Information", "", _info_get_obj },
+ { 0, "", "", NULL },
+};
+
+/* Column definitions */
+#define OFFSET_OF(strct, field) ((unsigned int) &((struct strct *)NULL)->field)
+#define STR (DM_REPORT_FIELD_TYPE_STRING)
+#define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
+#define FIELD_O(type, strct, sorttype, head, field, width, func, id, desc) {DR_ ## type, sorttype, OFFSET_OF(strct, field), width, id, head, &_ ## func ## _disp, desc},
+#define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},
+
+static const struct dm_report_field_type _report_fields[] = {
+/* *INDENT-OFF* */
+FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
+FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
+FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
+FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.")
+FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.")
+FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.")
+FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.")
+FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
+{0, 0, 0, 0, "", "", NULL, NULL},
+/* *INDENT-ON* */
+};
+
+#undef STR
+#undef NUM
+#undef FIELD_O
+#undef FIELD_F
+
+static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid";
+
+static int _report_init(struct command *c)
+{
+ char *options = (char *) default_report_options;
+ const char *keys = "";
+ const char *separator = " ";
+ int aligned = 1, headings = 1, buffered = 0;
+ uint32_t report_type = 0;
+ uint32_t flags = 0;
+ size_t len = 0;
+ int r = 0;
+
+ /* emulate old dmsetup behaviour */
+ if (_switches[NOHEADINGS_ARG]) {
+ separator = ":";
+ aligned = 0;
+ headings = 0;
+ }
+
+ if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) {
+ if (*_string_args[OPTIONS_ARG] != '+')
+ options = _string_args[OPTIONS_ARG];
+ else {
+ len = strlen(default_report_options) +
+ strlen(_string_args[OPTIONS_ARG]) + 1;
+ if (!(options = dm_malloc(len))) {
+ err("Failed to allocate option string.");
+ return 0;
+ }
+ if (dm_snprintf(options, len, "%s,%s",
+ default_report_options,
+ &_string_args[OPTIONS_ARG][1]) < 0) {
+ err("snprintf failed");
+ goto out;
+ }
+ }
+ }
+
+ if (_switches[SORT_ARG] && _string_args[SORT_ARG]) {
+ keys = _string_args[SORT_ARG];
+ buffered = 1;
+ if (c && (!strcmp(c->name, "status") || !strcmp(c->name, "table"))) {
+ err("--sort is not yet supported with status and table");
+ goto out;
+ }
+ }
+
+ if (_switches[SEPARATOR_ARG] && _string_args[SEPARATOR_ARG]) {
+ separator = _string_args[SEPARATOR_ARG];
+ aligned = 0;
+ }
+
+ if (aligned)
+ flags |= DM_REPORT_OUTPUT_ALIGNED;
+
+ if (buffered)
+ flags |= DM_REPORT_OUTPUT_BUFFERED;
+
+ if (headings)
+ flags |= DM_REPORT_OUTPUT_HEADINGS;
+
+ if (!(_report = dm_report_init(&report_type,
+ _report_types, _report_fields,
+ options, separator, flags, keys, NULL)))
+ goto out;
+
+ r = 1;
+
+out:
+ if (len)
+ dm_free(options);
+
+ return r;
+}
+
+/*
* List devices
*/
static int _ls(int argc, char **argv, void *data)
@@ -1490,20 +1673,13 @@
return _process_all(argc, argv, 0, _display_name);
}
+static int _help(int argc, char **argv, void *data);
+
/*
- * dispatch table
+ * Dispatch table
*/
-typedef int (*command_fn) (int argc, char **argv, void *data);
-
-struct command {
- const char *name;
- const char *help;
- int min_args;
- int max_args;
- command_fn fn;
-};
-
static struct command _commands[] = {
+ {"help", "[-c|-C|--columns]", 0, 0, _help},
{"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
"\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
"\t [-u|uuid <uuid>]\n"
@@ -1522,7 +1698,7 @@
{"info", "[<device>]", 0, 1, _info},
{"deps", "[<device>]", 0, 1, _deps},
{"status", "[<device>] [--target <target_type>]", 0, 1, _status},
- {"table", "[<device>] [--target <target_type>]", 0, 1, _status},
+ {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, 1, _status},
{"wait", "<device> [<event_nr>]", 0, 2, _wait},
{"mknodes", "[<device>]", 0, 1, _mknodes},
{"targets", "", 0, 0, _targets},
@@ -1537,14 +1713,18 @@
fprintf(out, "Usage:\n\n");
fprintf(out, "dmsetup [--version] [-v|--verbose [-v|--verbose ...]]\n"
- " [-r|--readonly] [--noopencount] [--nolockfs]\n\n");
+ " [-r|--readonly] [--noopencount] [--nolockfs]\n"
+ " [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
+ " [--noheadings] [--separator <separator>]\n\n");
for (i = 0; _commands[i].name; i++)
fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
fprintf(out, "\n<device> may be device name or -u <uuid> or "
"-j <major> -m <minor>\n");
+ fprintf(out, "<fields> are comma-separated. Use 'help -c' for list.\n");
fprintf(out, "Table_file contents may be supplied on stdin.\n");
fprintf(out, "Tree options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
- " [no]device, active, open, rw and uuid.\n\n");
+ " [no]device, active, open, rw and uuid.\n");
+ fprintf(out, "\n");
return;
}
@@ -1555,6 +1735,23 @@
"[-o offset] [-f|loop_device] [file]\n\n");
}
+static int _help(int argc __attribute((unused)),
+ char **argv __attribute((unused)),
+ void *data __attribute((unused)))
+{
+ _usage(stderr);
+
+ if (_switches[COLS_ARG]) {
+ _switches[OPTIONS_ARG] = 1;
+ _string_args[OPTIONS_ARG] = (char *) "help";
+ _switches[SORT_ARG] = 0;
+
+ (void) _report_init(NULL);
+ }
+
+ return 1;
+}
+
static struct command *_find_command(const char *name)
{
int i;
@@ -1653,7 +1850,7 @@
char *buf;
char *device;
- if (!(buf = dm_malloc(PATH_MAX)));
+ if (!(buf = dm_malloc(PATH_MAX)))
return NULL;
if (dev[0] == '/') {
@@ -1683,7 +1880,8 @@
/*
* create a table for a mapped device using the loop target.
*/
-static int _loop_table(char *table, size_t tlen, char *file, char *dev, off_t off)
+static int _loop_table(char *table, size_t tlen, char *file,
+ char *dev __attribute((unused)), off_t off)
{
struct stat fbuf;
off_t size, sectors;
@@ -1716,7 +1914,7 @@
#ifdef HAVE_SYS_STATVFS_H
if (fstatvfs(fd, &fsbuf))
- goto error;
+ goto error;
/* FIXME Fragment size currently unused */
blksize = fsbuf.f_frsize;
@@ -1724,7 +1922,7 @@
close(fd);
- if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
+ if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
(long long unsigned)sectors, file, off) < 0)
return 0;
@@ -1868,6 +2066,9 @@
{"noopencount", 0, &ind, NOOPENCOUNT_ARG},
{"notable", 0, &ind, NOTABLE_ARG},
{"options", 1, &ind, OPTIONS_ARG},
+ {"separator", 1, &ind, SEPARATOR_ARG},
+ {"showkeys", 0, &ind, SHOWKEYS_ARG},
+ {"sort", 1, &ind, SORT_ARG},
{"table", 1, &ind, TABLE_ARG},
{"target", 1, &ind, TARGET_ARG},
{"tree", 0, &ind, TREE_ARG},
@@ -1885,7 +2086,7 @@
* Zero all the index counts.
*/
memset(&_switches, 0, sizeof(_switches));
- memset(&_values, 0, sizeof(_values));
+ memset(&_int_args, 0, sizeof(_int_args));
namebase = strdup((*argv)[0]);
base = basename(namebase);
@@ -1897,17 +2098,17 @@
_switches[OPTIONS_ARG]++;
_switches[MAJOR_ARG]++;
_switches[MINOR_ARG]++;
- _fields = (char *) "name";
+ _string_args[OPTIONS_ARG] = (char *) "name";
if (*argc == 3) {
- _values[MAJOR_ARG] = atoi((*argv)[1]);
- _values[MINOR_ARG] = atoi((*argv)[2]);
+ _int_args[MAJOR_ARG] = atoi((*argv)[1]);
+ _int_args[MINOR_ARG] = atoi((*argv)[2]);
*argc -= 2;
*argv += 2;
} else if ((*argc == 2) &&
(2 == sscanf((*argv)[1], "%i:%i",
- &_values[MAJOR_ARG],
- &_values[MINOR_ARG]))) {
+ &_int_args[MAJOR_ARG],
+ &_int_args[MINOR_ARG]))) {
*argc -= 1;
*argv += 1;
} else {
@@ -1919,7 +2120,7 @@
return 1;
}
- if(!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
+ if (!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
r = _process_losetup_switches(base, argc, argv);
free(namebase);
return r;
@@ -1929,7 +2130,7 @@
optarg = 0;
optind = OPTIND_INIT;
- while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:j:m:M:no:ru:U:v",
+ while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:j:m:M:no:O:ru:U:v",
long_options, NULL)) != -1) {
if (c == ':' || c == '?')
return 0;
@@ -1941,17 +2142,25 @@
_switches[READ_ONLY]++;
if (c == 'j' || ind == MAJOR_ARG) {
_switches[MAJOR_ARG]++;
- _values[MAJOR_ARG] = atoi(optarg);
+ _int_args[MAJOR_ARG] = atoi(optarg);
}
if (c == 'm' || ind == MINOR_ARG) {
_switches[MINOR_ARG]++;
- _values[MINOR_ARG] = atoi(optarg);
+ _int_args[MINOR_ARG] = atoi(optarg);
}
if (c == 'n' || ind == NOTABLE_ARG)
_switches[NOTABLE_ARG]++;
if (c == 'o' || ind == OPTIONS_ARG) {
_switches[OPTIONS_ARG]++;
- _fields = optarg;
+ _string_args[OPTIONS_ARG] = optarg;
+ }
+ if (ind == SEPARATOR_ARG) {
+ _switches[SEPARATOR_ARG]++;
+ _string_args[SEPARATOR_ARG] = optarg;
+ }
+ if (c == 'O' || ind == SORT_ARG) {
+ _switches[SORT_ARG]++;
+ _string_args[SORT_ARG] = optarg;
}
if (c == 'v' || ind == VERBOSE_ARG)
_switches[VERBOSE_ARG]++;
@@ -1961,16 +2170,16 @@
}
if (c == 'G' || ind == GID_ARG) {
_switches[GID_ARG]++;
- _values[GID_ARG] = atoi(optarg);
+ _int_args[GID_ARG] = atoi(optarg);
}
if (c == 'U' || ind == UID_ARG) {
_switches[UID_ARG]++;
- _values[UID_ARG] = atoi(optarg);
+ _int_args[UID_ARG] = atoi(optarg);
}
if (c == 'M' || ind == MODE_ARG) {
_switches[MODE_ARG]++;
/* FIXME Accept modes as per chmod */
- _values[MODE_ARG] = (int) strtol(optarg, NULL, 8);
+ _int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
}
if ((ind == EXEC_ARG)) {
_switches[EXEC_ARG]++;
@@ -1988,6 +2197,8 @@
_switches[NOLOCKFS_ARG]++;
if ((ind == NOOPENCOUNT_ARG))
_switches[NOOPENCOUNT_ARG]++;
+ if ((ind == SHOWKEYS_ARG))
+ _switches[SHOWKEYS_ARG]++;
if ((ind == TABLE_ARG)) {
_switches[TABLE_ARG]++;
_table = optarg;
@@ -2008,13 +2219,7 @@
return 0;
}
- if (_switches[COLS_ARG] && _switches[OPTIONS_ARG] &&
- strcmp(_fields, "name")) {
- fprintf(stderr, "Only -o name is supported so far.\n");
- return 0;
- }
-
- if (_switches[TREE_ARG] && !_process_tree_options(_fields))
+ if (_switches[TREE_ARG] && !_process_tree_options(_string_args[OPTIONS_ARG]))
return 0;
if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
@@ -2062,6 +2267,9 @@
goto out;
}
+ if (_switches[COLS_ARG] && !_report_init(c))
+ goto out;
+
doit:
if (!c->fn(argc, argv, NULL)) {
fprintf(stderr, "Command failed\n");
@@ -2071,5 +2279,10 @@
r = 0;
out:
+ if (_report) {
+ dm_report_output(_report);
+ dm_report_free(_report);
+ }
+
return r;
}
Modified: devmapper/trunk/include/configure.h.in
==============================================================================
--- devmapper/trunk/include/configure.h.in (original)
+++ devmapper/trunk/include/configure.h.in Sat Apr 7 09:09:48 2007
@@ -3,6 +3,15 @@
/* Define to 1 if the `closedir' function returns void instead of `int'. */
#undef CLOSEDIR_VOID
+/* Path to dmeventd binary. */
+#undef DMEVENTD_PATH
+
+/* Path to dmeventd pidfile. */
+#undef DMEVENTD_PIDFILE
+
+/* Library version */
+#undef DM_LIB_VERSION
+
/* Define to 1 if canonicalize_file_name is available. */
#undef HAVE_CANONICALIZE_FILE_NAME
@@ -168,11 +177,9 @@
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
-/* Define to `__inline__' or `__inline' if that's what the C compiler
- calls it, or to nothing if 'inline' is not supported under any name. */
-#ifndef __cplusplus
+/* Define as `__inline' if that's what the C compiler calls it, or to nothing
+ if it is not supported. */
#undef inline
-#endif
/* Define to rpl_malloc if the replacement function should be used. */
#undef malloc
Modified: devmapper/trunk/lib/.exported_symbols
==============================================================================
--- devmapper/trunk/lib/.exported_symbols (original)
+++ devmapper/trunk/lib/.exported_symbols Sat Apr 7 09:09:48 2007
@@ -67,6 +67,7 @@
dm_tree_node_add_mirror_target_log
dm_tree_node_add_target_area
dm_tree_skip_lockfs
+dm_tree_use_no_flush_suspend
dm_is_dm_major
dm_mknodes
dm_malloc_aux
@@ -115,3 +116,16 @@
dm_split_lvm_name
dm_split_words
dm_snprintf
+dm_basename
+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
Modified: devmapper/trunk/lib/Makefile.in
==============================================================================
--- devmapper/trunk/lib/Makefile.in (original)
+++ devmapper/trunk/lib/Makefile.in Sat Apr 7 09:09:48 2007
@@ -24,6 +24,7 @@
libdm-file.c \
libdm-deptree.c \
libdm-string.c \
+ libdm-report.c \
mm/abi.c \
mm/dbg_malloc.c \
mm/pool.c \
@@ -39,8 +40,8 @@
LIB_SHARED = $(interface)/libdevmapper.so
endif
-CFLAGS += -DDEVICE_UID=@DEVICE_UID@ -DDEVICE_GID=@DEVICE_GID@ \
- -DDEVICE_MODE=@DEVICE_MODE@
+DEFS += -DDEVICE_UID=@DEVICE_UID@ -DDEVICE_GID=@DEVICE_GID@ \
+ -DDEVICE_MODE=@DEVICE_MODE@
include ../make.tmpl
@@ -85,7 +86,7 @@
.PHONY: distclean_lib distclean
distclean_lib:
- $(RM) libdm-common.h libdevmapper.pc
+ $(RM) libdevmapper.pc
distclean: distclean_lib
Modified: devmapper/trunk/lib/datastruct/hash.c
==============================================================================
--- devmapper/trunk/lib/datastruct/hash.c (original)
+++ devmapper/trunk/lib/datastruct/hash.c Sat Apr 7 09:09:48 2007
@@ -230,12 +230,14 @@
t->num_nodes = 0u;
}
-char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n)
+char *dm_hash_get_key(struct dm_hash_table *t __attribute((unused)),
+ struct dm_hash_node *n)
{
return n->key;
}
-void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n)
+void *dm_hash_get_data(struct dm_hash_table *t __attribute((unused)),
+ struct dm_hash_node *n)
{
return n->data;
}
Modified: devmapper/trunk/lib/ioctl/libdm-iface.c
==============================================================================
--- devmapper/trunk/lib/ioctl/libdm-iface.c (original)
+++ devmapper/trunk/lib/ioctl/libdm-iface.c Sat Apr 7 09:09:48 2007
@@ -149,7 +149,8 @@
if (!strcmp(name, nm)) {
if (number) {
*number = num;
- fclose(fl);
+ if (fclose(fl))
+ log_error("%s: fclose failed: %s", file, strerror(errno));
return 1;
}
dm_bit_set(_dm_bitset, num);
@@ -158,7 +159,8 @@
c = fgetc(fl);
} while (c != EOF && c != '\n');
}
- fclose(fl);
+ if (fclose(fl))
+ log_error("%s: fclose failed: %s", file, strerror(errno));
if (number) {
log_error("%s: No entry for %s found", file, name);
@@ -1322,7 +1324,7 @@
dir = dm_dir();
if (!(d = opendir(dir))) {
- fprintf(stderr, "opendir %s: %s", dir, strerror(errno));
+ log_error("opendir %s: %s", dir, strerror(errno));
return 0;
}
@@ -1335,9 +1337,8 @@
dm_task_run(dmt);
}
- if (closedir(d)) {
- fprintf(stderr, "closedir %s: %s", dir, strerror(errno));
- }
+ if (closedir(d))
+ log_error("closedir %s: %s", dir, strerror(errno));
return r;
}
@@ -1506,6 +1507,8 @@
t2 = task->head;
while (t1 && t2) {
+ while (t2->params[strlen(t2->params) - 1] == ' ')
+ t2->params[strlen(t2->params) - 1] = '\0';
if ((t1->start != t2->start) ||
(t1->length != t2->length) ||
(strcmp(t1->type, t2->type)) ||
Modified: devmapper/trunk/lib/libdevmapper.h
==============================================================================
--- devmapper/trunk/lib/libdevmapper.h (original)
+++ devmapper/trunk/lib/libdevmapper.h Sat Apr 7 09:09:48 2007
@@ -124,10 +124,10 @@
};
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 @@
* 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);
struct dm_tree_node *_dm_tree_add_new_dev_mode(struct dm_tree *tree,
const char *name,
@@ -298,16 +298,16 @@
* 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.
@@ -325,6 +325,16 @@
void dm_tree_skip_lockfs(struct dm_tree_node *dnode);
/*
+ * Set the 'noflush' flag when suspending devices.
+ * If the kernel supports it, instead of erroring outstanding I/O that
+ * cannot be completed, the I/O is queued and resubmitted when the
+ * device is resumed. This affects multipath devices when all paths
+ * have failed and queue_if_no_path is set, and mirror devices when
+ * block_on_error is set and the mirror log has failed.
+ */
+void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode);
+
+/*
* Is the uuid prefix present in the tree?
* Only returns 0 if every node was checked successfully.
* Returns 1 if the tree walk has to be aborted.
@@ -617,4 +627,97 @@
*/
int dm_snprintf(char *buf, size_t bufsize, const char *format, ...);
+/*
+ * Returns pointer to the last component of the path.
+ */
+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_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 0x000000FF
+#define DM_REPORT_FIELD_ALIGN_MASK 0x0000000F
+#define DM_REPORT_FIELD_ALIGN_LEFT 0x00000001
+#define DM_REPORT_FIELD_ALIGN_RIGHT 0x00000002
+#define DM_REPORT_FIELD_TYPE_MASK 0x000000F0
+#define DM_REPORT_FIELD_TYPE_STRING 0x00000010
+#define DM_REPORT_FIELD_TYPE_NUMBER 0x00000020
+
+struct dm_report;
+struct dm_report_field_type {
+ uint32_t type; /* object type id */
+ uint32_t flags; /* DM_REPORT_FIELD_* */
+ uint32_t offset; /* byte offset in the object */
+ int32_t width; /* default width */
+ const char id[32]; /* string used to specify the field */
+ const char heading[32]; /* string printed in header */
+ int (*report_fn)(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data,
+ void *private);
+ const char *desc; /* description of the field */
+};
+
+/*
+ * dm_report_init output_flags
+ */
+#define DM_REPORT_OUTPUT_MASK 0x000000FF
+#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 are provided for simple data types.
+ * They take care of allocating copies of the data.
+ */
+int dm_report_field_string(struct dm_report *rh, struct dm_report_field *field,
+ const char **data);
+int dm_report_field_int32(struct dm_report *rh, struct dm_report_field *field,
+ const int32_t *data);
+int dm_report_field_uint32(struct dm_report *rh, struct dm_report_field *field,
+ const uint32_t *data);
+int dm_report_field_int(struct dm_report *rh, struct dm_report_field *field,
+ const int *data);
+int dm_report_field_uint64(struct dm_report *rh, struct dm_report_field *field,
+ const uint64_t *data);
+
+/*
+ * For custom fields, allocate the data in 'mem' and use
+ * dm_report_field_set_value().
+ * 'sortvalue' may be NULL if it matches 'value'
+ */
+void dm_report_field_set_value(struct dm_report_field *field, const void *value,
+ const void *sortvalue);
+
#endif /* LIB_DEVICE_MAPPER_H */
Modified: devmapper/trunk/lib/libdm-common.c
==============================================================================
--- devmapper/trunk/lib/libdm-common.c (original)
+++ devmapper/trunk/lib/libdm-common.c Sat Apr 7 09:09:48 2007
@@ -38,8 +38,8 @@
* Library users can provide their own logging
* function.
*/
-static void _default_log(int level, const char *file, int line,
- const char *f, ...)
+static void _default_log(int level, const char *file __attribute((unused)),
+ int line __attribute((unused)), const char *f, ...)
{
va_list ap;
Added: devmapper/trunk/lib/libdm-common.h
==============================================================================
--- (empty file)
+++ devmapper/trunk/lib/libdm-common.h Sat Apr 7 09:09:48 2007
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004-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_DMCOMMON_H
+#define LIB_DMCOMMON_H
+
+#include "libdevmapper.h"
+
+struct target *create_target(uint64_t start,
+ uint64_t len,
+ const char *type, const char *params);
+
+int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major,
+ uid_t uid, gid_t gid, mode_t mode);
+int rm_dev_node(const char *dev_name);
+int rename_dev_node(const char *old_name, const char *new_name);
+void update_devs(void);
+
+#endif
Modified: devmapper/trunk/lib/libdm-deptree.c
==============================================================================
--- devmapper/trunk/lib/libdm-deptree.c (original)
+++ devmapper/trunk/lib/libdm-deptree.c Sat Apr 7 09:09:48 2007
@@ -133,6 +133,7 @@
struct dm_hash_table *uuids;
struct dm_tree_node root;
int skip_lockfs; /* 1 skips lockfs (for non-snapshots) */
+ int no_flush; /* 1 sets noflush (mirrors/multipath) */
};
/* FIXME Consider exporting this */
@@ -165,6 +166,7 @@
list_init(&dtree->root.uses);
list_init(&dtree->root.used_by);
dtree->skip_lockfs = 0;
+ dtree->no_flush = 0;
if (!(dtree->mem = dm_pool_create("dtree", 1024))) {
log_error("dtree pool creation failed");
@@ -922,13 +924,15 @@
}
static int _suspend_node(const char *name, uint32_t major, uint32_t minor,
- int skip_lockfs, struct dm_info *newinfo)
+ int skip_lockfs, int no_flush, struct dm_info *newinfo)
{
struct dm_task *dmt;
int r;
- log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")%s", name, major,
- minor, skip_lockfs ? "" : " with filesystem sync.");
+ log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")%s%s",
+ name, major, minor,
+ skip_lockfs ? "" : " with filesystem sync",
+ no_flush ? "" : " without device flush");
if (!(dmt = dm_task_create(DM_DEVICE_SUSPEND))) {
log_error("Suspend dm_task creation failed for %s", name);
@@ -947,6 +951,9 @@
if (skip_lockfs && !dm_task_skip_lockfs(dmt))
log_error("Failed to set skip_lockfs flag.");
+ if (no_flush && !dm_task_no_flush(dmt))
+ log_error("Failed to set no_flush flag.");
+
if ((r = dm_task_run(dmt)))
r = dm_task_get_info(dmt, newinfo);
@@ -1010,6 +1017,11 @@
dnode->dtree->skip_lockfs = 1;
}
+void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode)
+{
+ dnode->dtree->no_flush = 1;
+}
+
int dm_tree_suspend_children(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len)
@@ -1051,7 +1063,8 @@
continue;
if (!_suspend_node(name, info.major, info.minor,
- child->dtree->skip_lockfs, &newinfo)) {
+ child->dtree->skip_lockfs,
+ child->dtree->no_flush, &newinfo)) {
log_error("Unable to suspend %s (%" PRIu32
":%" PRIu32 ")", name, info.major,
info.minor);
@@ -1224,7 +1237,9 @@
return 1;
}
-static int _emit_areas_line(struct dm_task *dmt, struct load_segment *seg, char *params, size_t paramsize, int *pos)
+static int _emit_areas_line(struct dm_task *dmt __attribute((unused)),
+ struct load_segment *seg, char *params,
+ size_t paramsize, int *pos)
{
struct seg_area *area;
char devbuf[10];
Added: devmapper/trunk/lib/libdm-report.c
==============================================================================
--- (empty file)
+++ devmapper/trunk/lib/libdm-report.c Sat Apr 7 09:09:48 2007
@@ -0,0 +1,838 @@
+/*
+ * 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;
+ int32_t 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_report_field *field, const char **data)
+{
+ char *repstr;
+
+ if (!(repstr = dm_pool_strdup(rh->mem, *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_report_field *field, const int *data)
+{
+ const int value = *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_report_field *field, const uint32_t *data)
+{
+ const uint32_t value = *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_report_field *field, const int32_t *data)
+{
+ const int32_t value = *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_report_field *field, const uint64_t *data)
+{
+ const int value = *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 = "";
+ size_t id_len = 0;
+
+ for (f = 0; rh->fields[f].report_fn; f++)
+ if (strlen(rh->fields[f].id) > id_len)
+ id_len = strlen(rh->fields[f].id);
+
+ 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", (int) strlen(desc) + 7,
+ (int) strlen(desc) + 7,
+ "------------------------------------------");
+
+ }
+
+ /* FIXME Add line-wrapping at terminal width (or 80 cols) */
+ log_print(" %-*s - %s", (int) id_len, rh->fields[f].id, rh->fields[f].desc);
+ 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(" ");
+ if (strcasecmp(ws, "help") && strcmp(ws, "?"))
+ log_error("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_TYPE_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_TYPE_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];
+ int32_t width;
+ uint32_t align;
+
+ 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: Unable to allocate output line");
+ 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))) {
+ log_error("dm_report: Unable to extend output line");
+ goto bad;
+ }
+ } else {
+ if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
+ align = (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ?
+ DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
+ if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
+ if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
+ width, width, repstr) < 0) {
+ log_error("dm_report: left-aligned snprintf() failed");
+ goto bad;
+ }
+ if (!dm_pool_grow_object(rh->mem, buf, width)) {
+ log_error("dm_report: Unable to extend output line");
+ goto bad;
+ }
+ } else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
+ if (dm_snprintf(buf, sizeof(buf), "%*.*s",
+ width, width, repstr) < 0) {
+ log_error("dm_report: right-aligned snprintf() failed");
+ goto bad;
+ }
+ if (!dm_pool_grow_object(rh->mem, buf, width)) {
+ log_error("dm_report: Unable to extend output line");
+ goto bad;
+ }
+ }
+ }
+
+ if (!list_end(&row->fields, fh))
+ if (!dm_pool_grow_object(rh->mem, rh->separator,
+ strlen(rh->separator))) {
+ log_error("dm_report: Unable to extend output line");
+ goto bad;
+ }
+ list_del(&field->list);
+ }
+ if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
+ log_error("dm_report: Unable to terminate output line");
+ goto bad;
+ }
+ 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:
+ dm_pool_abandon_object(rh->mem);
+ return 0;
+}
Modified: devmapper/trunk/lib/libdm-string.c
==============================================================================
--- devmapper/trunk/lib/libdm-string.c (original)
+++ devmapper/trunk/lib/libdm-string.c Sat Apr 7 09:09:48 2007
@@ -37,7 +37,8 @@
* Split buffer into NULL-separated words in argv.
* Returns number of words.
*/
-int dm_split_words(char *buffer, unsigned max, unsigned ignore_comments,
+int dm_split_words(char *buffer, unsigned max,
+ unsigned ignore_comments __attribute((unused)),
char **argv)
{
unsigned arg;
@@ -121,3 +122,41 @@
return n;
}
+
+char *dm_basename(const char *path)
+{
+ char *p = strrchr(path, '/');
+
+ return p ? p + 1 : (char *) path;
+}
+
+int dm_asprintf(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;
+}
Modified: devmapper/trunk/lib/mm/dbg_malloc.c
==============================================================================
--- devmapper/trunk/lib/mm/dbg_malloc.c (original)
+++ devmapper/trunk/lib/mm/dbg_malloc.c Sat Apr 7 09:09:48 2007
@@ -26,9 +26,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;
@@ -232,7 +237,8 @@
}
}
-void *dm_malloc_aux(size_t s, const char *file, int line)
+void *dm_malloc_aux(size_t s, const char *file __attribute((unused)),
+ int line __attribute((unused)))
{
if (s > 50000000) {
log_error("Huge memory allocation (size %" PRIsize_t
Modified: devmapper/trunk/make.tmpl.in
==============================================================================
--- devmapper/trunk/make.tmpl.in (original)
+++ devmapper/trunk/make.tmpl.in Sat Apr 7 09:09:48 2007
@@ -163,13 +163,13 @@
ifeq ("@LIB_SUFFIX@","so")
$(LIB_SHARED): $(OBJECTS) $(LDDEPS)
$(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
- $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
+ $(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
endif
ifeq ("@LIB_SUFFIX@","dylib")
$(LIB_SHARED): $(OBJECTS) $(LDDEPS)
$(CC) -dynamiclib -dylib_current_version,$(LIB_VERSION) \
- $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
+ $(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
endif
$(LIB_STATIC): $(OBJECTS)
Modified: devmapper/trunk/man/dmsetup.8
==============================================================================
--- devmapper/trunk/man/dmsetup.8 (original)
+++ devmapper/trunk/man/dmsetup.8 Sat Apr 7 09:09:48 2007
@@ -3,6 +3,9 @@
dmsetup \- low level logical volume management
.SH SYNOPSIS
.ad l
+.B dmsetup help
+.I [-c|-C|--columns]
+.br
.B dmsetup create
.I device_name [-u uuid] [--notable | --table <table> | table_file]
.br
@@ -30,21 +33,28 @@
.B dmsetup rename
.I device_name new_name
.br
-.B dmsetup ls [--target target_type] [--exec command] [--tree [-o options]]
+.B dmsetup message
+.I device_name sector message
+.br
+.B dmsetup ls
+.I [--target target_type] [--exec command] [--tree [-o options]]
.br
.B dmsetup info
.I [device_name]
.br
-.B dmsetup info -c|-C|--columns [--noheadings] [-o name]
+.B dmsetup info -c|-C|--columns
+.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
.I [device_name]
.br
.B dmsetup deps
.I [device_name]
.br
-.B dmsetup status [--target target_type]
+.B dmsetup status
+.I [--target target_type]
.I [device_name]
.br
-.B dmsetup table [--target target_type]
+.B dmsetup table
+.I [--target target_type]
.I [device_name]
.br
.B dmsetup wait
@@ -58,6 +68,9 @@
.br
.B dmsetup version
.br
+.B dmsetup setgeometry
+.I device_name cyl head sect start
+.br
.B devmap_name
.I major minor
@@ -97,7 +110,7 @@
When creating a device, don't load any table.
.IP \fB-o|--options
.br
-Specify which fields to display. Only \fB-o\ name\fP is supported.
+Specify which fields to display.
.IP \fB-r|--readonly
.br
Set the table being loaded read-only.
@@ -130,6 +143,11 @@
.br
Outputs a list of (major, minor) pairs for devices referenced by the
live table for the specified device.
+.IP \fBhelp
+.I [-c|-C|--columns]
+.br
+Outputs a summary of the commands available, optionally including
+the list of report fields.
.IP \fBinfo
.I [device_name]
.br
@@ -148,6 +166,17 @@
Number of targets in the live table
.br
UUID
+.IP \fBinfo -c|-C|--columns
+.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
+.I [device_name]
+.br
+Output you can customise.
+Fields are comma-separated and chosen from the following list:
+name, major, minor, attr, open, segments, events, uuid.
+Attributes are: (L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.
+Precede the list with '+' to append
+to the default selection of columns instead of replacing it.
+Precede any sort_field with - for a reverse sort on that column.
.IP \fBls
.I [--target target_type]
.I [--exec command]
@@ -167,6 +196,10 @@
.br
Loads <table> or table_file into the inactive table slot for device_name.
If neither is supplied, reads a table from standard input.
+.IP \fBmessage
+.I device_name sector message
+.br
+Send message to target. If sector not needed use 0.
.IP \fBmknodes
.I [device_name]
.br
@@ -205,6 +238,10 @@
Un-suspends a device.
If an inactive table has been loaded, it becomes live.
Postponed I/O then gets re-queued for processing.
+.IP \fBsetgeometry
+.I device_name cyl head sect start
+.br
+Sets the device geometry to C/H/S.
.IP \fBstatus
.I [--target target_type]
.I [device_name]
Modified: devmapper/trunk/po/device-mapper.po
==============================================================================
--- devmapper/trunk/po/device-mapper.po (original)
+++ devmapper/trunk/po/device-mapper.po Sat Apr 7 09:09:48 2007
@@ -1,12 +1,14 @@
# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR Free Software Foundation, Inc.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL at ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2004-02-24 15:16+0000\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-01-29 19:56+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
"Language-Team: LANGUAGE <LL at li.org>\n"
@@ -14,138 +16,829 @@
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ioctl/libdevmapper.c:113
+#: datastruct/hash.c:96 datastruct/hash.c:109 ioctl/libdm-iface.c:247
+#: libdm-deptree.c:471 libdm-deptree.c:475 libdm-deptree.c:481
+#: libdm-deptree.c:491 libdm-deptree.c:502 libdm-deptree.c:594
+#: libdm-deptree.c:598 libdm-deptree.c:614 libdm-deptree.c:712
+#: libdm-deptree.c:721 libdm-deptree.c:863 libdm-deptree.c:959
+#: libdm-deptree.c:964 libdm-deptree.c:969 libdm-deptree.c:1020
+#: libdm-deptree.c:1025 libdm-deptree.c:1030 libdm-deptree.c:1064
+#: libdm-deptree.c:1093 libdm-deptree.c:1109 libdm-deptree.c:1120
+#: libdm-deptree.c:1226 libdm-deptree.c:1230 libdm-deptree.c:1267
+#: libdm-deptree.c:1279 libdm-deptree.c:1283 libdm-deptree.c:1290
+#: libdm-deptree.c:1297 libdm-deptree.c:1304 libdm-deptree.c:1312
+#: libdm-deptree.c:1318 libdm-deptree.c:1326 libdm-deptree.c:1333
+#: libdm-deptree.c:1341 libdm-deptree.c:1343 libdm-deptree.c:1348
+#: libdm-deptree.c:1354 libdm-deptree.c:1357 libdm-deptree.c:1365
+#: libdm-deptree.c:1381 libdm-deptree.c:1391 libdm-deptree.c:1415
+#: libdm-deptree.c:1460 libdm-deptree.c:1504 libdm-deptree.c:1511
+#: libdm-deptree.c:1518 libdm-deptree.c:1609 libdm-deptree.c:1618
+#: libdm-deptree.c:1637 libdm-deptree.c:1646 libdm-deptree.c:1655
+#: libdm-deptree.c:1667 libdm-deptree.c:1676 libdm-deptree.c:1685
+#: libdm-deptree.c:1697 libdm-deptree.c:1733 libdm-deptree.c:1752
+#: libdm-deptree.c:1795 libdm-deptree.c:1809 libdm-deptree.c:1820
+msgid "<backtrace>"
+msgstr ""
+
+#: ioctl/libdm-iface.c:143
#, c-format
-msgid "%s: open failed: %s"
+msgid "%s: fopen failed: %s"
+msgstr ""
+
+#: ioctl/libdm-iface.c:153 ioctl/libdm-iface.c:163
+#, c-format
+msgid "%s: fclose failed: %s"
+msgstr ""
+
+#: ioctl/libdm-iface.c:166
+#, c-format
+msgid "%s: No entry for %s found"
+msgstr ""
+
+#: ioctl/libdm-iface.c:193
+#, c-format
+msgid "%s: stat failed: %s"
+msgstr ""
+
+#: ioctl/libdm-iface.c:199
+#, c-format
+msgid "%s: Wrong inode type"
+msgstr ""
+
+#: ioctl/libdm-iface.c:202 ioctl/libdm-iface.c:214
+#, c-format
+msgid "%s: unlink failed: %s"
+msgstr ""
+
+#: ioctl/libdm-iface.c:208
+#, c-format
+msgid "%s: Wrong device number: (%u, %u) instead of (%u, %u)"
+msgstr ""
+
+#: ioctl/libdm-iface.c:237
+#, c-format
+msgid "Creating device %s (%u, %u)"
msgstr ""
-#: ioctl/libdevmapper.c:114
+#: ioctl/libdm-iface.c:241
+#, c-format
+msgid "%s: mknod failed: %s"
+msgstr ""
+
+#: ioctl/libdm-iface.c:297
msgid "Is device-mapper driver missing from kernel?"
msgstr ""
-#: ioctl/libdevmapper.c:555
+#: ioctl/libdm-iface.c:304
+#, c-format
+msgid "%s: open failed: %s"
+msgstr ""
+
+#: ioctl/libdm-iface.c:309
+msgid "Failed to set up list of device-mapper major numbers"
+msgstr ""
+
+#: ioctl/libdm-iface.c:316
+msgid "Failure to communicate with kernel device-mapper driver."
+msgstr ""
+
+#: ioctl/libdm-iface.c:778
msgid "Failed to get device-mapper version"
msgstr ""
-#: ioctl/libdevmapper.c:591
+#: ioctl/libdm-iface.c:814
#, c-format
msgid ""
-"device-mapper ioctl protocol version %d failed. Trying protocol version 1."
+"device-mapper ioctl protocol version %u failed. Trying protocol version 1."
msgstr ""
-#: ioctl/libdevmapper.c:595
+#: ioctl/libdm-iface.c:818
msgid "Using device-mapper ioctl protocol version 1"
msgstr ""
-#: ioctl/libdevmapper.c:603
+#: ioctl/libdm-iface.c:826
#, c-format
msgid "Incompatible libdevmapper %s%s and kernel driver %s"
msgstr ""
-#: ioctl/libdevmapper.c:760
+#: ioctl/libdm-iface.c:990
#, c-format
msgid "dm_task_set_newname: strdup(%s) failed"
msgstr ""
-#: ioctl/libdevmapper.c:780
+#: ioctl/libdm-iface.c:1000
+#, c-format
+msgid "dm_task_set_message: strdup(%s) failed"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1019
+msgid "dm_task_set_geometry: dm_malloc failed"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1024
+msgid "dm_task_set_geometry: sprintf failed"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1065
#, c-format
-msgid "create_target: malloc(%d) failed"
+msgid "create_target: malloc(%zu) failed"
msgstr ""
-#: ioctl/libdevmapper.c:787
+#: ioctl/libdm-iface.c:1073
msgid "create_target: strdup(params) failed"
msgstr ""
-#: ioctl/libdevmapper.c:792
+#: ioctl/libdm-iface.c:1078
msgid "create_target: strdup(type) failed"
msgstr ""
-#: ioctl/libdevmapper.c:831
+#: ioctl/libdm-iface.c:1117
#, c-format
msgid "t->params= '%s'"
msgstr ""
-#: ioctl/libdevmapper.c:864
+#: ioctl/libdm-iface.c:1185
+msgid "targets and message are incompatible"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1190
msgid "targets and newname are incompatible"
msgstr ""
-#: ioctl/libdevmapper.c:902
-msgid "Missing major number for persistent device"
+#: ioctl/libdm-iface.c:1195
+msgid "targets and geometry are incompatible"
msgstr ""
-#: ioctl/libdevmapper.c:939 ioctl/libdevmapper.c:964
-msgid "Failed to create device-mapper task struct"
+#: ioctl/libdm-iface.c:1200
+msgid "message and newname are incompatible"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1205
+msgid "geometry and newname are incompatible"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1210
+msgid "geometry and message are incompatible"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1215
+msgid "message is required with sector"
msgstr ""
-#: ioctl/libdevmapper.c:1008
+#: ioctl/libdm-iface.c:1255
+msgid "Missing major number for persistent device."
+msgstr ""
+
+#: ioctl/libdm-iface.c:1265
#, c-format
-msgid "Internal error: unknown device-mapper task %d"
+msgid "Unable to find name for device (%u:%u)"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1269
+#, c-format
+msgid "device (%u:%u) is %s for compatibility with old kernel"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1327
+#, c-format
+msgid "opendir %s: %s"
msgstr ""
-#: ioctl/libdevmapper.c:1024
-msgid "Couldn't create ioctl argument"
+#: ioctl/libdm-iface.c:1341
+#, c-format
+msgid "closedir %s: %s"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1399 ioctl/libdm-iface.c:1427 ioctl/libdm-iface.c:1478
+msgid "Failed to create device-mapper task struct"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1465
+msgid "Failed to revert device creation."
msgstr ""
-#: ioctl/libdevmapper.c:1032
+#: ioctl/libdm-iface.c:1545
+msgid "Couldn't create ioctl argument."
+msgstr ""
+
+#: ioctl/libdm-iface.c:1557
+#, c-format
+msgid "dm %s %s %s%s%s %s%.0d%s%.0d%s%s%c%c%s %.0llu %s [%u]"
+msgstr ""
+
+#: ioctl/libdm-iface.c:1581 ioctl/libdm-iface.c:1586
#, c-format
-msgid "dm %s %s %s %s"
+msgid "device-mapper: %s ioctl failed: %s"
msgstr ""
-#: ioctl/libdevmapper.c:1041 ioctl/libdevmapper.c:1044
+#: ioctl/libdm-iface.c:1616
#, c-format
-msgid "device-mapper ioctl cmd %d failed: %s"
+msgid "Internal error: unknown device-mapper task %d"
msgstr ""
-#: libdm-common.c:94
+#: ioctl/libdm-iface.c:1653
+msgid "Warning: libdevmapper buffer too small for data"
+msgstr ""
+
+#: libdm-common.c:99
#, c-format
-msgid "dm_task_create: malloc(%d) failed"
+msgid "dm_task_create: malloc(%zu) failed"
msgstr ""
-#: libdm-common.c:126
+#: libdm-common.c:141
#, c-format
msgid "dm_task_set_name: Device %s not found"
msgstr ""
-#: libdm-common.c:135
+#: libdm-common.c:150
#, c-format
msgid "dm_task_set_name: strdup(%s) failed"
msgstr ""
-#: libdm-common.c:150
+#: libdm-common.c:165
#, c-format
msgid "dm_task_set_uuid: strdup(%s) failed"
msgstr ""
-#: libdm-common.c:160
+#: libdm-common.c:234
+#, c-format
+msgid "%s: matchpathcon %07o failed: %s"
+msgstr ""
+
+#: libdm-common.c:239
#, c-format
-msgid "Setting major: %d"
+msgid "Setting SELinux context for %s to %s."
msgstr ""
-#: libdm-common.c:168
+#: libdm-common.c:242
#, c-format
-msgid "Setting minor: %d"
+msgid "%s: lsetfilecon failed: %s"
msgstr ""
-#: libdm-common.c:201 libdm-common.c:235
+#: libdm-common.c:264 libdm-common.c:311
#, c-format
msgid "A non-block device file at '%s' is already present"
msgstr ""
-#: libdm-common.c:210 libdm-common.c:245 libdm-common.c:271
+#: libdm-common.c:274 libdm-common.c:321 libdm-common.c:347
#, c-format
msgid "Unable to unlink device node for '%s'"
msgstr ""
-#: libdm-common.c:217
+#: libdm-common.c:282
#, c-format
msgid "Unable to make device node for '%s'"
msgstr ""
-#: libdm-common.c:252
+#: libdm-common.c:288
+#, c-format
+msgid "%s: chown failed: %s"
+msgstr ""
+
+#: libdm-common.c:328
#, c-format
msgid "Unable to rename device node from '%s' to '%s'"
msgstr ""
-#: libdm-common.c:326
+#: libdm-common.c:407
msgid "Insufficient memory to stack mknod operation"
msgstr ""
+
+#: libdm-common.c:504
+msgid "Failed to get driver version"
+msgstr ""
+
+#: libdm-deptree.c:157
+msgid "dm_tree_create malloc failed"
+msgstr ""
+
+#: libdm-deptree.c:169
+msgid "dtree pool creation failed"
+msgstr ""
+
+#: libdm-deptree.c:175
+msgid "dtree hash creation failed"
+msgstr ""
+
+#: libdm-deptree.c:182
+msgid "dtree uuid hash creation failed"
+msgstr ""
+
+#: libdm-deptree.c:220
+msgid "dtree link allocation failed"
+msgstr ""
+
+#: libdm-deptree.c:314
+msgid "_create_dm_tree_node alloc failed"
+msgstr ""
+
+#: libdm-deptree.c:334
+msgid "dtree node hash insertion failed"
+msgstr ""
+
+#: libdm-deptree.c:341
+msgid "dtree uuid hash insertion failed"
+msgstr ""
+
+#: libdm-deptree.c:394
+msgid "deps dm_task creation failed"
+msgstr ""
+
+#: libdm-deptree.c:399
+#, c-format
+msgid "_deps: failed to set major for (%u:%u)"
+msgstr ""
+
+#: libdm-deptree.c:405
+#, c-format
+msgid "_deps: failed to set minor for (%u:%u)"
+msgstr ""
+
+#: libdm-deptree.c:411
+#, c-format
+msgid "_deps: task run failed for (%u:%u)"
+msgstr ""
+
+#: libdm-deptree.c:417
+#, c-format
+msgid "_deps: failed to get info for (%u:%u)"
+msgstr ""
+
+#: libdm-deptree.c:428
+#, c-format
+msgid "Inconsistent dtree major number: %u != %u"
+msgstr ""
+
+#: libdm-deptree.c:433
+#, c-format
+msgid "Inconsistent dtree minor number: %u != %u"
+msgstr ""
+
+#: libdm-deptree.c:438 libdm-deptree.c:577 libdm-deptree.c:606
+msgid "name pool_strdup failed"
+msgstr ""
+
+#: libdm-deptree.c:442 libdm-deptree.c:581
+msgid "uuid pool_strdup failed"
+msgstr ""
+
+#: libdm-deptree.c:520
+msgid "_node_clear_table failed: missing info"
+msgstr ""
+
+#: libdm-deptree.c:525
+msgid "_node_clear_table failed: missing name"
+msgstr ""
+
+#: libdm-deptree.c:533
+#, c-format
+msgid "Clearing inactive table %s (%u:%u)"
+msgstr ""
+
+#: libdm-deptree.c:538
+#, c-format
+msgid "Table clear dm_task creation failed for %s"
+msgstr ""
+
+#: libdm-deptree.c:544
+#, c-format
+msgid "Failed to set device number for %s table clear"
+msgstr ""
+
+#: libdm-deptree.c:552
+#, c-format
+msgid "_node_clear_table failed: info missing after running task for %s"
+msgstr ""
+
+#: libdm-deptree.c:791
+msgid "_info_by_dev: dm_task creation failed"
+msgstr ""
+
+#: libdm-deptree.c:796
+msgid "_info_by_dev: Failed to set device number"
+msgstr ""
+
+#: libdm-deptree.c:802 libdm-deptree.c:831 libdm-deptree.c:866
+#: libdm-deptree.c:897 libdm-deptree.c:930 libdm-deptree.c:1191
+#: libdm-deptree.c:1456
+msgid "Failed to disable open_count"
+msgstr ""
+
+#: libdm-deptree.c:817
+#, c-format
+msgid "Removing %s (%u:%u)"
+msgstr ""
+
+#: libdm-deptree.c:820
+#, c-format
+msgid "Deactivation dm_task creation failed for %s"
+msgstr ""
+
+#: libdm-deptree.c:825
+#, c-format
+msgid "Failed to set device number for %s deactivation"
+msgstr ""
+
+#: libdm-deptree.c:850
+#, c-format
+msgid "Renaming %s (%u:%u) to %s"
+msgstr ""
+
+#: libdm-deptree.c:853
+#, c-format
+msgid "Rename dm_task creation failed for %s"
+msgstr ""
+
+#: libdm-deptree.c:858
+#, c-format
+msgid "Failed to set name for %s rename."
+msgstr ""
+
+#: libdm-deptree.c:883
+#, c-format
+msgid "Resuming %s (%u:%u)"
+msgstr ""
+
+#: libdm-deptree.c:886 libdm-deptree.c:919
+#, c-format
+msgid "Suspend dm_task creation failed for %s"
+msgstr ""
+
+#: libdm-deptree.c:891
+#, c-format
+msgid "Failed to set device number for %s resumption."
+msgstr ""
+
+#: libdm-deptree.c:913
+#, c-format
+msgid "Suspending %s (%u:%u)%s%s"
+msgstr ""
+
+#: libdm-deptree.c:924
+#, c-format
+msgid "Failed to set device number for %s suspension."
+msgstr ""
+
+#: libdm-deptree.c:933
+msgid "Failed to set skip_lockfs flag."
+msgstr ""
+
+#: libdm-deptree.c:936
+msgid "Failed to set no_flush flag."
+msgstr ""
+
+#: libdm-deptree.c:983
+#, c-format
+msgid "Unable to deactivate %s (%u:%u)"
+msgstr ""
+
+#: libdm-deptree.c:1049
+#, c-format
+msgid "Unable to suspend %s (%u:%u)"
+msgstr ""
+
+#: libdm-deptree.c:1127
+#, c-format
+msgid "Failed to rename %s (%u:%u) to %s"
+msgstr ""
+
+#: libdm-deptree.c:1140 libdm-deptree.c:1531
+#, c-format
+msgid "Unable to resume %s (%u:%u)"
+msgstr ""
+
+#: libdm-deptree.c:1161
+#, c-format
+msgid "Creating %s"
+msgstr ""
+
+#: libdm-deptree.c:1164
+#, c-format
+msgid "Create dm_task creation failed for %s"
+msgstr ""
+
+#: libdm-deptree.c:1169
+#, c-format
+msgid "Failed to set device name for %s"
+msgstr ""
+
+#: libdm-deptree.c:1174
+#, c-format
+msgid "Failed to set uuid for %s"
+msgstr ""
+
+#: libdm-deptree.c:1181
+#, c-format
+msgid "Failed to set device number for %s creation."
+msgstr ""
+
+#: libdm-deptree.c:1186 libdm-deptree.c:1451
+#, c-format
+msgid "Failed to set read only flag for %s"
+msgstr ""
+
+#: libdm-deptree.c:1206
+#, c-format
+msgid "Failed to format %s device number for %s as dm target (%u,%u)"
+msgstr ""
+
+#: libdm-deptree.c:1387
+#, c-format
+msgid "Adding target: %lu %lu %s %s"
+msgstr ""
+
+#: libdm-deptree.c:1407
+msgid "Insufficient space for target parameters."
+msgstr ""
+
+#: libdm-deptree.c:1420
+#, c-format
+msgid "Insufficient space in params[%zu] for target parameters."
+msgstr ""
+
+#: libdm-deptree.c:1426
+msgid "Target parameter size too big. Aborting."
+msgstr ""
+
+#: libdm-deptree.c:1437
+#, c-format
+msgid "Loading %s table"
+msgstr ""
+
+#: libdm-deptree.c:1440
+#, c-format
+msgid "Reload dm_task creation failed for %s"
+msgstr ""
+
+#: libdm-deptree.c:1446
+#, c-format
+msgid "Failed to set device number for %s reload."
+msgstr ""
+
+#: libdm-deptree.c:1463
+msgid "Failed to suppress reload of identical tables."
+msgstr ""
+
+#: libdm-deptree.c:1468
+#, c-format
+msgid "Suppressed %s identical table reload."
+msgstr ""
+
+#: libdm-deptree.c:1559
+msgid "Failed to get uuid for dtree node."
+msgstr ""
+
+#: libdm-deptree.c:1581
+msgid "dtree node segment allocation failed"
+msgstr ""
+
+#: libdm-deptree.c:1612 libdm-deptree.c:1640 libdm-deptree.c:1649
+#, c-format
+msgid "Couldn't find snapshot origin uuid %s."
+msgstr ""
+
+#: libdm-deptree.c:1715 libdm-deptree.c:1813
+msgid "Internal error: Attempt to add target area to missing segment."
+msgstr ""
+
+#: libdm-deptree.c:1723
+msgid "log uuid pool_strdup failed"
+msgstr ""
+
+#: libdm-deptree.c:1728
+#, c-format
+msgid "Couldn't find mirror log uuid %s."
+msgstr ""
+
+#: libdm-deptree.c:1762
+msgid "Failed to allocate target segment area."
+msgstr ""
+
+#: libdm-deptree.c:1785
+msgid "dm_tree_node_add_target_area called without device"
+msgstr ""
+
+#: libdm-deptree.c:1791
+#, c-format
+msgid "Couldn't find area uuid %s."
+msgstr ""
+
+#: libdm-deptree.c:1798
+#, c-format
+msgid "Device %s not found."
+msgstr ""
+
+#: libdm-deptree.c:1803
+#, c-format
+msgid "Device %s is not a block device."
+msgstr ""
+
+#: libdm-file.c:28
+#, c-format
+msgid "Creating directory \"%s\""
+msgstr ""
+
+#: libdm-file.c:36 libdm-file.c:47
+#, c-format
+msgid "%s: mkdir failed: %s"
+msgstr ""
+
+#: libdm-file.c:71
+#, c-format
+msgid "Directory \"%s\" not found"
+msgstr ""
+
+#: libdm-report.c:108
+msgid "dm_report_field_string: dm_pool_strdup failed"
+msgstr ""
+
+#: libdm-report.c:126 libdm-report.c:131
+msgid "dm_report_field_int: dm_pool_alloc failed"
+msgstr ""
+
+#: libdm-report.c:136
+#, c-format
+msgid "dm_report_field_int: int too big: %d"
+msgstr ""
+
+#: libdm-report.c:155 libdm-report.c:160
+msgid "dm_report_field_uint32: dm_pool_alloc failed"
+msgstr ""
+
+#: libdm-report.c:165
+#, c-format
+msgid "dm_report_field_uint32: uint32 too big: %u"
+msgstr ""
+
+#: libdm-report.c:184 libdm-report.c:189
+msgid "dm_report_field_int32: dm_pool_alloc failed"
+msgstr ""
+
+#: libdm-report.c:194
+#, c-format
+msgid "dm_report_field_int32: int32 too big: %d"
+msgstr ""
+
+#: libdm-report.c:213 libdm-report.c:218
+msgid "dm_report_field_uint64: dm_pool_alloc failed"
+msgstr ""
+
+#: libdm-report.c:223
+#, c-format
+msgid "dm_report_field_uint64: uint64 too big: %d"
+msgstr ""
+
+#: libdm-report.c:264 libdm-report.c:428
+msgid " "
+msgstr ""
+
+#: libdm-report.c:265
+#, c-format
+msgid "%s Fields"
+msgstr ""
+
+#: libdm-report.c:266
+#, c-format
+msgid "%*.*s"
+msgstr ""
+
+#: libdm-report.c:273
+#, c-format
+msgid " %-*s - %s"
+msgstr ""
+
+#: libdm-report.c:291
+#, c-format
+msgid "dm_report: field not match: %s"
+msgstr ""
+
+#: libdm-report.c:316 libdm-report.c:347
+msgid "dm_report: struct field_properties allocation failed"
+msgstr ""
+
+#: libdm-report.c:361
+#, c-format
+msgid "dm_report: Ignoring duplicate sort field: %s"
+msgstr ""
+
+#: libdm-report.c:393
+msgid "dm_report: Missing sort field name"
+msgstr ""
+
+#: libdm-report.c:430
+#, c-format
+msgid "Unrecognised field: %.*s"
+msgstr ""
+
+#: libdm-report.c:452
+#, c-format
+msgid "dm_report: Unrecognised field: %.*s"
+msgstr ""
+
+#: libdm-report.c:474
+msgid "dm_report_init: dm_malloc failed"
+msgstr ""
+
+#: libdm-report.c:506
+msgid "dm_report_init: allocation of memory pool failed"
+msgstr ""
+
+#: libdm-report.c:552
+msgid "dm_report_object: struct row allocation failed"
+msgstr ""
+
+#: libdm-report.c:562
+msgid "dm_report_object: row sort value structure allocation failed"
+msgstr ""
+
+#: libdm-report.c:573
+msgid "dm_report_object: struct dm_report_field allocation failed"
+msgstr ""
+
+#: libdm-report.c:586
+#, c-format
+msgid "dm_report_object: report function failed for field %s"
+msgstr ""
+
+#: libdm-report.c:626
+msgid "dm_report: dm_pool_begin_object failed for headings"
+msgstr ""
+
+#: libdm-report.c:640
+msgid "dm_report: snprintf heading failed"
+msgstr ""
+
+#: libdm-report.c:644 libdm-report.c:649 libdm-report.c:656 libdm-report.c:661
+msgid "dm_report: Failed to generate report headings for printing"
+msgstr ""
+
+#: libdm-report.c:664 libdm-report.c:826
+#, c-format
+msgid "%s"
+msgstr ""
+
+#: libdm-report.c:727
+msgid "dm_report: sort array allocation failed"
+msgstr ""
+
+#: libdm-report.c:770
+msgid "dm_report: Unable to allocate output line"
+msgstr ""
+
+#: libdm-report.c:784 libdm-report.c:798 libdm-report.c:808 libdm-report.c:817
+msgid "dm_report: Unable to extend output line"
+msgstr ""
+
+#: libdm-report.c:794
+msgid "dm_report: left-aligned snprintf() failed"
+msgstr ""
+
+#: libdm-report.c:804
+msgid "dm_report: right-aligned snprintf() failed"
+msgstr ""
+
+#: libdm-report.c:823
+msgid "dm_report: Unable to terminate output line"
+msgstr ""
+
+#: mm/dbg_malloc.c:26
+msgid "Internal error: dm_strdup called with NULL pointer"
+msgstr ""
+
+#: mm/dbg_malloc.c:63 mm/dbg_malloc.c:238
+#, c-format
+msgid "Huge memory allocation (size %zu) rejected - metadata corruption?"
+msgstr ""
+
+#: mm/dbg_malloc.c:69
+#, c-format
+msgid "couldn't allocate any memory, size = %zu"
+msgstr ""
+
+#: mm/dbg_malloc.c:193
+msgid "You have a memory leak:"
+msgstr ""
+
+#: mm/dbg_malloc.c:208
+#, c-format
+msgid "block %d at %p, size %zu\t [%s]"
+msgstr ""
+
+#: mm/dbg_malloc.c:215
+#, c-format
+msgid "%ld bytes leaked in total"
+msgstr ""
+
+#: mm/pool-fast.c:43
+#, c-format
+msgid "Couldn't create memory pool %s (size %zu)"
+msgstr ""
+
+#: mm/pool-fast.c:132
+msgid "Internal error: pool_free asked to free pointer not in pool"
+msgstr ""
+
+#: mm/pool-fast.c:221
+#, c-format
+msgid "Out of memory. Requested %zu bytes."
+msgstr ""
More information about the pkg-lvm-commits
mailing list