~ubuntu-branches/ubuntu/vivid/lvm2/vivid

« back to all changes in this revision

Viewing changes to .pc/missing-dmeventd.patch/daemons/dmeventd/libdevmapper-event.c

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2012-11-26 10:35:00 UTC
  • mfrom: (3.1.26 sid)
  • Revision ID: package-import@ubuntu.com-20121126103500-a1zw30282cu9kdev
Tags: 2.02.95-5ubuntu1
* Merge from Debian unstable, remaining changes (LP: #1082325):
  - debian/patches/avoid-dev-block.patch: Prefer any other device name over
    names in /dev/block/ since lvm.conf won't handle this.
  - debian/rules:
    - copy .po file to .pot file for Rosetta (Ubuntu specific).
  - debian/{dmsetup,lvm2}-udeb.install:
    - install initramfs and udev hooks in udebs (Debian bug 504341).
  - auto-start VGs as their PVs are discovered (Ubuntu specific):
    - add debian/tree/lvm2/lib/udev/rules.d/85-lvm2.rules: use watershed plus
      the sledgehammer of vgscan/vgchange to turn on VGs as they come online.
    - debian/tree/lvm2/usr/share/initramfs-tools/scripts/hooks/lvm2:
      - add 85-lvm2.rules to the list of udev rules to copy.
      - depend on udev.
    - debian/control:
      - add versioned Depend on watershed in lvm2 for udev rules.
      - add Depends on watershed-udeb in lvm2-udeb for udev rules.
      - add versioned Depend/Breaks on udev in dmsetup for udev rules.
      - add Depend on initramfs-tools in dmsetup so system is not potentially
        rendered unbootable by out-of-order dpkg configuration.
      - In libdevmapper-event1.02.1 add Breaks: dmeventd
        (<< 2.02.95-4ubuntu1) due to debian symbol rename
    - debian/rules:
      - do not install local-top scripts since Ubuntu mounts root using udev.
      - do not install init scripts for lvm2, since udev starts LVM.
    - debian/lvm2.postinst: handle missing lvm2 init script.
    - debian/tree/dmsetup/lib/udev/rules.d/60-persistent-storage-dm.rules:
      watch dm devices for changes with inotify
  - add mountroot failure hooks to help fix bad boots (Debian bug 468115):
    - debian/tree/lvm2/usr/share/initramfs-tools/scripts/init-premount/lvm2
  - remaining changes to upstream event manager packages (Debian bug 514706):
    - debian/rules:
      - enable dmeventd during configure.
    - debian/dmeventd.{8,manpages}: install dmeventd files.
  - rename debian/clvm.defaults to debian/clvm.default so it is installed
    correctly.
  - debian/control: add dmsetup-udeb to libdevmapper1.02.1-udeb recommends.
  - debian/rules: make sure dmsetup and lvm2 initramfs-tools scripts are
    executable.  When the Ubuntu-specific ones are added with a patch,
    they may lose their executable bit.
  - Add and install clvmd resource agent
  - Add dependency on libudev-dev to libdevmapper-dev so that the .pc file
    works.
  - debian/{clvmd.ra,clvm.init}:
    - create /run/lvm if it doesn't exist.
  - debian/clvm.init:
    - exit 3 if not running on status action.
  - Call dh_installman so that our dmeventd manpage actually gets installed
  - Install the missing fsadm manpage.
  - Complete libdevmapper-dev multiarch:
    - move .so symlinks and pkgconfig files to multiarched locations.
    - mark libdevmapper-dev M-A: same

* Dropped changes debian/lvm2.{preinst,postinst,postrm}, not needed in Raring:
  - Implement removal of obsolete /etc/init.d/lvm2 conffile, which
    should not have been re-introduced in Quantal.

Show diffs side-by-side

added added

removed removed

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