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