Home | History | Annotate | Line # | Download | only in dmeventd
      1  1.1  haad /*	$NetBSD: dmeventd.c,v 1.1.1.1 2008/12/22 00:18:53 haad Exp $	*/
      2  1.1  haad 
      3  1.1  haad /*
      4  1.1  haad  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
      5  1.1  haad  *
      6  1.1  haad  * This file is part of the device-mapper userspace tools.
      7  1.1  haad  *
      8  1.1  haad  * This copyrighted material is made available to anyone wishing to use,
      9  1.1  haad  * modify, copy, or redistribute it subject to the terms and conditions
     10  1.1  haad  * of the GNU Lesser General Public License v.2.1.
     11  1.1  haad  *
     12  1.1  haad  * You should have received a copy of the GNU Lesser General Public License
     13  1.1  haad  * along with this program; if not, write to the Free Software Foundation,
     14  1.1  haad  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     15  1.1  haad  */
     16  1.1  haad 
     17  1.1  haad /*
     18  1.1  haad  * dmeventd - dm event daemon to monitor active mapped devices
     19  1.1  haad  */
     20  1.1  haad 
     21  1.1  haad #define _GNU_SOURCE
     22  1.1  haad #define _FILE_OFFSET_BITS 64
     23  1.1  haad 
     24  1.1  haad #include "configure.h"
     25  1.1  haad #include "libdevmapper.h"
     26  1.1  haad #include "libdevmapper-event.h"
     27  1.1  haad #include "dmeventd.h"
     28  1.1  haad //#include "libmultilog.h"
     29  1.1  haad #include "dm-logging.h"
     30  1.1  haad 
     31  1.1  haad #include <dlfcn.h>
     32  1.1  haad #include <errno.h>
     33  1.1  haad #include <pthread.h>
     34  1.1  haad #include <sys/file.h>
     35  1.1  haad #include <sys/stat.h>
     36  1.1  haad #include <sys/wait.h>
     37  1.1  haad #include <sys/time.h>
     38  1.1  haad #include <sys/resource.h>
     39  1.1  haad #include <unistd.h>
     40  1.1  haad #include <signal.h>
     41  1.1  haad #include <arpa/inet.h>		/* for htonl, ntohl */
     42  1.1  haad 
     43  1.1  haad #ifdef linux
     44  1.1  haad #  include <malloc.h>
     45  1.1  haad 
     46  1.1  haad #  define OOM_ADJ_FILE "/proc/self/oom_adj"
     47  1.1  haad 
     48  1.1  haad /* From linux/oom.h */
     49  1.1  haad #  define OOM_DISABLE (-17)
     50  1.1  haad #  define OOM_ADJUST_MIN (-16)
     51  1.1  haad 
     52  1.1  haad #endif
     53  1.1  haad 
     54  1.1  haad /* FIXME We use syslog for now, because multilog is not yet implemented */
     55  1.1  haad #include <syslog.h>
     56  1.1  haad 
     57  1.1  haad static volatile sig_atomic_t _exit_now = 0;	/* set to '1' when signal is given to exit */
     58  1.1  haad static volatile sig_atomic_t _thread_registries_empty = 1;	/* registries are empty initially */
     59  1.1  haad static int _debug = 0;
     60  1.1  haad 
     61  1.1  haad /* List (un)link macros. */
     62  1.1  haad #define	LINK(x, head)		dm_list_add(head, &(x)->list)
     63  1.1  haad #define	LINK_DSO(dso)		LINK(dso, &_dso_registry)
     64  1.1  haad #define	LINK_THREAD(thread)	LINK(thread, &_thread_registry)
     65  1.1  haad 
     66  1.1  haad #define	UNLINK(x)		dm_list_del(&(x)->list)
     67  1.1  haad #define	UNLINK_DSO(x)		UNLINK(x)
     68  1.1  haad #define	UNLINK_THREAD(x)	UNLINK(x)
     69  1.1  haad 
     70  1.1  haad #define DAEMON_NAME "dmeventd"
     71  1.1  haad 
     72  1.1  haad /*
     73  1.1  haad   Global mutex for thread list access. Has to be held when:
     74  1.1  haad   - iterating thread list
     75  1.1  haad   - adding or removing elements from thread list
     76  1.1  haad   - changing or reading thread_status's fields:
     77  1.1  haad     processing, status, events
     78  1.1  haad   Use _lock_mutex() and _unlock_mutex() to hold/release it
     79  1.1  haad */
     80  1.1  haad static pthread_mutex_t _global_mutex;
     81  1.1  haad 
     82  1.1  haad /*
     83  1.1  haad   There are three states a thread can attain (see struct
     84  1.1  haad   thread_status, field int status):
     85  1.1  haad 
     86  1.1  haad   - DM_THREAD_RUNNING: thread has started up and is either working or
     87  1.1  haad   waiting for events... transitions to either SHUTDOWN or DONE
     88  1.1  haad   - DM_THREAD_SHUTDOWN: thread is still doing something, but it is
     89  1.1  haad   supposed to terminate (and transition to DONE) as soon as it
     90  1.1  haad   finishes whatever it was doing at the point of flipping state to
     91  1.1  haad   SHUTDOWN... the thread is still on the thread list
     92  1.1  haad   - DM_THREAD_DONE: thread has terminated and has been moved over to
     93  1.1  haad   unused thread list, cleanup pending
     94  1.1  haad  */
     95  1.1  haad #define DM_THREAD_RUNNING  0
     96  1.1  haad #define DM_THREAD_SHUTDOWN 1
     97  1.1  haad #define DM_THREAD_DONE     2
     98  1.1  haad 
     99  1.1  haad #define THREAD_STACK_SIZE (300*1024)
    100  1.1  haad 
    101  1.1  haad #define DEBUGLOG(fmt, args...) _debuglog(fmt, ## args)
    102  1.1  haad 
    103  1.1  haad /* Data kept about a DSO. */
    104  1.1  haad struct dso_data {
    105  1.1  haad 	struct dm_list list;
    106  1.1  haad 
    107  1.1  haad 	char *dso_name;		/* DSO name (eg, "evms", "dmraid", "lvm2"). */
    108  1.1  haad 
    109  1.1  haad 	void *dso_handle;	/* Opaque handle as returned from dlopen(). */
    110  1.1  haad 	unsigned int ref_count;	/* Library reference count. */
    111  1.1  haad 
    112  1.1  haad 	/*
    113  1.1  haad 	 * Event processing.
    114  1.1  haad 	 *
    115  1.1  haad 	 * The DSO can do whatever appropriate steps if an event
    116  1.1  haad 	 * happens such as changing the mapping in case a mirror
    117  1.1  haad 	 * fails, update the application metadata etc.
    118  1.1  haad 	 *
    119  1.1  haad 	 * This function gets a dm_task that is a result of
    120  1.1  haad 	 * DM_DEVICE_WAITEVENT ioctl (results equivalent to
    121  1.1  haad 	 * DM_DEVICE_STATUS). It should not destroy it.
    122  1.1  haad 	 * The caller must dispose of the task.
    123  1.1  haad 	 */
    124  1.1  haad 	void (*process_event)(struct dm_task *dmt, enum dm_event_mask event, void **user);
    125  1.1  haad 
    126  1.1  haad 	/*
    127  1.1  haad 	 * Device registration.
    128  1.1  haad 	 *
    129  1.1  haad 	 * When an application registers a device for an event, the DSO
    130  1.1  haad 	 * can carry out appropriate steps so that a later call to
    131  1.1  haad 	 * the process_event() function is sane (eg, read metadata
    132  1.1  haad 	 * and activate a mapping).
    133  1.1  haad 	 */
    134  1.1  haad 	int (*register_device)(const char *device, const char *uuid, int major,
    135  1.1  haad 			       int minor, void **user);
    136  1.1  haad 
    137  1.1  haad 	/*
    138  1.1  haad 	 * Device unregistration.
    139  1.1  haad 	 *
    140  1.1  haad 	 * In case all devices of a mapping (eg, RAID10) are unregistered
    141  1.1  haad 	 * for events, the DSO can recognize this and carry out appropriate
    142  1.1  haad 	 * steps (eg, deactivate mapping, metadata update).
    143  1.1  haad 	 */
    144  1.1  haad 	int (*unregister_device)(const char *device, const char *uuid,
    145  1.1  haad 				 int major, int minor, void **user);
    146  1.1  haad };
    147  1.1  haad static DM_LIST_INIT(_dso_registry);
    148  1.1  haad 
    149  1.1  haad /* Structure to keep parsed register variables from client message. */
    150  1.1  haad struct message_data {
    151  1.1  haad 	char *id;
    152  1.1  haad 	char *dso_name;		/* Name of DSO. */
    153  1.1  haad 	char *device_uuid;	/* Mapped device path. */
    154  1.1  haad 	union {
    155  1.1  haad 		char *str;	/* Events string as fetched from message. */
    156  1.1  haad 		enum dm_event_mask field;	/* Events bitfield. */
    157  1.1  haad 	} events;
    158  1.1  haad 	union {
    159  1.1  haad 		char *str;
    160  1.1  haad 		uint32_t secs;
    161  1.1  haad 	} timeout;
    162  1.1  haad 	struct dm_event_daemon_message *msg;	/* Pointer to message buffer. */
    163  1.1  haad };
    164  1.1  haad 
    165  1.1  haad /*
    166  1.1  haad  * Housekeeping of thread+device states.
    167  1.1  haad  *
    168  1.1  haad  * One thread per mapped device which can block on it until an event
    169  1.1  haad  * occurs and the event processing function of the DSO gets called.
    170  1.1  haad  */
    171  1.1  haad struct thread_status {
    172  1.1  haad 	struct dm_list list;
    173  1.1  haad 
    174  1.1  haad 	pthread_t thread;
    175  1.1  haad 
    176  1.1  haad 	struct dso_data *dso_data;	/* DSO this thread accesses. */
    177  1.1  haad 
    178  1.1  haad 	struct {
    179  1.1  haad 		char *uuid;
    180  1.1  haad 		char *name;
    181  1.1  haad 		int major, minor;
    182  1.1  haad 	} device;
    183  1.1  haad 	uint32_t event_nr;	/* event number */
    184  1.1  haad 	int processing;		/* Set when event is being processed */
    185  1.1  haad 
    186  1.1  haad 	int status;		/* see DM_THREAD_{RUNNING,SHUTDOWN,DONE}
    187  1.1  haad 				   constants above */
    188  1.1  haad 	enum dm_event_mask events;	/* bitfield for event filter. */
    189  1.1  haad 	enum dm_event_mask current_events;	/* bitfield for occured events. */
    190  1.1  haad 	struct dm_task *current_task;
    191  1.1  haad 	time_t next_time;
    192  1.1  haad 	uint32_t timeout;
    193  1.1  haad 	struct dm_list timeout_list;
    194  1.1  haad 	void *dso_private; /* dso per-thread status variable */
    195  1.1  haad };
    196  1.1  haad static DM_LIST_INIT(_thread_registry);
    197  1.1  haad static DM_LIST_INIT(_thread_registry_unused);
    198  1.1  haad 
    199  1.1  haad static int _timeout_running;
    200  1.1  haad static DM_LIST_INIT(_timeout_registry);
    201  1.1  haad static pthread_mutex_t _timeout_mutex = PTHREAD_MUTEX_INITIALIZER;
    202  1.1  haad static pthread_cond_t _timeout_cond = PTHREAD_COND_INITIALIZER;
    203  1.1  haad 
    204  1.1  haad static void _debuglog(const char *fmt, ...)
    205  1.1  haad {
    206  1.1  haad         time_t P;
    207  1.1  haad         va_list ap;
    208  1.1  haad 
    209  1.1  haad         if (!_debug)
    210  1.1  haad                 return;
    211  1.1  haad 
    212  1.1  haad         va_start(ap,fmt);
    213  1.1  haad 
    214  1.1  haad         time(&P);
    215  1.1  haad         fprintf(stderr, "dmeventd[%p]: %.15s ", (void *) pthread_self(), ctime(&P)+4 );
    216  1.1  haad         vfprintf(stderr, fmt, ap);
    217  1.1  haad 	fprintf(stderr, "\n");
    218  1.1  haad 
    219  1.1  haad         va_end(ap);
    220  1.1  haad }
    221  1.1  haad 
    222  1.1  haad /* Allocate/free the status structure for a monitoring thread. */
    223  1.1  haad static struct thread_status *_alloc_thread_status(struct message_data *data,
    224  1.1  haad 						  struct dso_data *dso_data)
    225  1.1  haad {
    226  1.1  haad 	struct thread_status *ret = (typeof(ret)) dm_malloc(sizeof(*ret));
    227  1.1  haad 
    228  1.1  haad 	if (!ret)
    229  1.1  haad 		return NULL;
    230  1.1  haad 
    231  1.1  haad 	memset(ret, 0, sizeof(*ret));
    232  1.1  haad 	if (!(ret->device.uuid = dm_strdup(data->device_uuid))) {
    233  1.1  haad 		dm_free(ret);
    234  1.1  haad 		return NULL;
    235  1.1  haad 	}
    236  1.1  haad 
    237  1.1  haad 	ret->current_task = NULL;
    238  1.1  haad 	ret->device.name = NULL;
    239  1.1  haad 	ret->device.major = ret->device.minor = 0;
    240  1.1  haad 	ret->dso_data = dso_data;
    241  1.1  haad 	ret->events = data->events.field;
    242  1.1  haad 	ret->timeout = data->timeout.secs;
    243  1.1  haad 	dm_list_init(&ret->timeout_list);
    244  1.1  haad 
    245  1.1  haad 	return ret;
    246  1.1  haad }
    247  1.1  haad 
    248  1.1  haad static void _free_thread_status(struct thread_status *thread)
    249  1.1  haad {
    250  1.1  haad 	if (thread->current_task)
    251  1.1  haad 		dm_task_destroy(thread->current_task);
    252  1.1  haad 	dm_free(thread->device.uuid);
    253  1.1  haad 	dm_free(thread->device.name);
    254  1.1  haad 	dm_free(thread);
    255  1.1  haad }
    256  1.1  haad 
    257  1.1  haad /* Allocate/free DSO data. */
    258  1.1  haad static struct dso_data *_alloc_dso_data(struct message_data *data)
    259  1.1  haad {
    260  1.1  haad 	struct dso_data *ret = (typeof(ret)) dm_malloc(sizeof(*ret));
    261  1.1  haad 
    262  1.1  haad 	if (!ret)
    263  1.1  haad 		return NULL;
    264  1.1  haad 
    265  1.1  haad 	memset(ret, 0, sizeof(*ret));
    266  1.1  haad 	if (!(ret->dso_name = dm_strdup(data->dso_name))) {
    267  1.1  haad 		dm_free(ret);
    268  1.1  haad 		return NULL;
    269  1.1  haad 	}
    270  1.1  haad 
    271  1.1  haad 	return ret;
    272  1.1  haad }
    273  1.1  haad 
    274  1.1  haad /* Create a device monitoring thread. */
    275  1.1  haad static int _pthread_create_smallstack(pthread_t *t, void *(*fun)(void *), void *arg)
    276  1.1  haad {
    277  1.1  haad 	pthread_attr_t attr;
    278  1.1  haad 	pthread_attr_init(&attr);
    279  1.1  haad 	/*
    280  1.1  haad 	 * We use a smaller stack since it gets preallocated in its entirety
    281  1.1  haad 	 */
    282  1.1  haad 	pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
    283  1.1  haad 	return pthread_create(t, &attr, fun, arg);
    284  1.1  haad }
    285  1.1  haad 
    286  1.1  haad static void _free_dso_data(struct dso_data *data)
    287  1.1  haad {
    288  1.1  haad 	dm_free(data->dso_name);
    289  1.1  haad 	dm_free(data);
    290  1.1  haad }
    291  1.1  haad 
    292  1.1  haad /*
    293  1.1  haad  * Fetch a string off src and duplicate it into *ptr.
    294  1.1  haad  * Pay attention to zero-length strings.
    295  1.1  haad  */
    296  1.1  haad /* FIXME? move to libdevmapper to share with the client lib (need to
    297  1.1  haad    make delimiter a parameter then) */
    298  1.1  haad static int _fetch_string(char **ptr, char **src, const int delimiter)
    299  1.1  haad {
    300  1.1  haad 	int ret = 0;
    301  1.1  haad 	char *p;
    302  1.1  haad 	size_t len;
    303  1.1  haad 
    304  1.1  haad 	if ((p = strchr(*src, delimiter)))
    305  1.1  haad 		*p = 0;
    306  1.1  haad 
    307  1.1  haad 	if ((*ptr = dm_strdup(*src))) {
    308  1.1  haad 		if ((len = strlen(*ptr)))
    309  1.1  haad 			*src += len;
    310  1.1  haad 		else {
    311  1.1  haad 			dm_free(*ptr);
    312  1.1  haad 			*ptr = NULL;
    313  1.1  haad 		}
    314  1.1  haad 
    315  1.1  haad 		(*src)++;
    316  1.1  haad 		ret = 1;
    317  1.1  haad 	}
    318  1.1  haad 
    319  1.1  haad 	if (p)
    320  1.1  haad 		*p = delimiter;
    321  1.1  haad 
    322  1.1  haad 	return ret;
    323  1.1  haad }
    324  1.1  haad 
    325  1.1  haad /* Free message memory. */
    326  1.1  haad static void _free_message(struct message_data *message_data)
    327  1.1  haad {
    328  1.1  haad 	if (message_data->id)
    329  1.1  haad 		dm_free(message_data->id);
    330  1.1  haad 	if (message_data->dso_name)
    331  1.1  haad 		dm_free(message_data->dso_name);
    332  1.1  haad 
    333  1.1  haad 	if (message_data->device_uuid)
    334  1.1  haad 		dm_free(message_data->device_uuid);
    335  1.1  haad 
    336  1.1  haad }
    337  1.1  haad 
    338  1.1  haad /* Parse a register message from the client. */
    339  1.1  haad static int _parse_message(struct message_data *message_data)
    340  1.1  haad {
    341  1.1  haad 	int ret = 0;
    342  1.1  haad 	char *p = message_data->msg->data;
    343  1.1  haad 	struct dm_event_daemon_message *msg = message_data->msg;
    344  1.1  haad 
    345  1.1  haad 	if (!msg->data)
    346  1.1  haad 		return 0;
    347  1.1  haad 
    348  1.1  haad 	/*
    349  1.1  haad 	 * Retrieve application identifier, mapped device
    350  1.1  haad 	 * path and events # string from message.
    351  1.1  haad 	 */
    352  1.1  haad 	if (_fetch_string(&message_data->id, &p, ' ') &&
    353  1.1  haad 	    _fetch_string(&message_data->dso_name, &p, ' ') &&
    354  1.1  haad 	    _fetch_string(&message_data->device_uuid, &p, ' ') &&
    355  1.1  haad 	    _fetch_string(&message_data->events.str, &p, ' ') &&
    356  1.1  haad 	    _fetch_string(&message_data->timeout.str, &p, ' ')) {
    357  1.1  haad 		if (message_data->events.str) {
    358  1.1  haad 			enum dm_event_mask i = atoi(message_data->events.str);
    359  1.1  haad 
    360  1.1  haad 			/*
    361  1.1  haad 			 * Free string representaion of events.
    362  1.1  haad 			 * Not needed an more.
    363  1.1  haad 			 */
    364  1.1  haad 			dm_free(message_data->events.str);
    365  1.1  haad 			message_data->events.field = i;
    366  1.1  haad 		}
    367  1.1  haad 		if (message_data->timeout.str) {
    368  1.1  haad 			uint32_t secs = atoi(message_data->timeout.str);
    369  1.1  haad 			dm_free(message_data->timeout.str);
    370  1.1  haad 			message_data->timeout.secs = secs ? secs :
    371  1.1  haad 			    DM_EVENT_DEFAULT_TIMEOUT;
    372  1.1  haad 		}
    373  1.1  haad 
    374  1.1  haad 		ret = 1;
    375  1.1  haad 	}
    376  1.1  haad 
    377  1.1  haad 	dm_free(msg->data);
    378  1.1  haad 	msg->data = NULL;
    379  1.1  haad 	msg->size = 0;
    380  1.1  haad 	return ret;
    381  1.1  haad };
    382  1.1  haad 
    383  1.1  haad /* Global mutex to lock access to lists et al. See _global_mutex
    384  1.1  haad    above. */
    385  1.1  haad static int _lock_mutex(void)
    386  1.1  haad {
    387  1.1  haad 	return pthread_mutex_lock(&_global_mutex);
    388  1.1  haad }
    389  1.1  haad 
    390  1.1  haad static int _unlock_mutex(void)
    391  1.1  haad {
    392  1.1  haad 	return pthread_mutex_unlock(&_global_mutex);
    393  1.1  haad }
    394  1.1  haad 
    395  1.1  haad /* Store pid in pidfile. */
    396  1.1  haad static int _storepid(int lf)
    397  1.1  haad {
    398  1.1  haad 	int len;
    399  1.1  haad 	char pid[8];
    400  1.1  haad 
    401  1.1  haad 	if ((len = snprintf(pid, sizeof(pid), "%u\n", getpid())) < 0)
    402  1.1  haad 		return 0;
    403  1.1  haad 
    404  1.1  haad 	if (len > (int) sizeof(pid))
    405  1.1  haad 		len = (int) sizeof(pid);
    406  1.1  haad 
    407  1.1  haad 	if (write(lf, pid, (size_t) len) != len)
    408  1.1  haad 		return 0;
    409  1.1  haad 
    410  1.1  haad 	fsync(lf);
    411  1.1  haad 
    412  1.1  haad 	return 1;
    413  1.1  haad }
    414  1.1  haad 
    415  1.1  haad /* Check, if a device exists. */
    416  1.1  haad static int _fill_device_data(struct thread_status *ts)
    417  1.1  haad {
    418  1.1  haad 	struct dm_task *dmt;
    419  1.1  haad 	struct dm_info dmi;
    420  1.1  haad 
    421  1.1  haad 	if (!ts->device.uuid)
    422  1.1  haad 		return 0;
    423  1.1  haad 
    424  1.1  haad 	ts->device.name = NULL;
    425  1.1  haad 	ts->device.major = ts->device.minor = 0;
    426  1.1  haad 
    427  1.1  haad 	dmt = dm_task_create(DM_DEVICE_INFO);
    428  1.1  haad 	if (!dmt)
    429  1.1  haad 		return 0;
    430  1.1  haad 
    431  1.1  haad 	dm_task_set_uuid(dmt, ts->device.uuid);
    432  1.1  haad 	if (!dm_task_run(dmt))
    433  1.1  haad 		goto fail;
    434  1.1  haad 
    435  1.1  haad 	ts->device.name = dm_strdup(dm_task_get_name(dmt));
    436  1.1  haad 	if (!ts->device.name)
    437  1.1  haad 		goto fail;
    438  1.1  haad 
    439  1.1  haad 	if (!dm_task_get_info(dmt, &dmi))
    440  1.1  haad 		goto fail;
    441  1.1  haad 
    442  1.1  haad 	ts->device.major = dmi.major;
    443  1.1  haad 	ts->device.minor = dmi.minor;
    444  1.1  haad 
    445  1.1  haad 	dm_task_destroy(dmt);
    446  1.1  haad 	return 1;
    447  1.1  haad 
    448  1.1  haad       fail:
    449  1.1  haad 	dm_task_destroy(dmt);
    450  1.1  haad 	dm_free(ts->device.name);
    451  1.1  haad 	return 0;
    452  1.1  haad }
    453  1.1  haad 
    454  1.1  haad /*
    455  1.1  haad  * Find an existing thread for a device.
    456  1.1  haad  *
    457  1.1  haad  * Mutex must be held when calling this.
    458  1.1  haad  */
    459  1.1  haad static struct thread_status *_lookup_thread_status(struct message_data *data)
    460  1.1  haad {
    461  1.1  haad 	struct thread_status *thread;
    462  1.1  haad 
    463  1.1  haad 	dm_list_iterate_items(thread, &_thread_registry)
    464  1.1  haad 	    if (!strcmp(data->device_uuid, thread->device.uuid))
    465  1.1  haad 		return thread;
    466  1.1  haad 
    467  1.1  haad 	return NULL;
    468  1.1  haad }
    469  1.1  haad 
    470  1.1  haad /* Cleanup at exit. */
    471  1.1  haad static void _exit_dm_lib(void)
    472  1.1  haad {
    473  1.1  haad 	dm_lib_release();
    474  1.1  haad 	dm_lib_exit();
    475  1.1  haad }
    476  1.1  haad 
    477  1.1  haad static void _exit_timeout(void *unused __attribute((unused)))
    478  1.1  haad {
    479  1.1  haad 	_timeout_running = 0;
    480  1.1  haad 	pthread_mutex_unlock(&_timeout_mutex);
    481  1.1  haad }
    482  1.1  haad 
    483  1.1  haad /* Wake up monitor threads every so often. */
    484  1.1  haad static void *_timeout_thread(void *unused __attribute((unused)))
    485  1.1  haad {
    486  1.1  haad 	struct timespec timeout;
    487  1.1  haad 	time_t curr_time;
    488  1.1  haad 
    489  1.1  haad 	timeout.tv_nsec = 0;
    490  1.1  haad 	pthread_cleanup_push(_exit_timeout, NULL);
    491  1.1  haad 	pthread_mutex_lock(&_timeout_mutex);
    492  1.1  haad 
    493  1.1  haad 	while (!dm_list_empty(&_timeout_registry)) {
    494  1.1  haad 		struct thread_status *thread;
    495  1.1  haad 
    496  1.1  haad 		timeout.tv_sec = 0;
    497  1.1  haad 		curr_time = time(NULL);
    498  1.1  haad 
    499  1.1  haad 		dm_list_iterate_items_gen(thread, &_timeout_registry, timeout_list) {
    500  1.1  haad 			if (thread->next_time <= curr_time) {
    501  1.1  haad 				thread->next_time = curr_time + thread->timeout;
    502  1.1  haad 				pthread_kill(thread->thread, SIGALRM);
    503  1.1  haad 			}
    504  1.1  haad 
    505  1.1  haad 			if (thread->next_time < timeout.tv_sec || !timeout.tv_sec)
    506  1.1  haad 				timeout.tv_sec = thread->next_time;
    507  1.1  haad 		}
    508  1.1  haad 
    509  1.1  haad 		pthread_cond_timedwait(&_timeout_cond, &_timeout_mutex,
    510  1.1  haad 				       &timeout);
    511  1.1  haad 	}
    512  1.1  haad 
    513  1.1  haad 	pthread_cleanup_pop(1);
    514  1.1  haad 
    515  1.1  haad 	return NULL;
    516  1.1  haad }
    517  1.1  haad 
    518  1.1  haad static int _register_for_timeout(struct thread_status *thread)
    519  1.1  haad {
    520  1.1  haad 	int ret = 0;
    521  1.1  haad 
    522  1.1  haad 	pthread_mutex_lock(&_timeout_mutex);
    523  1.1  haad 
    524  1.1  haad 	thread->next_time = time(NULL) + thread->timeout;
    525  1.1  haad 
    526  1.1  haad 	if (dm_list_empty(&thread->timeout_list)) {
    527  1.1  haad 		dm_list_add(&_timeout_registry, &thread->timeout_list);
    528  1.1  haad 		if (_timeout_running)
    529  1.1  haad 			pthread_cond_signal(&_timeout_cond);
    530  1.1  haad 	}
    531  1.1  haad 
    532  1.1  haad 	if (!_timeout_running) {
    533  1.1  haad 		pthread_t timeout_id;
    534  1.1  haad 
    535  1.1  haad 		if (!(ret = -_pthread_create_smallstack(&timeout_id, _timeout_thread, NULL)))
    536  1.1  haad 			_timeout_running = 1;
    537  1.1  haad 	}
    538  1.1  haad 
    539  1.1  haad 	pthread_mutex_unlock(&_timeout_mutex);
    540  1.1  haad 
    541  1.1  haad 	return ret;
    542  1.1  haad }
    543  1.1  haad 
    544  1.1  haad static void _unregister_for_timeout(struct thread_status *thread)
    545  1.1  haad {
    546  1.1  haad 	pthread_mutex_lock(&_timeout_mutex);
    547  1.1  haad 	if (!dm_list_empty(&thread->timeout_list)) {
    548  1.1  haad 		dm_list_del(&thread->timeout_list);
    549  1.1  haad 		dm_list_init(&thread->timeout_list);
    550  1.1  haad 	}
    551  1.1  haad 	pthread_mutex_unlock(&_timeout_mutex);
    552  1.1  haad }
    553  1.1  haad 
    554  1.1  haad static void _no_intr_log(int level, const char *file, int line,
    555  1.1  haad 			const char *f, ...)
    556  1.1  haad {
    557  1.1  haad 	va_list ap;
    558  1.1  haad 
    559  1.1  haad 	if (errno == EINTR)
    560  1.1  haad 		return;
    561  1.1  haad 	if (level > _LOG_WARN)
    562  1.1  haad 		return;
    563  1.1  haad 
    564  1.1  haad 	va_start(ap, f);
    565  1.1  haad 
    566  1.1  haad 	if (level < _LOG_WARN)
    567  1.1  haad 		vfprintf(stderr, f, ap);
    568  1.1  haad 	else
    569  1.1  haad 		vprintf(f, ap);
    570  1.1  haad 
    571  1.1  haad 	va_end(ap);
    572  1.1  haad 
    573  1.1  haad 	if (level < _LOG_WARN)
    574  1.1  haad 		fprintf(stderr, "\n");
    575  1.1  haad 	else
    576  1.1  haad 		fprintf(stdout, "\n");
    577  1.1  haad }
    578  1.1  haad 
    579  1.1  haad static sigset_t _unblock_sigalrm(void)
    580  1.1  haad {
    581  1.1  haad 	sigset_t set, old;
    582  1.1  haad 
    583  1.1  haad 	sigemptyset(&set);
    584  1.1  haad 	sigaddset(&set, SIGALRM);
    585  1.1  haad 	pthread_sigmask(SIG_UNBLOCK, &set, &old);
    586  1.1  haad 	return old;
    587  1.1  haad }
    588  1.1  haad 
    589  1.1  haad #define DM_WAIT_RETRY 0
    590  1.1  haad #define DM_WAIT_INTR 1
    591  1.1  haad #define DM_WAIT_FATAL 2
    592  1.1  haad 
    593  1.1  haad /* Wait on a device until an event occurs. */
    594  1.1  haad static int _event_wait(struct thread_status *thread, struct dm_task **task)
    595  1.1  haad {
    596  1.1  haad 	sigset_t set;
    597  1.1  haad 	int ret = DM_WAIT_RETRY;
    598  1.1  haad 	struct dm_task *dmt;
    599  1.1  haad 	struct dm_info info;
    600  1.1  haad 
    601  1.1  haad 	*task = 0;
    602  1.1  haad 
    603  1.1  haad 	if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
    604  1.1  haad 		return DM_WAIT_RETRY;
    605  1.1  haad 
    606  1.1  haad 	thread->current_task = dmt;
    607  1.1  haad 
    608  1.1  haad 	if (!dm_task_set_uuid(dmt, thread->device.uuid) ||
    609  1.1  haad 	    !dm_task_set_event_nr(dmt, thread->event_nr))
    610  1.1  haad 		goto out;
    611  1.1  haad 
    612  1.1  haad 	/*
    613  1.1  haad 	 * This is so that you can break out of waiting on an event,
    614  1.1  haad 	 * either for a timeout event, or to cancel the thread.
    615  1.1  haad 	 */
    616  1.1  haad 	set = _unblock_sigalrm();
    617  1.1  haad 	dm_log_init(_no_intr_log);
    618  1.1  haad 	errno = 0;
    619  1.1  haad 	if (dm_task_run(dmt)) {
    620  1.1  haad 		thread->current_events |= DM_EVENT_DEVICE_ERROR;
    621  1.1  haad 		ret = DM_WAIT_INTR;
    622  1.1  haad 
    623  1.1  haad 		if ((ret = dm_task_get_info(dmt, &info)))
    624  1.1  haad 			thread->event_nr = info.event_nr;
    625  1.1  haad 	} else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) {
    626  1.1  haad 		thread->current_events |= DM_EVENT_TIMEOUT;
    627  1.1  haad 		ret = DM_WAIT_INTR;
    628  1.1  haad 	} else if (thread->status == DM_THREAD_SHUTDOWN && errno == EINTR) {
    629  1.1  haad 		ret = DM_WAIT_FATAL;
    630  1.1  haad 	} else {
    631  1.1  haad 		syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
    632  1.1  haad 		       errno, strerror(errno));
    633  1.1  haad 		if (errno == ENXIO) {
    634  1.1  haad 			syslog(LOG_ERR, "%s disappeared, detaching",
    635  1.1  haad 			       thread->device.name);
    636  1.1  haad 			ret = DM_WAIT_FATAL;
    637  1.1  haad 		}
    638  1.1  haad 	}
    639  1.1  haad 
    640  1.1  haad 	pthread_sigmask(SIG_SETMASK, &set, NULL);
    641  1.1  haad 	dm_log_init(NULL);
    642  1.1  haad 
    643  1.1  haad       out:
    644  1.1  haad 	if (ret == DM_WAIT_FATAL || ret == DM_WAIT_RETRY) {
    645  1.1  haad 		dm_task_destroy(dmt);
    646  1.1  haad 		thread->current_task = NULL;
    647  1.1  haad 	} else
    648  1.1  haad 		*task = dmt;
    649  1.1  haad 
    650  1.1  haad 	return ret;
    651  1.1  haad }
    652  1.1  haad 
    653  1.1  haad /* Register a device with the DSO. */
    654  1.1  haad static int _do_register_device(struct thread_status *thread)
    655  1.1  haad {
    656  1.1  haad 	return thread->dso_data->register_device(thread->device.name,
    657  1.1  haad 						 thread->device.uuid,
    658  1.1  haad 						 thread->device.major,
    659  1.1  haad 						 thread->device.minor,
    660  1.1  haad 						 &(thread->dso_private));
    661  1.1  haad }
    662  1.1  haad 
    663  1.1  haad /* Unregister a device with the DSO. */
    664  1.1  haad static int _do_unregister_device(struct thread_status *thread)
    665  1.1  haad {
    666  1.1  haad 	return thread->dso_data->unregister_device(thread->device.name,
    667  1.1  haad 						   thread->device.uuid,
    668  1.1  haad 						   thread->device.major,
    669  1.1  haad 						   thread->device.minor,
    670  1.1  haad 						   &(thread->dso_private));
    671  1.1  haad }
    672  1.1  haad 
    673  1.1  haad /* Process an event in the DSO. */
    674  1.1  haad static void _do_process_event(struct thread_status *thread, struct dm_task *task)
    675  1.1  haad {
    676  1.1  haad 	thread->dso_data->process_event(task, thread->current_events, &(thread->dso_private));
    677  1.1  haad }
    678  1.1  haad 
    679  1.1  haad /* Thread cleanup handler to unregister device. */
    680  1.1  haad static void _monitor_unregister(void *arg)
    681  1.1  haad {
    682  1.1  haad 	struct thread_status *thread = arg, *thread_iter;
    683  1.1  haad 
    684  1.1  haad 	if (!_do_unregister_device(thread))
    685  1.1  haad 		syslog(LOG_ERR, "%s: %s unregister failed\n", __func__,
    686  1.1  haad 		       thread->device.name);
    687  1.1  haad 	if (thread->current_task)
    688  1.1  haad 		dm_task_destroy(thread->current_task);
    689  1.1  haad 	thread->current_task = NULL;
    690  1.1  haad 
    691  1.1  haad 	_lock_mutex();
    692  1.1  haad 	if (thread->events & DM_EVENT_TIMEOUT) {
    693  1.1  haad 		/* _unregister_for_timeout locks another mutex, we
    694  1.1  haad 		   don't want to deadlock so we release our mutex for
    695  1.1  haad 		   a bit */
    696  1.1  haad 		_unlock_mutex();
    697  1.1  haad 		_unregister_for_timeout(thread);
    698  1.1  haad 		_lock_mutex();
    699  1.1  haad 	}
    700  1.1  haad 	/* we may have been relinked to unused registry since we were
    701  1.1  haad 	   called, so check that */
    702  1.1  haad 	dm_list_iterate_items(thread_iter, &_thread_registry_unused)
    703  1.1  haad 		if (thread_iter == thread) {
    704  1.1  haad 			thread->status = DM_THREAD_DONE;
    705  1.1  haad 			_unlock_mutex();
    706  1.1  haad 			return;
    707  1.1  haad 		}
    708  1.1  haad 	thread->status = DM_THREAD_DONE;
    709  1.1  haad 	UNLINK_THREAD(thread);
    710  1.1  haad 	LINK(thread, &_thread_registry_unused);
    711  1.1  haad 	_unlock_mutex();
    712  1.1  haad }
    713  1.1  haad 
    714  1.1  haad static struct dm_task *_get_device_status(struct thread_status *ts)
    715  1.1  haad {
    716  1.1  haad 	struct dm_task *dmt = dm_task_create(DM_DEVICE_STATUS);
    717  1.1  haad 
    718  1.1  haad 	if (!dmt)
    719  1.1  haad 		return NULL;
    720  1.1  haad 
    721  1.1  haad 	dm_task_set_uuid(dmt, ts->device.uuid);
    722  1.1  haad 
    723  1.1  haad 	if (!dm_task_run(dmt)) {
    724  1.1  haad 		dm_task_destroy(dmt);
    725  1.1  haad 		return NULL;
    726  1.1  haad 	}
    727  1.1  haad 
    728  1.1  haad 	return dmt;
    729  1.1  haad }
    730  1.1  haad 
    731  1.1  haad /* Device monitoring thread. */
    732  1.1  haad static void *_monitor_thread(void *arg)
    733  1.1  haad {
    734  1.1  haad 	struct thread_status *thread = arg;
    735  1.1  haad 	int wait_error = 0;
    736  1.1  haad 	struct dm_task *task;
    737  1.1  haad 
    738  1.1  haad 	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    739  1.1  haad 	pthread_cleanup_push(_monitor_unregister, thread);
    740  1.1  haad 
    741  1.1  haad 	/* Wait for do_process_request() to finish its task. */
    742  1.1  haad 	_lock_mutex();
    743  1.1  haad 	thread->status = DM_THREAD_RUNNING;
    744  1.1  haad 	_unlock_mutex();
    745  1.1  haad 
    746  1.1  haad 	/* Loop forever awaiting/analyzing device events. */
    747  1.1  haad 	while (1) {
    748  1.1  haad 		thread->current_events = 0;
    749  1.1  haad 
    750  1.1  haad 		wait_error = _event_wait(thread, &task);
    751  1.1  haad 		if (wait_error == DM_WAIT_RETRY)
    752  1.1  haad 			continue;
    753  1.1  haad 
    754  1.1  haad 		if (wait_error == DM_WAIT_FATAL)
    755  1.1  haad 			break;
    756  1.1  haad 
    757  1.1  haad 		/* Timeout occurred, task is not filled properly.
    758  1.1  haad 		 * We get device status here for processing it in DSO.
    759  1.1  haad 		 */
    760  1.1  haad 		if (wait_error == DM_WAIT_INTR &&
    761  1.1  haad 		    thread->current_events & DM_EVENT_TIMEOUT) {
    762  1.1  haad 			dm_task_destroy(task);
    763  1.1  haad 			task = _get_device_status(thread);
    764  1.1  haad 			/* FIXME: syslog fail here ? */
    765  1.1  haad 			if (!(thread->current_task = task))
    766  1.1  haad 				continue;
    767  1.1  haad 		}
    768  1.1  haad 
    769  1.1  haad 		/*
    770  1.1  haad 		 * We know that wait succeeded and stored a
    771  1.1  haad 		 * pointer to dm_task with device status into task.
    772  1.1  haad 		 */
    773  1.1  haad 
    774  1.1  haad 		/*
    775  1.1  haad 		 * Check against filter.
    776  1.1  haad 		 *
    777  1.1  haad 		 * If there's current events delivered from _event_wait() AND
    778  1.1  haad 		 * the device got registered for those events AND
    779  1.1  haad 		 * those events haven't been processed yet, call
    780  1.1  haad 		 * the DSO's process_event() handler.
    781  1.1  haad 		 */
    782  1.1  haad 		_lock_mutex();
    783  1.1  haad 		if (thread->status == DM_THREAD_SHUTDOWN) {
    784  1.1  haad 			_unlock_mutex();
    785  1.1  haad 			break;
    786  1.1  haad 		}
    787  1.1  haad 		_unlock_mutex();
    788  1.1  haad 
    789  1.1  haad 		if (thread->events & thread->current_events) {
    790  1.1  haad 			_lock_mutex();
    791  1.1  haad 			thread->processing = 1;
    792  1.1  haad 			_unlock_mutex();
    793  1.1  haad 
    794  1.1  haad 			_do_process_event(thread, task);
    795  1.1  haad 			dm_task_destroy(task);
    796  1.1  haad 			thread->current_task = NULL;
    797  1.1  haad 
    798  1.1  haad 			_lock_mutex();
    799  1.1  haad 			thread->processing = 0;
    800  1.1  haad 			_unlock_mutex();
    801  1.1  haad 		} else {
    802  1.1  haad 			dm_task_destroy(task);
    803  1.1  haad 			thread->current_task = NULL;
    804  1.1  haad 		}
    805  1.1  haad 	}
    806  1.1  haad 
    807  1.1  haad 	pthread_cleanup_pop(1);
    808  1.1  haad 
    809  1.1  haad 	return NULL;
    810  1.1  haad }
    811  1.1  haad 
    812  1.1  haad /* Create a device monitoring thread. */
    813  1.1  haad static int _create_thread(struct thread_status *thread)
    814  1.1  haad {
    815  1.1  haad 	return _pthread_create_smallstack(&thread->thread, _monitor_thread, thread);
    816  1.1  haad }
    817  1.1  haad 
    818  1.1  haad static int _terminate_thread(struct thread_status *thread)
    819  1.1  haad {
    820  1.1  haad 	return pthread_kill(thread->thread, SIGALRM);
    821  1.1  haad }
    822  1.1  haad 
    823  1.1  haad /* DSO reference counting. Call with _global_mutex locked! */
    824  1.1  haad static void _lib_get(struct dso_data *data)
    825  1.1  haad {
    826  1.1  haad 	data->ref_count++;
    827  1.1  haad }
    828  1.1  haad 
    829  1.1  haad static void _lib_put(struct dso_data *data)
    830  1.1  haad {
    831  1.1  haad 	if (!--data->ref_count) {
    832  1.1  haad 		dlclose(data->dso_handle);
    833  1.1  haad 		UNLINK_DSO(data);
    834  1.1  haad 		_free_dso_data(data);
    835  1.1  haad 	}
    836  1.1  haad }
    837  1.1  haad 
    838  1.1  haad /* Find DSO data. */
    839  1.1  haad static struct dso_data *_lookup_dso(struct message_data *data)
    840  1.1  haad {
    841  1.1  haad 	struct dso_data *dso_data, *ret = NULL;
    842  1.1  haad 
    843  1.1  haad 	dm_list_iterate_items(dso_data, &_dso_registry)
    844  1.1  haad 	    if (!strcmp(data->dso_name, dso_data->dso_name)) {
    845  1.1  haad 		_lib_get(dso_data);
    846  1.1  haad 		ret = dso_data;
    847  1.1  haad 		break;
    848  1.1  haad 	}
    849  1.1  haad 
    850  1.1  haad 	return ret;
    851  1.1  haad }
    852  1.1  haad 
    853  1.1  haad /* Lookup DSO symbols we need. */
    854  1.1  haad static int _lookup_symbol(void *dl, void **symbol, const char *name)
    855  1.1  haad {
    856  1.1  haad 	if ((*symbol = dlsym(dl, name)))
    857  1.1  haad 		return 1;
    858  1.1  haad 
    859  1.1  haad 	return 0;
    860  1.1  haad }
    861  1.1  haad 
    862  1.1  haad static int lookup_symbols(void *dl, struct dso_data *data)
    863  1.1  haad {
    864  1.1  haad 	return _lookup_symbol(dl, (void *) &data->process_event,
    865  1.1  haad 			     "process_event") &&
    866  1.1  haad 	    _lookup_symbol(dl, (void *) &data->register_device,
    867  1.1  haad 			  "register_device") &&
    868  1.1  haad 	    _lookup_symbol(dl, (void *) &data->unregister_device,
    869  1.1  haad 			  "unregister_device");
    870  1.1  haad }
    871  1.1  haad 
    872  1.1  haad /* Load an application specific DSO. */
    873  1.1  haad static struct dso_data *_load_dso(struct message_data *data)
    874  1.1  haad {
    875  1.1  haad 	void *dl;
    876  1.1  haad 	struct dso_data *ret = NULL;
    877  1.1  haad 
    878  1.1  haad 	if (!(dl = dlopen(data->dso_name, RTLD_NOW))) {
    879  1.1  haad 		const char *dlerr = dlerror();
    880  1.1  haad 		syslog(LOG_ERR, "dmeventd %s dlopen failed: %s", data->dso_name,
    881  1.1  haad 		       dlerr);
    882  1.1  haad 		data->msg->size =
    883  1.1  haad 		    dm_asprintf(&(data->msg->data), "%s %s dlopen failed: %s",
    884  1.1  haad 				data->id, data->dso_name, dlerr);
    885  1.1  haad 		return NULL;
    886  1.1  haad 	}
    887  1.1  haad 
    888  1.1  haad 	if (!(ret = _alloc_dso_data(data))) {
    889  1.1  haad 		dlclose(dl);
    890  1.1  haad 		return NULL;
    891  1.1  haad 	}
    892  1.1  haad 
    893  1.1  haad 	if (!(lookup_symbols(dl, ret))) {
    894  1.1  haad 		_free_dso_data(ret);
    895  1.1  haad 		dlclose(dl);
    896  1.1  haad 		return NULL;
    897  1.1  haad 	}
    898  1.1  haad 
    899  1.1  haad 	/*
    900  1.1  haad 	 * Keep handle to close the library once
    901  1.1  haad 	 * we've got no references to it any more.
    902  1.1  haad 	 */
    903  1.1  haad 	ret->dso_handle = dl;
    904  1.1  haad 	_lib_get(ret);
    905  1.1  haad 
    906  1.1  haad 	_lock_mutex();
    907  1.1  haad 	LINK_DSO(ret);
    908  1.1  haad 	_unlock_mutex();
    909  1.1  haad 
    910  1.1  haad 	return ret;
    911  1.1  haad }
    912  1.1  haad 
    913  1.1  haad /* Return success on daemon active check. */
    914  1.1  haad static int _active(struct message_data *message_data)
    915  1.1  haad {
    916  1.1  haad 	return 0;
    917  1.1  haad }
    918  1.1  haad 
    919  1.1  haad /*
    920  1.1  haad  * Register for an event.
    921  1.1  haad  *
    922  1.1  haad  * Only one caller at a time here, because we use
    923  1.1  haad  * a FIFO and lock it against multiple accesses.
    924  1.1  haad  */
    925  1.1  haad static int _register_for_event(struct message_data *message_data)
    926  1.1  haad {
    927  1.1  haad 	int ret = 0;
    928  1.1  haad 	struct thread_status *thread, *thread_new = NULL;
    929  1.1  haad 	struct dso_data *dso_data;
    930  1.1  haad 
    931  1.1  haad 	if (!(dso_data = _lookup_dso(message_data)) &&
    932  1.1  haad 	    !(dso_data = _load_dso(message_data))) {
    933  1.1  haad 		stack;
    934  1.1  haad #ifdef ELIBACC
    935  1.1  haad 		ret = -ELIBACC;
    936  1.1  haad #else
    937  1.1  haad 		ret = -ENODEV;
    938  1.1  haad #endif
    939  1.1  haad 		goto out;
    940  1.1  haad 	}
    941  1.1  haad 
    942  1.1  haad 	/* Preallocate thread status struct to avoid deadlock. */
    943  1.1  haad 	if (!(thread_new = _alloc_thread_status(message_data, dso_data))) {
    944  1.1  haad 		stack;
    945  1.1  haad 		ret = -ENOMEM;
    946  1.1  haad 		goto out;
    947  1.1  haad 	}
    948  1.1  haad 
    949  1.1  haad 	if (!_fill_device_data(thread_new)) {
    950  1.1  haad 		stack;
    951  1.1  haad 		ret = -ENODEV;
    952  1.1  haad 		goto out;
    953  1.1  haad 	}
    954  1.1  haad 
    955  1.1  haad 	_lock_mutex();
    956  1.1  haad 
    957  1.1  haad 	/* If creation of timeout thread fails (as it may), we fail
    958  1.1  haad 	   here completely. The client is responsible for either
    959  1.1  haad 	   retrying later or trying to register without timeout
    960  1.1  haad 	   events. However, if timeout thread cannot be started, it
    961  1.1  haad 	   usually means we are so starved on resources that we are
    962  1.1  haad 	   almost as good as dead already... */
    963  1.1  haad 	if (thread_new->events & DM_EVENT_TIMEOUT) {
    964  1.1  haad 		ret = -_register_for_timeout(thread_new);
    965  1.1  haad 		if (ret) {
    966  1.1  haad 		    _unlock_mutex();
    967  1.1  haad 		    goto out;
    968  1.1  haad 		}
    969  1.1  haad 	}
    970  1.1  haad 
    971  1.1  haad 	if (!(thread = _lookup_thread_status(message_data))) {
    972  1.1  haad 		_unlock_mutex();
    973  1.1  haad 
    974  1.1  haad 		if (!(ret = _do_register_device(thread_new)))
    975  1.1  haad 			goto out;
    976  1.1  haad 
    977  1.1  haad 		thread = thread_new;
    978  1.1  haad 		thread_new = NULL;
    979  1.1  haad 
    980  1.1  haad 		/* Try to create the monitoring thread for this device. */
    981  1.1  haad 		_lock_mutex();
    982  1.1  haad 		if ((ret = -_create_thread(thread))) {
    983  1.1  haad 			_unlock_mutex();
    984  1.1  haad 			_do_unregister_device(thread);
    985  1.1  haad 			_free_thread_status(thread);
    986  1.1  haad 			goto out;
    987  1.1  haad 		} else
    988  1.1  haad 			LINK_THREAD(thread);
    989  1.1  haad 	}
    990  1.1  haad 
    991  1.1  haad 	/* Or event # into events bitfield. */
    992  1.1  haad 	thread->events |= message_data->events.field;
    993  1.1  haad 
    994  1.1  haad 	_unlock_mutex();
    995  1.1  haad 
    996  1.1  haad       out:
    997  1.1  haad 	/*
    998  1.1  haad 	 * Deallocate thread status after releasing
    999  1.1  haad 	 * the lock in case we haven't used it.
   1000  1.1  haad 	 */
   1001  1.1  haad 	if (thread_new)
   1002  1.1  haad 		_free_thread_status(thread_new);
   1003  1.1  haad 
   1004  1.1  haad 	return ret;
   1005  1.1  haad }
   1006  1.1  haad 
   1007  1.1  haad /*
   1008  1.1  haad  * Unregister for an event.
   1009  1.1  haad  *
   1010  1.1  haad  * Only one caller at a time here as with register_for_event().
   1011  1.1  haad  */
   1012  1.1  haad static int _unregister_for_event(struct message_data *message_data)
   1013  1.1  haad {
   1014  1.1  haad 	int ret = 0;
   1015  1.1  haad 	struct thread_status *thread;
   1016  1.1  haad 
   1017  1.1  haad 	/*
   1018  1.1  haad 	 * Clear event in bitfield and deactivate
   1019  1.1  haad 	 * monitoring thread in case bitfield is 0.
   1020  1.1  haad 	 */
   1021  1.1  haad 	_lock_mutex();
   1022  1.1  haad 
   1023  1.1  haad 	if (!(thread = _lookup_thread_status(message_data))) {
   1024  1.1  haad 		_unlock_mutex();
   1025  1.1  haad 		ret = -ENODEV;
   1026  1.1  haad 		goto out;
   1027  1.1  haad 	}
   1028  1.1  haad 
   1029  1.1  haad 	if (thread->status == DM_THREAD_DONE) {
   1030  1.1  haad 		/* the thread has terminated while we were not
   1031  1.1  haad 		   watching */
   1032  1.1  haad 		_unlock_mutex();
   1033  1.1  haad 		return 0;
   1034  1.1  haad 	}
   1035  1.1  haad 
   1036  1.1  haad 	thread->events &= ~message_data->events.field;
   1037  1.1  haad 
   1038  1.1  haad 	if (!(thread->events & DM_EVENT_TIMEOUT))
   1039  1.1  haad 		_unregister_for_timeout(thread);
   1040  1.1  haad 	/*
   1041  1.1  haad 	 * In case there's no events to monitor on this device ->
   1042  1.1  haad 	 * unlink and terminate its monitoring thread.
   1043  1.1  haad 	 */
   1044  1.1  haad 	if (!thread->events) {
   1045  1.1  haad 		UNLINK_THREAD(thread);
   1046  1.1  haad 		LINK(thread, &_thread_registry_unused);
   1047  1.1  haad 	}
   1048  1.1  haad 	_unlock_mutex();
   1049  1.1  haad 
   1050  1.1  haad       out:
   1051  1.1  haad 	return ret;
   1052  1.1  haad }
   1053  1.1  haad 
   1054  1.1  haad /*
   1055  1.1  haad  * Get registered device.
   1056  1.1  haad  *
   1057  1.1  haad  * Only one caller at a time here as with register_for_event().
   1058  1.1  haad  */
   1059  1.1  haad static int _registered_device(struct message_data *message_data,
   1060  1.1  haad 			     struct thread_status *thread)
   1061  1.1  haad {
   1062  1.1  haad 	struct dm_event_daemon_message *msg = message_data->msg;
   1063  1.1  haad 
   1064  1.1  haad 	const char *fmt = "%s %s %s %u";
   1065  1.1  haad 	const char *id = message_data->id;
   1066  1.1  haad 	const char *dso = thread->dso_data->dso_name;
   1067  1.1  haad 	const char *dev = thread->device.uuid;
   1068  1.1  haad 	unsigned events = ((thread->status == DM_THREAD_RUNNING)
   1069  1.1  haad 			   && (thread->events)) ? thread->events : thread->
   1070  1.1  haad 	    events | DM_EVENT_REGISTRATION_PENDING;
   1071  1.1  haad 
   1072  1.1  haad 	if (msg->data)
   1073  1.1  haad 		dm_free(msg->data);
   1074  1.1  haad 
   1075  1.1  haad 	msg->size = dm_asprintf(&(msg->data), fmt, id, dso, dev, events);
   1076  1.1  haad 
   1077  1.1  haad 	_unlock_mutex();
   1078  1.1  haad 
   1079  1.1  haad 	return 0;
   1080  1.1  haad }
   1081  1.1  haad 
   1082  1.1  haad static int _want_registered_device(char *dso_name, char *device_uuid,
   1083  1.1  haad 				  struct thread_status *thread)
   1084  1.1  haad {
   1085  1.1  haad 	/* If DSO names and device paths are equal. */
   1086  1.1  haad 	if (dso_name && device_uuid)
   1087  1.1  haad 		return !strcmp(dso_name, thread->dso_data->dso_name) &&
   1088  1.1  haad 		    !strcmp(device_uuid, thread->device.uuid) &&
   1089  1.1  haad 			(thread->status == DM_THREAD_RUNNING ||
   1090  1.1  haad 			 (thread->events & DM_EVENT_REGISTRATION_PENDING));
   1091  1.1  haad 
   1092  1.1  haad 	/* If DSO names are equal. */
   1093  1.1  haad 	if (dso_name)
   1094  1.1  haad 		return !strcmp(dso_name, thread->dso_data->dso_name) &&
   1095  1.1  haad 			(thread->status == DM_THREAD_RUNNING ||
   1096  1.1  haad 			 (thread->events & DM_EVENT_REGISTRATION_PENDING));
   1097  1.1  haad 
   1098  1.1  haad 	/* If device paths are equal. */
   1099  1.1  haad 	if (device_uuid)
   1100  1.1  haad 		return !strcmp(device_uuid, thread->device.uuid) &&
   1101  1.1  haad 			(thread->status == DM_THREAD_RUNNING ||
   1102  1.1  haad 			 (thread->events & DM_EVENT_REGISTRATION_PENDING));
   1103  1.1  haad 
   1104  1.1  haad 	return 1;
   1105  1.1  haad }
   1106  1.1  haad 
   1107  1.1  haad static int _get_registered_dev(struct message_data *message_data, int next)
   1108  1.1  haad {
   1109  1.1  haad 	struct thread_status *thread, *hit = NULL;
   1110  1.1  haad 
   1111  1.1  haad 	_lock_mutex();
   1112  1.1  haad 
   1113  1.1  haad 	/* Iterate list of threads checking if we want a particular one. */
   1114  1.1  haad 	dm_list_iterate_items(thread, &_thread_registry)
   1115  1.1  haad 		if (_want_registered_device(message_data->dso_name,
   1116  1.1  haad 					    message_data->device_uuid,
   1117  1.1  haad 					    thread)) {
   1118  1.1  haad 			hit = thread;
   1119  1.1  haad 			break;
   1120  1.1  haad 		}
   1121  1.1  haad 
   1122  1.1  haad 	/*
   1123  1.1  haad 	 * If we got a registered device and want the next one ->
   1124  1.1  haad 	 * fetch next conforming element off the list.
   1125  1.1  haad 	 */
   1126  1.1  haad 	if (hit && !next) {
   1127  1.1  haad 		_unlock_mutex();
   1128  1.1  haad 		return _registered_device(message_data, hit);
   1129  1.1  haad 	}
   1130  1.1  haad 
   1131  1.1  haad 	if (!hit)
   1132  1.1  haad 		goto out;
   1133  1.1  haad 
   1134  1.1  haad 	thread = hit;
   1135  1.1  haad 
   1136  1.1  haad 	while (1) {
   1137  1.1  haad 		if (dm_list_end(&_thread_registry, &thread->list))
   1138  1.1  haad 			goto out;
   1139  1.1  haad 
   1140  1.1  haad 		thread = dm_list_item(thread->list.n, struct thread_status);
   1141  1.1  haad 		if (_want_registered_device(message_data->dso_name, NULL, thread)) {
   1142  1.1  haad 			hit = thread;
   1143  1.1  haad 			break;
   1144  1.1  haad 		}
   1145  1.1  haad 	}
   1146  1.1  haad 
   1147  1.1  haad 	_unlock_mutex();
   1148  1.1  haad 	return _registered_device(message_data, hit);
   1149  1.1  haad 
   1150  1.1  haad       out:
   1151  1.1  haad 	_unlock_mutex();
   1152  1.1  haad 
   1153  1.1  haad 	return -ENOENT;
   1154  1.1  haad }
   1155  1.1  haad 
   1156  1.1  haad static int _get_registered_device(struct message_data *message_data)
   1157  1.1  haad {
   1158  1.1  haad 	return _get_registered_dev(message_data, 0);
   1159  1.1  haad }
   1160  1.1  haad 
   1161  1.1  haad static int _get_next_registered_device(struct message_data *message_data)
   1162  1.1  haad {
   1163  1.1  haad 	return _get_registered_dev(message_data, 1);
   1164  1.1  haad }
   1165  1.1  haad 
   1166  1.1  haad static int _set_timeout(struct message_data *message_data)
   1167  1.1  haad {
   1168  1.1  haad 	struct thread_status *thread;
   1169  1.1  haad 
   1170  1.1  haad 	_lock_mutex();
   1171  1.1  haad 	if ((thread = _lookup_thread_status(message_data)))
   1172  1.1  haad 		thread->timeout = message_data->timeout.secs;
   1173  1.1  haad 	_unlock_mutex();
   1174  1.1  haad 
   1175  1.1  haad 	return thread ? 0 : -ENODEV;
   1176  1.1  haad }
   1177  1.1  haad 
   1178  1.1  haad static int _get_timeout(struct message_data *message_data)
   1179  1.1  haad {
   1180  1.1  haad 	struct thread_status *thread;
   1181  1.1  haad 	struct dm_event_daemon_message *msg = message_data->msg;
   1182  1.1  haad 
   1183  1.1  haad 	if (msg->data)
   1184  1.1  haad 		dm_free(msg->data);
   1185  1.1  haad 
   1186  1.1  haad 	_lock_mutex();
   1187  1.1  haad 	if ((thread = _lookup_thread_status(message_data))) {
   1188  1.1  haad 		msg->size =
   1189  1.1  haad 		    dm_asprintf(&(msg->data), "%s %" PRIu32, message_data->id,
   1190  1.1  haad 				thread->timeout);
   1191  1.1  haad 	} else {
   1192  1.1  haad 		msg->data = NULL;
   1193  1.1  haad 		msg->size = 0;
   1194  1.1  haad 	}
   1195  1.1  haad 	_unlock_mutex();
   1196  1.1  haad 
   1197  1.1  haad 	return thread ? 0 : -ENODEV;
   1198  1.1  haad }
   1199  1.1  haad 
   1200  1.1  haad /* Initialize a fifos structure with path names. */
   1201  1.1  haad static void _init_fifos(struct dm_event_fifos *fifos)
   1202  1.1  haad {
   1203  1.1  haad 	memset(fifos, 0, sizeof(*fifos));
   1204  1.1  haad 
   1205  1.1  haad 	fifos->client_path = DM_EVENT_FIFO_CLIENT;
   1206  1.1  haad 	fifos->server_path = DM_EVENT_FIFO_SERVER;
   1207  1.1  haad }
   1208  1.1  haad 
   1209  1.1  haad /* Open fifos used for client communication. */
   1210  1.1  haad static int _open_fifos(struct dm_event_fifos *fifos)
   1211  1.1  haad {
   1212  1.1  haad 	/* Create fifos */
   1213  1.1  haad 	if (((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) ||
   1214  1.1  haad 	    ((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST)) {
   1215  1.1  haad 		syslog(LOG_ERR, "%s: Failed to create a fifo.\n", __func__);
   1216  1.1  haad 		stack;
   1217  1.1  haad 		return -errno;
   1218  1.1  haad 	}
   1219  1.1  haad 
   1220  1.1  haad 	struct stat st;
   1221  1.1  haad 
   1222  1.1  haad 	/* Warn about wrong permissions if applicable */
   1223  1.1  haad 	if ((!stat(fifos->client_path, &st)) && (st.st_mode & 0777) != 0600)
   1224  1.1  haad 		syslog(LOG_WARNING, "Fixing wrong permissions on %s",
   1225  1.1  haad 		       fifos->client_path);
   1226  1.1  haad 
   1227  1.1  haad 	if ((!stat(fifos->server_path, &st)) && (st.st_mode & 0777) != 0600)
   1228  1.1  haad 		syslog(LOG_WARNING, "Fixing wrong permissions on %s",
   1229  1.1  haad 		       fifos->server_path);
   1230  1.1  haad 
   1231  1.1  haad 	/* If they were already there, make sure permissions are ok. */
   1232  1.1  haad 	if (chmod(fifos->client_path, 0600)) {
   1233  1.1  haad 		syslog(LOG_ERR, "Unable to set correct file permissions on %s",
   1234  1.1  haad 		       fifos->client_path);
   1235  1.1  haad 		return -errno;
   1236  1.1  haad 	}
   1237  1.1  haad 
   1238  1.1  haad 	if (chmod(fifos->server_path, 0600)) {
   1239  1.1  haad 		syslog(LOG_ERR, "Unable to set correct file permissions on %s",
   1240  1.1  haad 		       fifos->server_path);
   1241  1.1  haad 		return -errno;
   1242  1.1  haad 	}
   1243  1.1  haad 
   1244  1.1  haad 	/* Need to open read+write or we will block or fail */
   1245  1.1  haad 	if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
   1246  1.1  haad 		stack;
   1247  1.1  haad 		return -errno;
   1248  1.1  haad 	}
   1249  1.1  haad 
   1250  1.1  haad 	/* Need to open read+write for select() to work. */
   1251  1.1  haad 	if ((fifos->client = open(fifos->client_path, O_RDWR)) < 0) {
   1252  1.1  haad 		stack;
   1253  1.1  haad 		close(fifos->server);
   1254  1.1  haad 		return -errno;
   1255  1.1  haad 	}
   1256  1.1  haad 
   1257  1.1  haad 	return 0;
   1258  1.1  haad }
   1259  1.1  haad 
   1260  1.1  haad /*
   1261  1.1  haad  * Read message from client making sure that data is available
   1262  1.1  haad  * and a complete message is read.  Must not block indefinitely.
   1263  1.1  haad  */
   1264  1.1  haad static int _client_read(struct dm_event_fifos *fifos,
   1265  1.1  haad 		       struct dm_event_daemon_message *msg)
   1266  1.1  haad {
   1267  1.1  haad 	struct timeval t;
   1268  1.1  haad 	unsigned bytes = 0;
   1269  1.1  haad 	int ret = 0;
   1270  1.1  haad 	fd_set fds;
   1271  1.1  haad 	int header = 1;
   1272  1.1  haad 	size_t size = 2 * sizeof(uint32_t);	/* status + size */
   1273  1.1  haad 	char *buf = alloca(size);
   1274  1.1  haad 
   1275  1.1  haad 	msg->data = NULL;
   1276  1.1  haad 
   1277  1.1  haad 	errno = 0;
   1278  1.1  haad 	while (bytes < size && errno != EOF) {
   1279  1.1  haad 		/* Watch client read FIFO for input. */
   1280  1.1  haad 		FD_ZERO(&fds);
   1281  1.1  haad 		FD_SET(fifos->client, &fds);
   1282  1.1  haad 		t.tv_sec = 1;
   1283  1.1  haad 		t.tv_usec = 0;
   1284  1.1  haad 		ret = select(fifos->client + 1, &fds, NULL, NULL, &t);
   1285  1.1  haad 
   1286  1.1  haad 		if (!ret && !bytes)	/* nothing to read */
   1287  1.1  haad 			return 0;
   1288  1.1  haad 
   1289  1.1  haad 		if (!ret)	/* trying to finish read */
   1290  1.1  haad 			continue;
   1291  1.1  haad 
   1292  1.1  haad 		if (ret < 0)	/* error */
   1293  1.1  haad 			return 0;
   1294  1.1  haad 
   1295  1.1  haad 		ret = read(fifos->client, buf + bytes, size - bytes);
   1296  1.1  haad 		bytes += ret > 0 ? ret : 0;
   1297  1.1  haad 		if (bytes == 2 * sizeof(uint32_t) && header) {
   1298  1.1  haad 			msg->cmd = ntohl(*((uint32_t *) buf));
   1299  1.1  haad 			msg->size = ntohl(*((uint32_t *) buf + 1));
   1300  1.1  haad 			buf = msg->data = dm_malloc(msg->size);
   1301  1.1  haad 			size = msg->size;
   1302  1.1  haad 			bytes = 0;
   1303  1.1  haad 			header = 0;
   1304  1.1  haad 		}
   1305  1.1  haad 	}
   1306  1.1  haad 
   1307  1.1  haad 	if (bytes != size) {
   1308  1.1  haad 		if (msg->data)
   1309  1.1  haad 			dm_free(msg->data);
   1310  1.1  haad 		msg->data = NULL;
   1311  1.1  haad 		msg->size = 0;
   1312  1.1  haad 	}
   1313  1.1  haad 
   1314  1.1  haad 	return bytes == size;
   1315  1.1  haad }
   1316  1.1  haad 
   1317  1.1  haad /*
   1318  1.1  haad  * Write a message to the client making sure that it is ready to write.
   1319  1.1  haad  */
   1320  1.1  haad static int _client_write(struct dm_event_fifos *fifos,
   1321  1.1  haad 			struct dm_event_daemon_message *msg)
   1322  1.1  haad {
   1323  1.1  haad 	unsigned bytes = 0;
   1324  1.1  haad 	int ret = 0;
   1325  1.1  haad 	fd_set fds;
   1326  1.1  haad 
   1327  1.1  haad 	size_t size = 2 * sizeof(uint32_t) + msg->size;
   1328  1.1  haad 	char *buf = alloca(size);
   1329  1.1  haad 
   1330  1.1  haad 	*((uint32_t *)buf) = htonl(msg->cmd);
   1331  1.1  haad 	*((uint32_t *)buf + 1) = htonl(msg->size);
   1332  1.1  haad 	if (msg->data)
   1333  1.1  haad 		memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
   1334  1.1  haad 
   1335  1.1  haad 	errno = 0;
   1336  1.1  haad 	while (bytes < size && errno != EIO) {
   1337  1.1  haad 		do {
   1338  1.1  haad 			/* Watch client write FIFO to be ready for output. */
   1339  1.1  haad 			FD_ZERO(&fds);
   1340  1.1  haad 			FD_SET(fifos->server, &fds);
   1341  1.1  haad 		} while (select(fifos->server + 1, NULL, &fds, NULL, NULL) !=
   1342  1.1  haad 			 1);
   1343  1.1  haad 
   1344  1.1  haad 		ret = write(fifos->server, buf + bytes, size - bytes);
   1345  1.1  haad 		bytes += ret > 0 ? ret : 0;
   1346  1.1  haad 	}
   1347  1.1  haad 
   1348  1.1  haad 	return bytes == size;
   1349  1.1  haad }
   1350  1.1  haad 
   1351  1.1  haad /*
   1352  1.1  haad  * Handle a client request.
   1353  1.1  haad  *
   1354  1.1  haad  * We put the request handling functions into
   1355  1.1  haad  * a list because of the growing number.
   1356  1.1  haad  */
   1357  1.1  haad static int _handle_request(struct dm_event_daemon_message *msg,
   1358  1.1  haad 			  struct message_data *message_data)
   1359  1.1  haad {
   1360  1.1  haad 	static struct {
   1361  1.1  haad 		unsigned int cmd;
   1362  1.1  haad 		int (*f)(struct message_data *);
   1363  1.1  haad 	} requests[] = {
   1364  1.1  haad 		{ DM_EVENT_CMD_REGISTER_FOR_EVENT, _register_for_event},
   1365  1.1  haad 		{ DM_EVENT_CMD_UNREGISTER_FOR_EVENT, _unregister_for_event},
   1366  1.1  haad 		{ DM_EVENT_CMD_GET_REGISTERED_DEVICE, _get_registered_device},
   1367  1.1  haad 		{ DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
   1368  1.1  haad 			_get_next_registered_device},
   1369  1.1  haad 		{ DM_EVENT_CMD_SET_TIMEOUT, _set_timeout},
   1370  1.1  haad 		{ DM_EVENT_CMD_GET_TIMEOUT, _get_timeout},
   1371  1.1  haad 		{ DM_EVENT_CMD_ACTIVE, _active},
   1372  1.1  haad 	}, *req;
   1373  1.1  haad 
   1374  1.1  haad 	for (req = requests; req < requests + sizeof(requests); req++)
   1375  1.1  haad 		if (req->cmd == msg->cmd)
   1376  1.1  haad 			return req->f(message_data);
   1377  1.1  haad 
   1378  1.1  haad 	return -EINVAL;
   1379  1.1  haad }
   1380  1.1  haad 
   1381  1.1  haad /* Process a request passed from the communication thread. */
   1382  1.1  haad static int _do_process_request(struct dm_event_daemon_message *msg)
   1383  1.1  haad {
   1384  1.1  haad 	int ret;
   1385  1.1  haad 	char *answer;
   1386  1.1  haad 	static struct message_data message_data;
   1387  1.1  haad 
   1388  1.1  haad 	/* Parse the message. */
   1389  1.1  haad 	memset(&message_data, 0, sizeof(message_data));
   1390  1.1  haad 	message_data.msg = msg;
   1391  1.1  haad 	if (msg->cmd == DM_EVENT_CMD_HELLO)  {
   1392  1.1  haad 		ret = 0;
   1393  1.1  haad 		answer = msg->data;
   1394  1.1  haad 		if (answer) {
   1395  1.1  haad 			msg->size = dm_asprintf(&(msg->data), "%s HELLO", answer);
   1396  1.1  haad 			dm_free(answer);
   1397  1.1  haad 		} else {
   1398  1.1  haad 			msg->size = 0;
   1399  1.1  haad 			msg->data = NULL;
   1400  1.1  haad 		}
   1401  1.1  haad 	} else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
   1402  1.1  haad 		stack;
   1403  1.1  haad 		ret = -EINVAL;
   1404  1.1  haad 	} else
   1405  1.1  haad 		ret = _handle_request(msg, &message_data);
   1406  1.1  haad 
   1407  1.1  haad 	msg->cmd = ret;
   1408  1.1  haad 	if (!msg->data)
   1409  1.1  haad 		msg->size = dm_asprintf(&(msg->data), "%s %s", message_data.id, strerror(-ret));
   1410  1.1  haad 
   1411  1.1  haad 	_free_message(&message_data);
   1412  1.1  haad 
   1413  1.1  haad 	return ret;
   1414  1.1  haad }
   1415  1.1  haad 
   1416  1.1  haad /* Only one caller at a time. */
   1417  1.1  haad static void _process_request(struct dm_event_fifos *fifos)
   1418  1.1  haad {
   1419  1.1  haad 	struct dm_event_daemon_message msg;
   1420  1.1  haad 
   1421  1.1  haad 	memset(&msg, 0, sizeof(msg));
   1422  1.1  haad 
   1423  1.1  haad 	/*
   1424  1.1  haad 	 * Read the request from the client (client_read, client_write
   1425  1.1  haad 	 * give true on success and false on failure).
   1426  1.1  haad 	 */
   1427  1.1  haad 	if (!_client_read(fifos, &msg))
   1428  1.1  haad 		return;
   1429  1.1  haad 
   1430  1.1  haad 	/* _do_process_request fills in msg (if memory allows for
   1431  1.1  haad 	   data, otherwise just cmd and size = 0) */
   1432  1.1  haad 	_do_process_request(&msg);
   1433  1.1  haad 
   1434  1.1  haad 	if (!_client_write(fifos, &msg))
   1435  1.1  haad 		stack;
   1436  1.1  haad 
   1437  1.1  haad 	if (msg.data)
   1438  1.1  haad 		dm_free(msg.data);
   1439  1.1  haad }
   1440  1.1  haad 
   1441  1.1  haad static void _cleanup_unused_threads(void)
   1442  1.1  haad {
   1443  1.1  haad 	int ret;
   1444  1.1  haad 	struct dm_list *l;
   1445  1.1  haad 	struct thread_status *thread;
   1446  1.1  haad 
   1447  1.1  haad 	_lock_mutex();
   1448  1.1  haad 	while ((l = dm_list_first(&_thread_registry_unused))) {
   1449  1.1  haad 		thread = dm_list_item(l, struct thread_status);
   1450  1.1  haad 		if (thread->processing)
   1451  1.1  haad 			break;	/* cleanup on the next round */
   1452  1.1  haad 
   1453  1.1  haad 		if (thread->status == DM_THREAD_RUNNING) {
   1454  1.1  haad 			thread->status = DM_THREAD_SHUTDOWN;
   1455  1.1  haad 			break;
   1456  1.1  haad 		}
   1457  1.1  haad 
   1458  1.1  haad 		if (thread->status == DM_THREAD_SHUTDOWN) {
   1459  1.1  haad 			if (!thread->events) {
   1460  1.1  haad 				/* turn codes negative -- should we be returning this? */
   1461  1.1  haad 				ret = _terminate_thread(thread);
   1462  1.1  haad 
   1463  1.1  haad 				if (ret == ESRCH) {
   1464  1.1  haad 					thread->status = DM_THREAD_DONE;
   1465  1.1  haad 				} else if (ret) {
   1466  1.1  haad 					syslog(LOG_ERR,
   1467  1.1  haad 					       "Unable to terminate thread: %s\n",
   1468  1.1  haad 					       strerror(-ret));
   1469  1.1  haad 					stack;
   1470  1.1  haad 				}
   1471  1.1  haad 				break;
   1472  1.1  haad 			}
   1473  1.1  haad 
   1474  1.1  haad 			dm_list_del(l);
   1475  1.1  haad 			syslog(LOG_ERR,
   1476  1.1  haad 			       "thread can't be on unused list unless !thread->events");
   1477  1.1  haad 			thread->status = DM_THREAD_RUNNING;
   1478  1.1  haad 			LINK_THREAD(thread);
   1479  1.1  haad 
   1480  1.1  haad 			continue;
   1481  1.1  haad 		}
   1482  1.1  haad 
   1483  1.1  haad 		if (thread->status == DM_THREAD_DONE) {
   1484  1.1  haad 			dm_list_del(l);
   1485  1.1  haad 			pthread_join(thread->thread, NULL);
   1486  1.1  haad 			_lib_put(thread->dso_data);
   1487  1.1  haad 			_free_thread_status(thread);
   1488  1.1  haad 		}
   1489  1.1  haad 	}
   1490  1.1  haad 
   1491  1.1  haad 	_unlock_mutex();
   1492  1.1  haad }
   1493  1.1  haad 
   1494  1.1  haad static void _sig_alarm(int signum __attribute((unused)))
   1495  1.1  haad {
   1496  1.1  haad 	pthread_testcancel();
   1497  1.1  haad }
   1498  1.1  haad 
   1499  1.1  haad /* Init thread signal handling. */
   1500  1.1  haad static void _init_thread_signals(void)
   1501  1.1  haad {
   1502  1.1  haad 	sigset_t my_sigset;
   1503  1.1  haad 	struct sigaction act;
   1504  1.1  haad 
   1505  1.1  haad 	memset(&act, 0, sizeof(act));
   1506  1.1  haad 	act.sa_handler = _sig_alarm;
   1507  1.1  haad 	sigaction(SIGALRM, &act, NULL);
   1508  1.1  haad 	sigfillset(&my_sigset);
   1509  1.1  haad 
   1510  1.1  haad 	/* These are used for exiting */
   1511  1.1  haad 	sigdelset(&my_sigset, SIGTERM);
   1512  1.1  haad 	sigdelset(&my_sigset, SIGINT);
   1513  1.1  haad 	sigdelset(&my_sigset, SIGHUP);
   1514  1.1  haad 	sigdelset(&my_sigset, SIGQUIT);
   1515  1.1  haad 
   1516  1.1  haad 	pthread_sigmask(SIG_BLOCK, &my_sigset, NULL);
   1517  1.1  haad }
   1518  1.1  haad 
   1519  1.1  haad /*
   1520  1.1  haad  * exit_handler
   1521  1.1  haad  * @sig
   1522  1.1  haad  *
   1523  1.1  haad  * Set the global variable which the process should
   1524  1.1  haad  * be watching to determine when to exit.
   1525  1.1  haad  */
   1526  1.1  haad static void _exit_handler(int sig __attribute((unused)))
   1527  1.1  haad {
   1528  1.1  haad 	/*
   1529  1.1  haad 	 * We exit when '_exit_now' is set.
   1530  1.1  haad 	 * That is, when a signal has been received.
   1531  1.1  haad 	 *
   1532  1.1  haad 	 * We can not simply set '_exit_now' unless all
   1533  1.1  haad 	 * threads are done processing.
   1534  1.1  haad 	 */
   1535  1.1  haad 	if (!_thread_registries_empty) {
   1536  1.1  haad 		syslog(LOG_ERR, "There are still devices being monitored.");
   1537  1.1  haad 		syslog(LOG_ERR, "Refusing to exit.");
   1538  1.1  haad 	} else
   1539  1.1  haad 		_exit_now = 1;
   1540  1.1  haad 
   1541  1.1  haad }
   1542  1.1  haad 
   1543  1.1  haad static int _lock_pidfile(void)
   1544  1.1  haad {
   1545  1.1  haad 	int lf;
   1546  1.1  haad 	char pidfile[] = DMEVENTD_PIDFILE;
   1547  1.1  haad 
   1548  1.1  haad 	if ((lf = open(pidfile, O_CREAT | O_RDWR, 0644)) < 0)
   1549  1.1  haad 		exit(EXIT_OPEN_PID_FAILURE);
   1550  1.1  haad 
   1551  1.1  haad 	if (flock(lf, LOCK_EX | LOCK_NB) < 0)
   1552  1.1  haad 		exit(EXIT_LOCKFILE_INUSE);
   1553  1.1  haad 
   1554  1.1  haad 	if (!_storepid(lf))
   1555  1.1  haad 		exit(EXIT_FAILURE);
   1556  1.1  haad 
   1557  1.1  haad 	return 0;
   1558  1.1  haad }
   1559  1.1  haad 
   1560  1.1  haad #ifdef linux
   1561  1.1  haad /*
   1562  1.1  haad  * Protection against OOM killer if kernel supports it
   1563  1.1  haad  */
   1564  1.1  haad static int _set_oom_adj(int val)
   1565  1.1  haad {
   1566  1.1  haad 	FILE *fp;
   1567  1.1  haad 
   1568  1.1  haad 	struct stat st;
   1569  1.1  haad 
   1570  1.1  haad 	if (stat(OOM_ADJ_FILE, &st) == -1) {
   1571  1.1  haad 		if (errno == ENOENT)
   1572  1.1  haad 			DEBUGLOG(OOM_ADJ_FILE " not found");
   1573  1.1  haad 		else
   1574  1.1  haad 			perror(OOM_ADJ_FILE ": stat failed");
   1575  1.1  haad 		return 1;
   1576  1.1  haad 	}
   1577  1.1  haad 
   1578  1.1  haad 	if (!(fp = fopen(OOM_ADJ_FILE, "w"))) {
   1579  1.1  haad 		perror(OOM_ADJ_FILE ": fopen failed");
   1580  1.1  haad 		return 0;
   1581  1.1  haad 	}
   1582  1.1  haad 
   1583  1.1  haad 	fprintf(fp, "%i", val);
   1584  1.1  haad 	if (dm_fclose(fp))
   1585  1.1  haad 		perror(OOM_ADJ_FILE ": fclose failed");
   1586  1.1  haad 
   1587  1.1  haad 	return 1;
   1588  1.1  haad }
   1589  1.1  haad #endif
   1590  1.1  haad 
   1591  1.1  haad static void _daemonize(void)
   1592  1.1  haad {
   1593  1.1  haad 	int child_status;
   1594  1.1  haad 	int fd;
   1595  1.1  haad 	pid_t pid;
   1596  1.1  haad 	struct rlimit rlim;
   1597  1.1  haad 	struct timeval tval;
   1598  1.1  haad 	sigset_t my_sigset;
   1599  1.1  haad 
   1600  1.1  haad 	sigemptyset(&my_sigset);
   1601  1.1  haad 	if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) {
   1602  1.1  haad 		fprintf(stderr, "Unable to restore signals.\n");
   1603  1.1  haad 		exit(EXIT_FAILURE);
   1604  1.1  haad 	}
   1605  1.1  haad 	signal(SIGTERM, &_exit_handler);
   1606  1.1  haad 
   1607  1.1  haad 	switch (pid = fork()) {
   1608  1.1  haad 	case -1:
   1609  1.1  haad 		perror("fork failed:");
   1610  1.1  haad 		exit(EXIT_FAILURE);
   1611  1.1  haad 
   1612  1.1  haad 	case 0:		/* Child */
   1613  1.1  haad 		break;
   1614  1.1  haad 
   1615  1.1  haad 	default:
   1616  1.1  haad 		/* Wait for response from child */
   1617  1.1  haad 		while (!waitpid(pid, &child_status, WNOHANG) && !_exit_now) {
   1618  1.1  haad 			tval.tv_sec = 0;
   1619  1.1  haad 			tval.tv_usec = 250000;	/* .25 sec */
   1620  1.1  haad 			select(0, NULL, NULL, NULL, &tval);
   1621  1.1  haad 		}
   1622  1.1  haad 
   1623  1.1  haad 		if (_exit_now)	/* Child has signaled it is ok - we can exit now */
   1624  1.1  haad 			exit(EXIT_SUCCESS);
   1625  1.1  haad 
   1626  1.1  haad 		/* Problem with child.  Determine what it is by exit code */
   1627  1.1  haad 		switch (WEXITSTATUS(child_status)) {
   1628  1.1  haad 		case EXIT_LOCKFILE_INUSE:
   1629  1.1  haad 			fprintf(stderr, "Another dmeventd daemon is already running\n");
   1630  1.1  haad 			break;
   1631  1.1  haad 		case EXIT_DESC_CLOSE_FAILURE:
   1632  1.1  haad 		case EXIT_DESC_OPEN_FAILURE:
   1633  1.1  haad 		case EXIT_OPEN_PID_FAILURE:
   1634  1.1  haad 		case EXIT_FIFO_FAILURE:
   1635  1.1  haad 		case EXIT_CHDIR_FAILURE:
   1636  1.1  haad 		default:
   1637  1.1  haad 			fprintf(stderr, "Child exited with code %d\n", WEXITSTATUS(child_status));
   1638  1.1  haad 			break;
   1639  1.1  haad 		}
   1640  1.1  haad 
   1641  1.1  haad 		exit(WEXITSTATUS(child_status));
   1642  1.1  haad 	}
   1643  1.1  haad 
   1644  1.1  haad 	if (chdir("/"))
   1645  1.1  haad 		exit(EXIT_CHDIR_FAILURE);
   1646  1.1  haad 
   1647  1.1  haad 	if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
   1648  1.1  haad 		fd = 256;	/* just have to guess */
   1649  1.1  haad 	else
   1650  1.1  haad 		fd = rlim.rlim_cur;
   1651  1.1  haad 
   1652  1.1  haad 	for (--fd; fd >= 0; fd--)
   1653  1.1  haad 		close(fd);
   1654  1.1  haad 
   1655  1.1  haad 	if ((open("/dev/null", O_RDONLY) < 0) ||
   1656  1.1  haad 	    (open("/dev/null", O_WRONLY) < 0) ||
   1657  1.1  haad 	    (open("/dev/null", O_WRONLY) < 0))
   1658  1.1  haad 		exit(EXIT_DESC_OPEN_FAILURE);
   1659  1.1  haad 
   1660  1.1  haad 	setsid();
   1661  1.1  haad }
   1662  1.1  haad 
   1663  1.1  haad static void usage(char *prog, FILE *file)
   1664  1.1  haad {
   1665  1.1  haad 	fprintf(file, "Usage:\n");
   1666  1.1  haad 	fprintf(file, "%s [Vhd]\n", prog);
   1667  1.1  haad 	fprintf(file, "\n");
   1668  1.1  haad 	fprintf(file, "   -V       Show version of dmeventd\n");
   1669  1.1  haad 	fprintf(file, "   -h       Show this help information\n");
   1670  1.1  haad 	fprintf(file, "   -d       Don't fork, run in the foreground\n");
   1671  1.1  haad 	fprintf(file, "\n");
   1672  1.1  haad }
   1673  1.1  haad 
   1674  1.1  haad int main(int argc, char *argv[])
   1675  1.1  haad {
   1676  1.1  haad 	int ret;
   1677  1.1  haad 	signed char opt;
   1678  1.1  haad 	struct dm_event_fifos fifos;
   1679  1.1  haad 	//struct sys_log logdata = {DAEMON_NAME, LOG_DAEMON};
   1680  1.1  haad 
   1681  1.1  haad 	opterr = 0;
   1682  1.1  haad 	optind = 0;
   1683  1.1  haad 
   1684  1.1  haad 	while ((opt = getopt(argc, argv, "?hVd")) != EOF) {
   1685  1.1  haad 		switch (opt) {
   1686  1.1  haad 		case 'h':
   1687  1.1  haad 			usage(argv[0], stdout);
   1688  1.1  haad 			exit(0);
   1689  1.1  haad 		case '?':
   1690  1.1  haad 			usage(argv[0], stderr);
   1691  1.1  haad 			exit(0);
   1692  1.1  haad 		case 'd':
   1693  1.1  haad 			_debug++;
   1694  1.1  haad 			break;
   1695  1.1  haad 		case 'V':
   1696  1.1  haad 			printf("dmeventd version: %s\n", DM_LIB_VERSION);
   1697  1.1  haad 			exit(1);
   1698  1.1  haad 			break;
   1699  1.1  haad 		}
   1700  1.1  haad 	}
   1701  1.1  haad 
   1702  1.1  haad 	if (!_debug)
   1703  1.1  haad 		_daemonize();
   1704  1.1  haad 
   1705  1.1  haad 	openlog("dmeventd", LOG_PID, LOG_DAEMON);
   1706  1.1  haad 
   1707  1.1  haad 	_lock_pidfile();		/* exits if failure */
   1708  1.1  haad 
   1709  1.1  haad 	/* Set the rest of the signals to cause '_exit_now' to be set */
   1710  1.1  haad 	signal(SIGINT, &_exit_handler);
   1711  1.1  haad 	signal(SIGHUP, &_exit_handler);
   1712  1.1  haad 	signal(SIGQUIT, &_exit_handler);
   1713  1.1  haad 
   1714  1.1  haad #ifdef linux
   1715  1.1  haad 	if (!_set_oom_adj(OOM_DISABLE) && !_set_oom_adj(OOM_ADJUST_MIN))
   1716  1.1  haad 		syslog(LOG_ERR, "Failed to set oom_adj to protect against OOM killer");
   1717  1.1  haad #endif
   1718  1.1  haad 
   1719  1.1  haad 	_init_thread_signals();
   1720  1.1  haad 
   1721  1.1  haad 	//multilog_clear_logging();
   1722  1.1  haad 	//multilog_add_type(std_syslog, &logdata);
   1723  1.1  haad 	//multilog_init_verbose(std_syslog, _LOG_DEBUG);
   1724  1.1  haad 	//multilog_async(1);
   1725  1.1  haad 
   1726  1.1  haad 	_init_fifos(&fifos);
   1727  1.1  haad 
   1728  1.1  haad 	pthread_mutex_init(&_global_mutex, NULL);
   1729  1.1  haad 
   1730  1.1  haad #ifdef MCL_CURRENT
   1731  1.1  haad 	if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1)
   1732  1.1  haad 		exit(EXIT_FAILURE);
   1733  1.1  haad #endif
   1734  1.1  haad 
   1735  1.1  haad 	if ((ret = _open_fifos(&fifos)))
   1736  1.1  haad 		exit(EXIT_FIFO_FAILURE);
   1737  1.1  haad 
   1738  1.1  haad 	/* Signal parent, letting them know we are ready to go. */
   1739  1.1  haad 	kill(getppid(), SIGTERM);
   1740  1.1  haad 	syslog(LOG_NOTICE, "dmeventd ready for processing.");
   1741  1.1  haad 
   1742  1.1  haad 	while (!_exit_now) {
   1743  1.1  haad 		_process_request(&fifos);
   1744  1.1  haad 		_cleanup_unused_threads();
   1745  1.1  haad 		if (!dm_list_empty(&_thread_registry)
   1746  1.1  haad 		    || !dm_list_empty(&_thread_registry_unused))
   1747  1.1  haad 			_thread_registries_empty = 0;
   1748  1.1  haad 		else
   1749  1.1  haad 			_thread_registries_empty = 1;
   1750  1.1  haad 	}
   1751  1.1  haad 
   1752  1.1  haad 	_exit_dm_lib();
   1753  1.1  haad 
   1754  1.1  haad #ifdef MCL_CURRENT
   1755  1.1  haad 	munlockall();
   1756  1.1  haad #endif
   1757  1.1  haad 	pthread_mutex_destroy(&_global_mutex);
   1758  1.1  haad 
   1759  1.1  haad 	syslog(LOG_NOTICE, "dmeventd shutting down.");
   1760  1.1  haad 	closelog();
   1761  1.1  haad 
   1762  1.1  haad 	exit(EXIT_SUCCESS);
   1763  1.1  haad }
   1764