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
_dm_event_handler_clear_dev_info(struct dm_event_handler * dmevh)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
dm_event_handler_create(void)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
dm_event_handler_destroy(struct dm_event_handler * dmevh)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
dm_event_handler_set_dso(struct dm_event_handler * dmevh,const char * path)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
dm_event_handler_set_dev_name(struct dm_event_handler * dmevh,const char * dev_name)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
dm_event_handler_set_uuid(struct dm_event_handler * dmevh,const char * uuid)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
dm_event_handler_set_major(struct dm_event_handler * dmevh,int major)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
dm_event_handler_set_minor(struct dm_event_handler * dmevh,int minor)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
dm_event_handler_set_event_mask(struct dm_event_handler * dmevh,enum dm_event_mask evmask)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
dm_event_handler_set_timeout(struct dm_event_handler * dmevh,int timeout)149 void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout)
150 {
151 dmevh->timeout = timeout;
152 }
153
dm_event_handler_get_dso(const struct dm_event_handler * dmevh)154 const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh)
155 {
156 return dmevh->dso;
157 }
158
dm_event_handler_get_dev_name(const struct dm_event_handler * dmevh)159 const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh)
160 {
161 return dmevh->dev_name;
162 }
163
dm_event_handler_get_uuid(const struct dm_event_handler * dmevh)164 const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh)
165 {
166 return dmevh->uuid;
167 }
168
dm_event_handler_get_major(const struct dm_event_handler * dmevh)169 int dm_event_handler_get_major(const struct dm_event_handler *dmevh)
170 {
171 return dmevh->major;
172 }
173
dm_event_handler_get_minor(const struct dm_event_handler * dmevh)174 int dm_event_handler_get_minor(const struct dm_event_handler *dmevh)
175 {
176 return dmevh->minor;
177 }
178
dm_event_handler_get_timeout(const struct dm_event_handler * dmevh)179 int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh)
180 {
181 return dmevh->timeout;
182 }
183
dm_event_handler_get_event_mask(const struct dm_event_handler * dmevh)184 enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh)
185 {
186 return dmevh->mask;
187 }
188
_check_message_id(struct dm_event_daemon_message * msg)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 */
_daemon_read(struct dm_event_fifos * fifos,struct dm_event_daemon_message * msg)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. */
_daemon_write(struct dm_event_fifos * fifos,struct dm_event_daemon_message * msg)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
_daemon_talk(struct dm_event_fifos * fifos,struct dm_event_daemon_message * msg,int cmd,const char * dso_name,const char * dev_name,enum dm_event_mask evmask,uint32_t timeout)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 */
_start_daemon(struct dm_event_fifos * fifos)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. */
_init_client(struct dm_event_fifos * fifos)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
_dtr_client(struct dm_event_fifos * fifos)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 */
_get_device_info(const struct dm_event_handler * dmevh)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. */
_do_event(int cmd,struct dm_event_daemon_message * msg,const char * dso_name,const char * dev_name,enum dm_event_mask evmask,uint32_t timeout)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. */
dm_event_register_handler(const struct dm_event_handler * dmevh)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
dm_event_unregister_handler(const struct dm_event_handler * dmevh)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. */
_fetch_string(char ** src,const int delimiter)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. */
_parse_message(struct dm_event_daemon_message * msg,char ** dso_name,char ** uuid,enum dm_event_mask * evmask)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 */
dm_event_get_registered_device(struct dm_event_handler * dmevh,int next)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