Sync usage with man page.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / daemons / dmeventd / libdevmapper-event.c
blobd3029119b893d0d33dc473def39eeefe91bf211c
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
6 * This file is part of the device-mapper userspace tools.
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.
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
17 #include "dmlib.h"
18 #include "libdevmapper-event.h"
19 //#include "libmultilog.h"
20 #include "dmeventd.h"
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 */
35 static int _sequence_nr = 0;
37 struct dm_event_handler {
38 char *dso;
40 char *dev_name;
42 char *uuid;
43 int major;
44 int minor;
45 uint32_t timeout;
47 enum dm_event_mask mask;
50 static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
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;
60 struct dm_event_handler *dm_event_handler_create(void)
62 struct dm_event_handler *dmevh = NULL;
64 if (!(dmevh = dm_malloc(sizeof(*dmevh))))
65 return NULL;
67 dmevh->dso = dmevh->dev_name = dmevh->uuid = NULL;
68 dmevh->major = dmevh->minor = 0;
69 dmevh->mask = 0;
70 dmevh->timeout = 0;
72 return dmevh;
75 void dm_event_handler_destroy(struct dm_event_handler *dmevh)
77 _dm_event_handler_clear_dev_info(dmevh);
78 if (dmevh->dso)
79 dm_free(dmevh->dso);
80 dm_free(dmevh);
83 int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
85 if (!path) /* noop */
86 return 0;
87 if (dmevh->dso)
88 dm_free(dmevh->dso);
90 dmevh->dso = dm_strdup(path);
91 if (!dmevh->dso)
92 return -ENOMEM;
94 return 0;
97 int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name)
99 if (!dev_name)
100 return 0;
102 _dm_event_handler_clear_dev_info(dmevh);
104 dmevh->dev_name = dm_strdup(dev_name);
105 if (!dmevh->dev_name)
106 return -ENOMEM;
107 return 0;
110 int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
112 if (!uuid)
113 return 0;
115 _dm_event_handler_clear_dev_info(dmevh);
117 dmevh->uuid = dm_strdup(uuid);
118 if (!dmevh->dev_name)
119 return -ENOMEM;
120 return 0;
123 void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major)
125 int minor = dmevh->minor;
127 _dm_event_handler_clear_dev_info(dmevh);
129 dmevh->major = major;
130 dmevh->minor = minor;
133 void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor)
135 int major = dmevh->major;
137 _dm_event_handler_clear_dev_info(dmevh);
139 dmevh->major = major;
140 dmevh->minor = minor;
143 void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
144 enum dm_event_mask evmask)
146 dmevh->mask = evmask;
149 void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout)
151 dmevh->timeout = timeout;
154 const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh)
156 return dmevh->dso;
159 const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh)
161 return dmevh->dev_name;
164 const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh)
166 return dmevh->uuid;
169 int dm_event_handler_get_major(const struct dm_event_handler *dmevh)
171 return dmevh->major;
174 int dm_event_handler_get_minor(const struct dm_event_handler *dmevh)
176 return dmevh->minor;
179 int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh)
181 return dmevh->timeout;
184 enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh)
186 return dmevh->mask;
189 static int _check_message_id(struct dm_event_daemon_message *msg)
191 int pid, seq_nr;
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;
201 return 1;
205 * daemon_read
206 * @fifos
207 * @msg
209 * Read message from daemon.
211 * Returns: 0 on failure, 1 on success
213 static int _daemon_read(struct dm_event_fifos *fifos,
214 struct dm_event_daemon_message *msg)
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;
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;
237 if (ret < 1) {
238 log_error("Unable to read from event server.");
239 return 0;
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;
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;
263 if (bytes != size) {
264 if (msg->data)
265 dm_free(msg->data);
266 msg->data = NULL;
269 return bytes == size;
272 /* Write message to daemon. */
273 static int _daemon_write(struct dm_event_fifos *fifos,
274 struct dm_event_daemon_message *msg)
276 unsigned bytes = 0;
277 int ret = 0;
278 fd_set fds;
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 };
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);
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;
299 if (ret == 0)
300 break;
301 read(fifos->server, drainbuf, 127);
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;
314 } while (ret < 1);
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;
327 bytes += ret;
330 return bytes == size;
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)
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));
345 * Set command and pack the arguments
346 * into ASCII message string.
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;
356 msg->size = msg_size;
359 * Write command and message to and
360 * read status return code from daemon.
362 if (!_daemon_write(fifos, msg)) {
363 stack;
364 dm_free(msg->data);
365 msg->data = 0;
366 return -EIO;
369 do {
371 if (msg->data)
372 dm_free(msg->data);
373 msg->data = 0;
375 if (!_daemon_read(fifos, msg)) {
376 stack;
377 return -EIO;
379 } while (!_check_message_id(msg));
381 _sequence_nr++;
383 return (int32_t) msg->cmd;
387 * start_daemon
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).
396 * Returns: 1 on success, 0 otherwise
398 static int _start_daemon(struct dm_event_fifos *fifos)
400 int pid, ret = 0;
401 int status;
402 struct stat statbuf;
404 if (stat(fifos->client_path, &statbuf))
405 goto start_server;
407 if (!S_ISFIFO(statbuf.st_mode)) {
408 log_error("%s is not a fifo.", fifos->client_path);
409 return 0;
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 */
417 close(fifos->client);
418 return 1;
419 } else if (errno != ENXIO) {
420 /* problem */
422 log_error("%s: Can't open client fifo %s: %s",
423 __func__, fifos->client_path, strerror(errno));
424 stack;
425 return 0;
428 start_server:
429 /* server is not running */
431 if (!strncmp(DMEVENTD_PATH, "/", 1) && stat(DMEVENTD_PATH, &statbuf)) {
432 log_error("Unable to find dmeventd.");
433 return_0;
436 pid = fork();
438 if (pid < 0)
439 log_error("Unable to fork.");
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;
454 return ret;
457 /* Initialize client. */
458 static int _init_client(struct dm_event_fifos *fifos)
460 /* FIXME? Is fifo the most suitable method? Why not share
461 comms/daemon code with something else e.g. multipath? */
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;
468 if (!_start_daemon(fifos)) {
469 stack;
470 return 0;
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;
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;
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;
497 return 1;
500 static void _dtr_client(struct dm_event_fifos *fifos)
502 if (flock(fifos->server, LOCK_UN))
503 log_error("flock unlock %s", fifos->server_path);
505 close(fifos->client);
506 close(fifos->server);
509 /* Get uuid of a device */
510 static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
512 struct dm_task *dmt;
513 struct dm_info info;
515 if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
516 log_error("_get_device_info: dm_task creation for info failed");
517 return NULL;
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);
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;
535 if (!dm_task_get_info(dmt, &info)) {
536 log_error("_get_device_info: failed to get info for device");
537 goto failed;
540 if (!info.exists) {
541 log_error("_get_device_info: device not found");
542 goto failed;
545 return dmt;
547 failed:
548 dm_task_destroy(dmt);
549 return NULL;
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)
557 int ret;
558 struct dm_event_fifos fifos;
560 if (!_init_client(&fifos)) {
561 stack;
562 return -ESRCH;
565 ret = _daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, 0, 0, 0, 0);
567 if (msg->data)
568 dm_free(msg->data);
569 msg->data = 0;
571 if (!ret)
572 ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
574 /* what is the opposite of init? */
575 _dtr_client(&fifos);
577 return ret;
580 /* External library interface. */
581 int dm_event_register_handler(const struct dm_event_handler *dmevh)
583 int ret = 1, err;
584 const char *uuid;
585 struct dm_task *dmt;
586 struct dm_event_daemon_message msg = { 0, 0, NULL };
588 if (!(dmt = _get_device_info(dmevh))) {
589 stack;
590 return 0;
593 uuid = dm_task_get_uuid(dmt);
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;
603 if (msg.data)
604 dm_free(msg.data);
606 dm_task_destroy(dmt);
608 return ret;
611 int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
613 int ret = 1, err;
614 const char *uuid;
615 struct dm_task *dmt;
616 struct dm_event_daemon_message msg = { 0, 0, NULL };
618 if (!(dmt = _get_device_info(dmevh))) {
619 stack;
620 return 0;
623 uuid = dm_task_get_uuid(dmt);
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;
633 if (msg.data)
634 dm_free(msg.data);
636 dm_task_destroy(dmt);
638 return ret;
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)
645 char *p, *ret;
647 if ((p = strchr(*src, delimiter)))
648 *p = 0;
650 if ((ret = dm_strdup(*src)))
651 *src += strlen(ret) + 1;
653 if (p)
654 *p = delimiter;
656 return ret;
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)
663 char *id = NULL;
664 char *p = msg->data;
666 if ((id = _fetch_string(&p, ' ')) &&
667 (*dso_name = _fetch_string(&p, ' ')) &&
668 (*uuid = _fetch_string(&p, ' '))) {
669 *evmask = atoi(p);
671 dm_free(id);
672 return 0;
675 if (id)
676 dm_free(id);
677 return -ENOMEM;
681 * Returns 0 if handler found; error (-ENOMEM, -ENOENT) otherwise.
683 int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
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 };
692 if (!(dmt = _get_device_info(dmevh))) {
693 stack;
694 return 0;
697 uuid = dm_task_get_uuid(dmt);
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;
710 dm_task_destroy(dmt);
711 dmt = NULL;
713 if (msg.data) {
714 dm_free(msg.data);
715 msg.data = NULL;
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;
725 if (!(dmt = _get_device_info(dmevh))) {
726 ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */
727 goto fail;
730 dm_event_handler_set_dso(dmevh, reply_dso);
731 dm_event_handler_set_event_mask(dmevh, reply_mask);
733 if (reply_dso) {
734 dm_free(reply_dso);
735 reply_dso = NULL;
738 if (reply_uuid) {
739 dm_free(reply_uuid);
740 reply_uuid = NULL;
743 dmevh->dev_name = dm_strdup(dm_task_get_name(dmt));
744 if (!dmevh->dev_name) {
745 ret = -ENOMEM;
746 goto fail;
749 struct dm_info info;
750 if (!dm_task_get_info(dmt, &info)) {
751 ret = -1;
752 goto fail;
755 dmevh->major = info.major;
756 dmevh->minor = info.minor;
758 dm_task_destroy(dmt);
760 return ret;
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;
775 #if 0 /* left out for now */
777 static char *_skip_string(char *src, const int delimiter)
779 src = srtchr(src, delimiter);
780 if (src && *(src + 1))
781 return src + 1;
782 return NULL;
785 int dm_event_set_timeout(const char *device_path, uint32_t timeout)
787 struct dm_event_daemon_message msg = { 0, 0, NULL };
789 if (!device_exists(device_path))
790 return -ENODEV;
792 return _do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
793 NULL, device_path, 0, timeout);
796 int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
798 int ret;
799 struct dm_event_daemon_message msg = { 0, 0, NULL };
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;
811 *timeout = atoi(p);
813 if (msg.data)
814 dm_free(msg.data);
815 return ret;
817 #endif