Home | History | Annotate | Line # | Download | only in dmeventd
      1 /*	$NetBSD: libdevmapper-event.c,v 1.1.1.2 2009/12/02 00:27:11 haad Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
      5  *
      6  * This file is part of the device-mapper userspace tools.
      7  *
      8  * This copyrighted material is made available to anyone wishing to use,
      9  * modify, copy, or redistribute it subject to the terms and conditions
     10  * of the GNU Lesser General Public License v.2.1.
     11  *
     12  * You should have received a copy of the GNU Lesser General Public License
     13  * along with this program; if not, write to the Free Software Foundation,
     14  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     15  */
     16 
     17 #include "dmlib.h"
     18 #include "libdevmapper-event.h"
     19 //#include "libmultilog.h"
     20 #include "dmeventd.h"
     21 
     22 #include <errno.h>
     23 #include <fcntl.h>
     24 #include <stdio.h>
     25 #include <stdint.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <sys/file.h>
     29 #include <sys/types.h>
     30 #include <sys/stat.h>
     31 #include <unistd.h>
     32 #include <sys/wait.h>
     33 #include <arpa/inet.h>		/* for htonl, ntohl */
     34 
     35 static int _sequence_nr = 0;
     36 
     37 struct dm_event_handler {
     38 	char *dso;
     39 
     40 	char *dev_name;
     41 
     42 	char *uuid;
     43 	int major;
     44 	int minor;
     45 	uint32_t timeout;
     46 
     47 	enum dm_event_mask mask;
     48 };
     49 
     50 static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
     51 {
     52 	if (dmevh->dev_name)
     53 		dm_free(dmevh->dev_name);
     54 	if (dmevh->uuid)
     55 		dm_free(dmevh->uuid);
     56 	dmevh->dev_name = dmevh->uuid = NULL;
     57 	dmevh->major = dmevh->minor = 0;
     58 }
     59 
     60 struct dm_event_handler *dm_event_handler_create(void)
     61 {
     62 	struct dm_event_handler *dmevh = NULL;
     63 
     64 	if (!(dmevh = dm_malloc(sizeof(*dmevh))))
     65 		return NULL;
     66 
     67 	dmevh->dso = dmevh->dev_name = dmevh->uuid = NULL;
     68 	dmevh->major = dmevh->minor = 0;
     69 	dmevh->mask = 0;
     70 	dmevh->timeout = 0;
     71 
     72 	return dmevh;
     73 }
     74 
     75 void dm_event_handler_destroy(struct dm_event_handler *dmevh)
     76 {
     77 	_dm_event_handler_clear_dev_info(dmevh);
     78 	if (dmevh->dso)
     79 		dm_free(dmevh->dso);
     80 	dm_free(dmevh);
     81 }
     82 
     83 int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
     84 {
     85 	if (!path) /* noop */
     86 		return 0;
     87 	if (dmevh->dso)
     88 		dm_free(dmevh->dso);
     89 
     90 	dmevh->dso = dm_strdup(path);
     91 	if (!dmevh->dso)
     92 		return -ENOMEM;
     93 
     94 	return 0;
     95 }
     96 
     97 int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name)
     98 {
     99 	if (!dev_name)
    100 		return 0;
    101 
    102 	_dm_event_handler_clear_dev_info(dmevh);
    103 
    104 	dmevh->dev_name = dm_strdup(dev_name);
    105 	if (!dmevh->dev_name)
    106 		return -ENOMEM;
    107 	return 0;
    108 }
    109 
    110 int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
    111 {
    112 	if (!uuid)
    113 		return 0;
    114 
    115 	_dm_event_handler_clear_dev_info(dmevh);
    116 
    117 	dmevh->uuid = dm_strdup(uuid);
    118 	if (!dmevh->dev_name)
    119 		return -ENOMEM;
    120 	return 0;
    121 }
    122 
    123 void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major)
    124 {
    125 	int minor = dmevh->minor;
    126 
    127 	_dm_event_handler_clear_dev_info(dmevh);
    128 
    129 	dmevh->major = major;
    130 	dmevh->minor = minor;
    131 }
    132 
    133 void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor)
    134 {
    135 	int major = dmevh->major;
    136 
    137 	_dm_event_handler_clear_dev_info(dmevh);
    138 
    139 	dmevh->major = major;
    140 	dmevh->minor = minor;
    141 }
    142 
    143 void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
    144 				     enum dm_event_mask evmask)
    145 {
    146 	dmevh->mask = evmask;
    147 }
    148 
    149 void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout)
    150 {
    151 	dmevh->timeout = timeout;
    152 }
    153 
    154 const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh)
    155 {
    156 	return dmevh->dso;
    157 }
    158 
    159 const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh)
    160 {
    161 	return dmevh->dev_name;
    162 }
    163 
    164 const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh)
    165 {
    166 	return dmevh->uuid;
    167 }
    168 
    169 int dm_event_handler_get_major(const struct dm_event_handler *dmevh)
    170 {
    171 	return dmevh->major;
    172 }
    173 
    174 int dm_event_handler_get_minor(const struct dm_event_handler *dmevh)
    175 {
    176 	return dmevh->minor;
    177 }
    178 
    179 int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh)
    180 {
    181 	return dmevh->timeout;
    182 }
    183 
    184 enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh)
    185 {
    186 	return dmevh->mask;
    187 }
    188 
    189 static int _check_message_id(struct dm_event_daemon_message *msg)
    190 {
    191 	int pid, seq_nr;
    192 
    193 	if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
    194 	    (pid != getpid()) || (seq_nr != _sequence_nr)) {
    195 		log_error("Ignoring out-of-sequence reply from dmeventd. "
    196 			  "Expected %d:%d but received %s", getpid(),
    197 			  _sequence_nr, msg->data);
    198 		return 0;
    199 	}
    200 
    201 	return 1;
    202 }
    203 
    204 /*
    205  * daemon_read
    206  * @fifos
    207  * @msg
    208  *
    209  * Read message from daemon.
    210  *
    211  * Returns: 0 on failure, 1 on success
    212  */
    213 static int _daemon_read(struct dm_event_fifos *fifos,
    214 			struct dm_event_daemon_message *msg)
    215 {
    216 	unsigned bytes = 0;
    217 	int ret, i;
    218 	fd_set fds;
    219 	struct timeval tval = { 0, 0 };
    220 	size_t size = 2 * sizeof(uint32_t);	/* status + size */
    221 	char *buf = alloca(size);
    222 	int header = 1;
    223 
    224 	while (bytes < size) {
    225 		for (i = 0, ret = 0; (i < 20) && (ret < 1); i++) {
    226 			/* Watch daemon read FIFO for input. */
    227 			FD_ZERO(&fds);
    228 			FD_SET(fifos->server, &fds);
    229 			tval.tv_sec = 1;
    230 			ret = select(fifos->server + 1, &fds, NULL, NULL,
    231 				     &tval);
    232 			if (ret < 0 && errno != EINTR) {
    233 				log_error("Unable to read from event server");
    234 				return 0;
    235 			}
    236 		}
    237 		if (ret < 1) {
    238 			log_error("Unable to read from event server.");
    239 			return 0;
    240 		}
    241 
    242 		ret = read(fifos->server, buf + bytes, size);
    243 		if (ret < 0) {
    244 			if ((errno == EINTR) || (errno == EAGAIN))
    245 				continue;
    246 			else {
    247 				log_error("Unable to read from event server.");
    248 				return 0;
    249 			}
    250 		}
    251 
    252 		bytes += ret;
    253 		if (bytes == 2 * sizeof(uint32_t) && header) {
    254 			msg->cmd = ntohl(*((uint32_t *)buf));
    255 			msg->size = ntohl(*((uint32_t *)buf + 1));
    256 			buf = msg->data = dm_malloc(msg->size);
    257 			size = msg->size;
    258 			bytes = 0;
    259 			header = 0;
    260 		}
    261 	}
    262 
    263 	if (bytes != size) {
    264 		if (msg->data)
    265 			dm_free(msg->data);
    266 		msg->data = NULL;
    267 	}
    268 
    269 	return bytes == size;
    270 }
    271 
    272 /* Write message to daemon. */
    273 static int _daemon_write(struct dm_event_fifos *fifos,
    274 			 struct dm_event_daemon_message *msg)
    275 {
    276 	unsigned bytes = 0;
    277 	int ret = 0;
    278 	fd_set fds;
    279 
    280 	size_t size = 2 * sizeof(uint32_t) + msg->size;
    281 	char *buf = alloca(size);
    282 	char drainbuf[128];
    283 	struct timeval tval = { 0, 0 };
    284 
    285 	*((uint32_t *)buf) = htonl(msg->cmd);
    286 	*((uint32_t *)buf + 1) = htonl(msg->size);
    287 	memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
    288 
    289 	/* drain the answer fifo */
    290 	while (1) {
    291 		FD_ZERO(&fds);
    292 		FD_SET(fifos->server, &fds);
    293 		tval.tv_usec = 100;
    294 		ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
    295 		if ((ret < 0) && (errno != EINTR)) {
    296 			log_error("Unable to talk to event daemon");
    297 			return 0;
    298 		}
    299 		if (ret == 0)
    300 			break;
    301 		read(fifos->server, drainbuf, 127);
    302 	}
    303 
    304 	while (bytes < size) {
    305 		do {
    306 			/* Watch daemon write FIFO to be ready for output. */
    307 			FD_ZERO(&fds);
    308 			FD_SET(fifos->client, &fds);
    309 			ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
    310 			if ((ret < 0) && (errno != EINTR)) {
    311 				log_error("Unable to talk to event daemon");
    312 				return 0;
    313 			}
    314 		} while (ret < 1);
    315 
    316 		ret = write(fifos->client, ((char *) buf) + bytes,
    317 			    size - bytes);
    318 		if (ret < 0) {
    319 			if ((errno == EINTR) || (errno == EAGAIN))
    320 				continue;
    321 			else {
    322 				log_error("Unable to talk to event daemon");
    323 				return 0;
    324 			}
    325 		}
    326 
    327 		bytes += ret;
    328 	}
    329 
    330 	return bytes == size;
    331 }
    332 
    333 static int _daemon_talk(struct dm_event_fifos *fifos,
    334 			struct dm_event_daemon_message *msg, int cmd,
    335 			const char *dso_name, const char *dev_name,
    336 			enum dm_event_mask evmask, uint32_t timeout)
    337 {
    338 	const char *dso = dso_name ? dso_name : "";
    339 	const char *dev = dev_name ? dev_name : "";
    340 	const char *fmt = "%d:%d %s %s %u %" PRIu32;
    341 	int msg_size;
    342 	memset(msg, 0, sizeof(*msg));
    343 
    344 	/*
    345 	 * Set command and pack the arguments
    346 	 * into ASCII message string.
    347 	 */
    348 	msg->cmd = cmd;
    349 	if (cmd == DM_EVENT_CMD_HELLO)
    350 		fmt = "%d:%d HELLO";
    351 	if ((msg_size = dm_asprintf(&(msg->data), fmt, getpid(), _sequence_nr,
    352 				    dso, dev, evmask, timeout)) < 0) {
    353 		log_error("_daemon_talk: message allocation failed");
    354 		return -ENOMEM;
    355 	}
    356 	msg->size = msg_size;
    357 
    358 	/*
    359 	 * Write command and message to and
    360 	 * read status return code from daemon.
    361 	 */
    362 	if (!_daemon_write(fifos, msg)) {
    363 		stack;
    364 		dm_free(msg->data);
    365 		msg->data = 0;
    366 		return -EIO;
    367 	}
    368 
    369 	do {
    370 
    371 		if (msg->data)
    372 			dm_free(msg->data);
    373 		msg->data = 0;
    374 
    375 		if (!_daemon_read(fifos, msg)) {
    376 			stack;
    377 			return -EIO;
    378 		}
    379 	} while (!_check_message_id(msg));
    380 
    381 	_sequence_nr++;
    382 
    383 	return (int32_t) msg->cmd;
    384 }
    385 
    386 /*
    387  * start_daemon
    388  *
    389  * This function forks off a process (dmeventd) that will handle
    390  * the events.  I am currently test opening one of the fifos to
    391  * ensure that the daemon is running and listening...  I thought
    392  * this would be less expensive than fork/exec'ing every time.
    393  * Perhaps there is an even quicker/better way (no, checking the
    394  * lock file is _not_ a better way).
    395  *
    396  * Returns: 1 on success, 0 otherwise
    397  */
    398 static int _start_daemon(struct dm_event_fifos *fifos)
    399 {
    400 	int pid, ret = 0;
    401 	int status;
    402 	struct stat statbuf;
    403 
    404 	if (stat(fifos->client_path, &statbuf))
    405 		goto start_server;
    406 
    407 	if (!S_ISFIFO(statbuf.st_mode)) {
    408 		log_error("%s is not a fifo.", fifos->client_path);
    409 		return 0;
    410 	}
    411 
    412 	/* Anyone listening?  If not, errno will be ENXIO */
    413 	fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
    414 	if (fifos->client >= 0) {
    415 		/* server is running and listening */
    416 
    417 		close(fifos->client);
    418 		return 1;
    419 	} else if (errno != ENXIO) {
    420 		/* problem */
    421 
    422 		log_error("%s: Can't open client fifo %s: %s",
    423 			  __func__, fifos->client_path, strerror(errno));
    424 		stack;
    425 		return 0;
    426 	}
    427 
    428       start_server:
    429 	/* server is not running */
    430 
    431 	if (!strncmp(DMEVENTD_PATH, "/", 1) && stat(DMEVENTD_PATH, &statbuf)) {
    432 		log_error("Unable to find dmeventd.");
    433 		return_0;
    434 	}
    435 
    436 	pid = fork();
    437 
    438 	if (pid < 0)
    439 		log_error("Unable to fork.");
    440 
    441 	else if (!pid) {
    442 		execvp(DMEVENTD_PATH, NULL);
    443 		_exit(EXIT_FAILURE);
    444 	} else {
    445 		if (waitpid(pid, &status, 0) < 0)
    446 			log_error("Unable to start dmeventd: %s",
    447 				  strerror(errno));
    448 		else if (WEXITSTATUS(status))
    449 			log_error("Unable to start dmeventd.");
    450 		else
    451 			ret = 1;
    452 	}
    453 
    454 	return ret;
    455 }
    456 
    457 /* Initialize client. */
    458 static int _init_client(struct dm_event_fifos *fifos)
    459 {
    460 	/* FIXME? Is fifo the most suitable method? Why not share
    461 	   comms/daemon code with something else e.g. multipath? */
    462 
    463 	/* init fifos */
    464 	memset(fifos, 0, sizeof(*fifos));
    465 	fifos->client_path = DM_EVENT_FIFO_CLIENT;
    466 	fifos->server_path = DM_EVENT_FIFO_SERVER;
    467 
    468 	if (!_start_daemon(fifos)) {
    469 		stack;
    470 		return 0;
    471 	}
    472 
    473 	/* Open the fifo used to read from the daemon. */
    474 	if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
    475 		log_error("%s: open server fifo %s",
    476 			  __func__, fifos->server_path);
    477 		stack;
    478 		return 0;
    479 	}
    480 
    481 	/* Lock out anyone else trying to do communication with the daemon. */
    482 	if (flock(fifos->server, LOCK_EX) < 0) {
    483 		log_error("%s: flock %s", __func__, fifos->server_path);
    484 		close(fifos->server);
    485 		return 0;
    486 	}
    487 
    488 /*	if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/
    489 	if ((fifos->client = open(fifos->client_path, O_RDWR | O_NONBLOCK)) < 0) {
    490 		log_error("%s: Can't open client fifo %s: %s",
    491 			  __func__, fifos->client_path, strerror(errno));
    492 		close(fifos->server);
    493 		stack;
    494 		return 0;
    495 	}
    496 
    497 	return 1;
    498 }
    499 
    500 static void _dtr_client(struct dm_event_fifos *fifos)
    501 {
    502 	if (flock(fifos->server, LOCK_UN))
    503 		log_error("flock unlock %s", fifos->server_path);
    504 
    505 	close(fifos->client);
    506 	close(fifos->server);
    507 }
    508 
    509 /* Get uuid of a device */
    510 static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
    511 {
    512 	struct dm_task *dmt;
    513 	struct dm_info info;
    514 
    515 	if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
    516 		log_error("_get_device_info: dm_task creation for info failed");
    517 		return NULL;
    518 	}
    519 
    520 	if (dmevh->uuid)
    521 		dm_task_set_uuid(dmt, dmevh->uuid);
    522 	else if (dmevh->dev_name)
    523 		dm_task_set_name(dmt, dmevh->dev_name);
    524 	else if (dmevh->major && dmevh->minor) {
    525 		dm_task_set_major(dmt, dmevh->major);
    526 		dm_task_set_minor(dmt, dmevh->minor);
    527         }
    528 
    529 	/* FIXME Add name or uuid or devno to messages */
    530 	if (!dm_task_run(dmt)) {
    531 		log_error("_get_device_info: dm_task_run() failed");
    532 		goto failed;
    533 	}
    534 
    535 	if (!dm_task_get_info(dmt, &info)) {
    536 		log_error("_get_device_info: failed to get info for device");
    537 		goto failed;
    538 	}
    539 
    540 	if (!info.exists) {
    541 		log_error("_get_device_info: device not found");
    542 		goto failed;
    543 	}
    544 
    545 	return dmt;
    546 
    547 failed:
    548 	dm_task_destroy(dmt);
    549 	return NULL;
    550 }
    551 
    552 /* Handle the event (de)registration call and return negative error codes. */
    553 static int _do_event(int cmd, struct dm_event_daemon_message *msg,
    554 		     const char *dso_name, const char *dev_name,
    555 		     enum dm_event_mask evmask, uint32_t timeout)
    556 {
    557 	int ret;
    558 	struct dm_event_fifos fifos;
    559 
    560 	if (!_init_client(&fifos)) {
    561 		stack;
    562 		return -ESRCH;
    563 	}
    564 
    565 	ret = _daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, 0, 0, 0, 0);
    566 
    567 	if (msg->data)
    568 		dm_free(msg->data);
    569 	msg->data = 0;
    570 
    571 	if (!ret)
    572 		ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
    573 
    574 	/* what is the opposite of init? */
    575 	_dtr_client(&fifos);
    576 
    577 	return ret;
    578 }
    579 
    580 /* External library interface. */
    581 int dm_event_register_handler(const struct dm_event_handler *dmevh)
    582 {
    583 	int ret = 1, err;
    584 	const char *uuid;
    585 	struct dm_task *dmt;
    586 	struct dm_event_daemon_message msg = { 0, 0, NULL };
    587 
    588 	if (!(dmt = _get_device_info(dmevh))) {
    589 		stack;
    590 		return 0;
    591 	}
    592 
    593 	uuid = dm_task_get_uuid(dmt);
    594 
    595 	if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
    596 			     dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
    597 		log_error("%s: event registration failed: %s",
    598 			  dm_task_get_name(dmt),
    599 			  msg.data ? msg.data : strerror(-err));
    600 		ret = 0;
    601 	}
    602 
    603 	if (msg.data)
    604 		dm_free(msg.data);
    605 
    606 	dm_task_destroy(dmt);
    607 
    608 	return ret;
    609 }
    610 
    611 int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
    612 {
    613 	int ret = 1, err;
    614 	const char *uuid;
    615 	struct dm_task *dmt;
    616 	struct dm_event_daemon_message msg = { 0, 0, NULL };
    617 
    618 	if (!(dmt = _get_device_info(dmevh))) {
    619 		stack;
    620 		return 0;
    621 	}
    622 
    623 	uuid = dm_task_get_uuid(dmt);
    624 
    625 	if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
    626 			    dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
    627 		log_error("%s: event deregistration failed: %s",
    628 			  dm_task_get_name(dmt),
    629 			  msg.data ? msg.data : strerror(-err));
    630 		ret = 0;
    631 	}
    632 
    633 	if (msg.data)
    634 		dm_free(msg.data);
    635 
    636 	dm_task_destroy(dmt);
    637 
    638 	return ret;
    639 }
    640 
    641 /* Fetch a string off src and duplicate it into *dest. */
    642 /* FIXME: move to separate module to share with the daemon. */
    643 static char *_fetch_string(char **src, const int delimiter)
    644 {
    645 	char *p, *ret;
    646 
    647 	if ((p = strchr(*src, delimiter)))
    648 		*p = 0;
    649 
    650 	if ((ret = dm_strdup(*src)))
    651 		*src += strlen(ret) + 1;
    652 
    653 	if (p)
    654 		*p = delimiter;
    655 
    656 	return ret;
    657 }
    658 
    659 /* Parse a device message from the daemon. */
    660 static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
    661 			 char **uuid, enum dm_event_mask *evmask)
    662 {
    663 	char *id = NULL;
    664 	char *p = msg->data;
    665 
    666 	if ((id = _fetch_string(&p, ' ')) &&
    667 	    (*dso_name = _fetch_string(&p, ' ')) &&
    668 	    (*uuid = _fetch_string(&p, ' '))) {
    669 		*evmask = atoi(p);
    670 
    671 		dm_free(id);
    672 		return 0;
    673 	}
    674 
    675 	if (id)
    676 		dm_free(id);
    677 	return -ENOMEM;
    678 }
    679 
    680 /*
    681  * Returns 0 if handler found; error (-ENOMEM, -ENOENT) otherwise.
    682  */
    683 int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
    684 {
    685 	int ret = 0;
    686 	const char *uuid = NULL;
    687 	char *reply_dso = NULL, *reply_uuid = NULL;
    688 	enum dm_event_mask reply_mask = 0;
    689 	struct dm_task *dmt = NULL;
    690 	struct dm_event_daemon_message msg = { 0, 0, NULL };
    691 
    692 	if (!(dmt = _get_device_info(dmevh))) {
    693 		stack;
    694 		return 0;
    695 	}
    696 
    697 	uuid = dm_task_get_uuid(dmt);
    698 
    699 	if (!(ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
    700 			     DM_EVENT_CMD_GET_REGISTERED_DEVICE,
    701 			      &msg, dmevh->dso, uuid, dmevh->mask, 0))) {
    702 		/* FIXME this will probably horribly break if we get
    703 		   ill-formatted reply */
    704 		ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask);
    705 	} else {
    706 		ret = -ENOENT;
    707 		goto fail;
    708 	}
    709 
    710 	dm_task_destroy(dmt);
    711 	dmt = NULL;
    712 
    713 	if (msg.data) {
    714 		dm_free(msg.data);
    715 		msg.data = NULL;
    716 	}
    717 
    718 	_dm_event_handler_clear_dev_info(dmevh);
    719 	dmevh->uuid = dm_strdup(reply_uuid);
    720 	if (!dmevh->uuid) {
    721 		ret = -ENOMEM;
    722 		goto fail;
    723 	}
    724 
    725 	if (!(dmt = _get_device_info(dmevh))) {
    726 		ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */
    727 		goto fail;
    728 	}
    729 
    730 	dm_event_handler_set_dso(dmevh, reply_dso);
    731 	dm_event_handler_set_event_mask(dmevh, reply_mask);
    732 
    733 	if (reply_dso) {
    734 		dm_free(reply_dso);
    735 		reply_dso = NULL;
    736 	}
    737 
    738 	if (reply_uuid) {
    739 		dm_free(reply_uuid);
    740 		reply_uuid = NULL;
    741 	}
    742 
    743 	dmevh->dev_name = dm_strdup(dm_task_get_name(dmt));
    744 	if (!dmevh->dev_name) {
    745 		ret = -ENOMEM;
    746 		goto fail;
    747 	}
    748 
    749 	struct dm_info info;
    750 	if (!dm_task_get_info(dmt, &info)) {
    751 		ret = -1;
    752 		goto fail;
    753 	}
    754 
    755 	dmevh->major = info.major;
    756 	dmevh->minor = info.minor;
    757 
    758 	dm_task_destroy(dmt);
    759 
    760 	return ret;
    761 
    762  fail:
    763 	if (msg.data)
    764 		dm_free(msg.data);
    765 	if (reply_dso)
    766 		dm_free(reply_dso);
    767 	if (reply_uuid)
    768 		dm_free(reply_uuid);
    769 	_dm_event_handler_clear_dev_info(dmevh);
    770 	if (dmt)
    771 		dm_task_destroy(dmt);
    772 	return ret;
    773 }
    774 
    775 #if 0				/* left out for now */
    776 
    777 static char *_skip_string(char *src, const int delimiter)
    778 {
    779 	src = srtchr(src, delimiter);
    780 	if (src && *(src + 1))
    781 		return src + 1;
    782 	return NULL;
    783 }
    784 
    785 int dm_event_set_timeout(const char *device_path, uint32_t timeout)
    786 {
    787 	struct dm_event_daemon_message msg = { 0, 0, NULL };
    788 
    789 	if (!device_exists(device_path))
    790 		return -ENODEV;
    791 
    792 	return _do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
    793 			 NULL, device_path, 0, timeout);
    794 }
    795 
    796 int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
    797 {
    798 	int ret;
    799 	struct dm_event_daemon_message msg = { 0, 0, NULL };
    800 
    801 	if (!device_exists(device_path))
    802 		return -ENODEV;
    803 	if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
    804 			     0, 0))) {
    805 		char *p = _skip_string(msg.data, ' ');
    806 		if (!p) {
    807 			log_error("malformed reply from dmeventd '%s'\n",
    808 				  msg.data);
    809 			return -EIO;
    810 		}
    811 		*timeout = atoi(p);
    812 	}
    813 	if (msg.data)
    814 		dm_free(msg.data);
    815 	return ret;
    816 }
    817 #endif
    818