chiark / gitweb /
ac7ba0c86a280299d4b8d0f3039081f8bd3d576a
[elogind.git] / extras / multipath / libdevmapper / ioctl / libdevmapper.c
1 /*
2  * Copyright (C) 2001 Sistina Software (UK) Limited.
3  *
4  * This file is released under the LGPL.
5  */
6
7 #include "libdm-targets.h"
8 #include "libdm-common.h"
9
10 #ifdef DM_COMPAT
11 #  include "libdm-compat.h"
12 #endif
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <dirent.h>
20 #include <errno.h>
21 #include <sys/stat.h>
22 #include <sys/ioctl.h>
23 #include <limits.h>
24
25 #ifdef linux
26 #  include <linux/limits.h>
27 #  include <linux/kdev_t.h>
28 #  include <linux/dm-ioctl.h>
29 #else
30 #  define MAJOR(x) major((x))
31 #  define MINOR(x) minor((x))
32 #  define MKDEV(x,y) makedev((x),(y))
33 #endif
34
35 /*
36  * Ensure build compatibility.  
37  * The hard-coded versions here are the highest present 
38  * in the _cmd_data arrays.
39  */
40
41 #if !((DM_VERSION_MAJOR == 1 && DM_VERSION_MINOR >= 0) || \
42       (DM_VERSION_MAJOR == 4 && DM_VERSION_MINOR >= 0))
43 #error The version of dm-ioctl.h included is incompatible.
44 #endif
45
46 /* dm major version no for running kernel */
47 static int _dm_version = DM_VERSION_MAJOR;
48 static int _log_suppress = 0;
49
50 static int _control_fd = -1;
51 static int _version_checked = 0;
52 static int _version_ok = 1;
53
54 /*
55  * Support both old and new major numbers to ease the transition.
56  * Clumsy, but only temporary.
57  */
58 #if DM_VERSION_MAJOR == 4 && defined(DM_COMPAT)
59 const int _dm_compat = 1;
60 #else
61 const int _dm_compat = 0;
62 #endif
63
64
65 /* *INDENT-OFF* */
66 static struct cmd_data _cmd_data_v4[] = {
67         {"create",      DM_DEV_CREATE,          {4, 0, 0}},
68         {"reload",      DM_TABLE_LOAD,          {4, 0, 0}},
69         {"remove",      DM_DEV_REMOVE,          {4, 0, 0}},
70         {"remove_all",  DM_REMOVE_ALL,          {4, 0, 0}},
71         {"suspend",     DM_DEV_SUSPEND,         {4, 0, 0}},
72         {"resume",      DM_DEV_SUSPEND,         {4, 0, 0}},
73         {"info",        DM_DEV_STATUS,          {4, 0, 0}},
74         {"deps",        DM_TABLE_DEPS,          {4, 0, 0}},
75         {"rename",      DM_DEV_RENAME,          {4, 0, 0}},
76         {"version",     DM_VERSION,             {4, 0, 0}},
77         {"status",      DM_TABLE_STATUS,        {4, 0, 0}},
78         {"table",       DM_TABLE_STATUS,        {4, 0, 0}},
79         {"waitevent",   DM_DEV_WAIT,            {4, 0, 0}},
80         {"names",       DM_LIST_DEVICES,        {4, 0, 0}},
81         {"clear",       DM_TABLE_CLEAR,         {4, 0, 0}},
82         {"mknodes",     DM_DEV_STATUS,          {4, 0, 0}},
83 };
84 /* *INDENT-ON* */
85
86 #define ALIGNMENT_V1 sizeof(int)
87 #define ALIGNMENT 8
88
89 /* FIXME Rejig library to record & use errno instead */
90 #ifndef DM_EXISTS_FLAG
91 #  define DM_EXISTS_FLAG 0x00000004
92 #endif
93
94 static void *_align(void *ptr, unsigned int a)
95 {
96         register unsigned long agn = --a;
97
98         return (void *) (((unsigned long) ptr + agn) & ~agn);
99 }
100
101 static int _open_control(void)
102 {
103         char control[PATH_MAX];
104
105         if (_control_fd != -1)
106                 return 1;
107
108         snprintf(control, sizeof(control), "%s/control", dm_dir());
109
110         if ((_control_fd = open(control, O_RDWR)) < 0) {
111                 log_error("%s: open failed: %s", control, strerror(errno));
112                 log_error("Is device-mapper driver missing from kernel?");
113                 return 0;
114         }
115
116         return 1;
117 }
118
119 void dm_task_destroy(struct dm_task *dmt)
120 {
121         struct target *t, *n;
122
123         for (t = dmt->head; t; t = n) {
124                 n = t->next;
125                 free(t->params);
126                 free(t->type);
127                 free(t);
128         }
129
130         if (dmt->dev_name)
131                 free(dmt->dev_name);
132
133         if (dmt->newname)
134                 free(dmt->newname);
135
136         if (dmt->dmi.v4)
137                 free(dmt->dmi.v4);
138
139         if (dmt->uuid)
140                 free(dmt->uuid);
141
142         free(dmt);
143 }
144
145 /*
146  * Protocol Version 1 compatibility functions.
147  */
148
149 #ifdef DM_COMPAT
150
151 static int _dm_task_get_driver_version_v1(struct dm_task *dmt, char *version,
152                                           size_t size)
153 {
154         unsigned int *v;
155
156         if (!dmt->dmi.v1) {
157                 version[0] = '\0';
158                 return 0;
159         }
160
161         v = dmt->dmi.v1->version;
162         snprintf(version, size, "%u.%u.%u", v[0], v[1], v[2]);
163         return 1;
164 }
165
166 /* Unmarshall the target info returned from a status call */
167 static int _unmarshal_status_v1(struct dm_task *dmt, struct dm_ioctl_v1 *dmi)
168 {
169         char *outbuf = (char *) dmi + dmi->data_start;
170         char *outptr = outbuf;
171         int32_t i;
172         struct dm_target_spec_v1 *spec;
173
174         for (i = 0; i < dmi->target_count; i++) {
175                 spec = (struct dm_target_spec_v1 *) outptr;
176
177                 if (!dm_task_add_target(dmt, spec->sector_start,
178                                         (uint64_t) spec->length,
179                                         spec->target_type,
180                                         outptr + sizeof(*spec)))
181                         return 0;
182
183                 outptr = outbuf + spec->next;
184         }
185
186         return 1;
187 }
188
189 static int _dm_format_dev_v1(char *buf, int bufsize, uint32_t dev_major,
190                              uint32_t dev_minor)
191 {
192         int r;
193
194         if (bufsize < 8)
195                 return 0;
196
197         r = snprintf(buf, bufsize, "%03x:%03x", dev_major, dev_minor);
198         if (r < 0 || r > bufsize - 1)
199                 return 0;
200
201         return 1;
202 }
203
204 static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info)
205 {
206         if (!dmt->dmi.v1)
207                 return 0;
208
209         memset(info, 0, sizeof(*info));
210
211         info->exists = dmt->dmi.v1->flags & DM_EXISTS_FLAG ? 1 : 0;
212         if (!info->exists)
213                 return 1;
214
215         info->suspended = dmt->dmi.v1->flags & DM_SUSPEND_FLAG ? 1 : 0;
216         info->read_only = dmt->dmi.v1->flags & DM_READONLY_FLAG ? 1 : 0;
217         info->target_count = dmt->dmi.v1->target_count;
218         info->open_count = dmt->dmi.v1->open_count;
219         info->event_nr = 0;
220         info->major = MAJOR(dmt->dmi.v1->dev);
221         info->minor = MINOR(dmt->dmi.v1->dev);
222         info->live_table = 1;
223         info->inactive_table = 0;
224
225         return 1;
226 }
227
228 static const char *_dm_task_get_name_v1(struct dm_task *dmt)
229 {
230         return (dmt->dmi.v1->name);
231 }
232
233 static const char *_dm_task_get_uuid_v1(struct dm_task *dmt)
234 {
235         return (dmt->dmi.v1->uuid);
236 }
237
238 static struct dm_deps *_dm_task_get_deps_v1(struct dm_task *dmt)
239 {
240         log_error("deps version 1 no longer supported by libdevmapper");
241         return NULL;
242 }
243
244 static struct dm_names *_dm_task_get_names_v1(struct dm_task *dmt)
245 {
246         return (struct dm_names *) (((void *) dmt->dmi.v1) +
247                                     dmt->dmi.v1->data_start);
248 }
249
250 static void *_add_target_v1(struct target *t, void *out, void *end)
251 {
252         void *out_sp = out;
253         struct dm_target_spec_v1 sp;
254         size_t sp_size = sizeof(struct dm_target_spec_v1);
255         int len;
256         const char no_space[] = "Ran out of memory building ioctl parameter";
257
258         out += sp_size;
259         if (out >= end) {
260                 log_error(no_space);
261                 return NULL;
262         }
263
264         sp.status = 0;
265         sp.sector_start = t->start;
266         sp.length = t->length;
267         strncpy(sp.target_type, t->type, sizeof(sp.target_type));
268
269         len = strlen(t->params);
270
271         if ((out + len + 1) >= end) {
272                 log_error(no_space);
273
274                 log_error("t->params= '%s'", t->params);
275                 return NULL;
276         }
277         strcpy((char *) out, t->params);
278         out += len + 1;
279
280         /* align next block */
281         out = _align(out, ALIGNMENT_V1);
282
283         sp.next = out - out_sp;
284
285         memcpy(out_sp, &sp, sp_size);
286
287         return out;
288 }
289
290 static struct dm_ioctl_v1 *_flatten_v1(struct dm_task *dmt)
291 {
292         const size_t min_size = 16 * 1024;
293         const int (*version)[3];
294
295         struct dm_ioctl_v1 *dmi;
296         struct target *t;
297         size_t len = sizeof(struct dm_ioctl_v1);
298         void *b, *e;
299         int count = 0;
300
301         for (t = dmt->head; t; t = t->next) {
302                 len += sizeof(struct dm_target_spec_v1);
303                 len += strlen(t->params) + 1 + ALIGNMENT_V1;
304                 count++;
305         }
306
307         if (count && dmt->newname) {
308                 log_error("targets and newname are incompatible");
309                 return NULL;
310         }
311
312         if (dmt->newname)
313                 len += strlen(dmt->newname) + 1;
314
315         /*
316          * Give len a minimum size so that we have space to store
317          * dependencies or status information.
318          */
319         if (len < min_size)
320                 len = min_size;
321
322         if (!(dmi = malloc(len)))
323                 return NULL;
324
325         memset(dmi, 0, len);
326
327         version = &_cmd_data_v1[dmt->type].version;
328
329         dmi->version[0] = (*version)[0];
330         dmi->version[1] = (*version)[1];
331         dmi->version[2] = (*version)[2];
332
333         dmi->data_size = len;
334         dmi->data_start = sizeof(struct dm_ioctl_v1);
335
336         if (dmt->dev_name)
337                 strncpy(dmi->name, dmt->dev_name, sizeof(dmi->name));
338
339         if (dmt->type == DM_DEVICE_SUSPEND)
340                 dmi->flags |= DM_SUSPEND_FLAG;
341         if (dmt->read_only)
342                 dmi->flags |= DM_READONLY_FLAG;
343
344         if (dmt->minor >= 0) {
345                 if (dmt->major <= 0) {
346                         log_error("Missing major number for persistent device");
347                         return NULL;
348                 }
349                 dmi->flags |= DM_PERSISTENT_DEV_FLAG;
350                 dmi->dev = MKDEV(dmt->major, dmt->minor);
351         }
352
353         if (dmt->uuid)
354                 strncpy(dmi->uuid, dmt->uuid, sizeof(dmi->uuid));
355
356         dmi->target_count = count;
357
358         b = (void *) (dmi + 1);
359         e = (void *) ((char *) dmi + len);
360
361         for (t = dmt->head; t; t = t->next)
362                 if (!(b = _add_target_v1(t, b, e)))
363                         goto bad;
364
365         if (dmt->newname)
366                 strcpy(b, dmt->newname);
367
368         return dmi;
369
370       bad:
371         free(dmi);
372         return NULL;
373 }
374
375 static int _dm_names_v1(struct dm_ioctl_v1 *dmi)
376 {
377         const char *dev_dir = dm_dir();
378         int r = 1, len;
379         const char *name;
380         struct dirent *dirent;
381         DIR *d;
382         struct dm_names *names, *old_names = NULL;
383         void *end = (void *) dmi + dmi->data_size;
384         struct stat buf;
385         char path[PATH_MAX];
386
387         if (!(d = opendir(dev_dir))) {
388                 log_error("%s: opendir failed: %s", dev_dir, strerror(errno));
389                 return 0;
390         }
391
392         names = (struct dm_names *) ((void *) dmi + dmi->data_start);
393
394         names->dev = 0;         /* Flags no data */
395
396         while ((dirent = readdir(d))) {
397                 name = dirent->d_name;
398
399                 if (name[0] == '.' || !strcmp(name, "control"))
400                         continue;
401
402                 if (old_names)
403                         old_names->next = (uint32_t) ((void *) names -
404                                                       (void *) old_names);
405                 snprintf(path, sizeof(path), "%s/%s", dev_dir, name);
406                 if (stat(path, &buf)) {
407                         log_error("%s: stat failed: %s", path, strerror(errno));
408                         continue;
409                 }
410                 if (!S_ISBLK(buf.st_mode))
411                         continue;
412                 names->dev = (uint64_t) buf.st_rdev;
413                 names->next = 0;
414                 len = strlen(name);
415                 if (((void *) (names + 1) + len + 1) >= end) {
416                         log_error("Insufficient buffer space for device list");
417                         r = 0;
418                         break;
419                 }
420
421                 strcpy(names->name, name);
422
423                 old_names = names;
424                 names = _align((void *) ++names + len + 1, ALIGNMENT);
425         }
426
427         if (closedir(d))
428                 log_error("%s: closedir failed: %s", dev_dir, strerror(errno));
429
430         return r;
431 }
432
433 static int _dm_task_run_v1(struct dm_task *dmt)
434 {
435         struct dm_ioctl_v1 *dmi;
436         unsigned int command;
437
438         dmi = _flatten_v1(dmt);
439         if (!dmi) {
440                 log_error("Couldn't create ioctl argument");
441                 return 0;
442         }
443
444         if (!_open_control())
445                 return 0;
446
447         if ((unsigned) dmt->type >=
448             (sizeof(_cmd_data_v1) / sizeof(*_cmd_data_v1))) {
449                 log_error("Internal error: unknown device-mapper task %d",
450                           dmt->type);
451                 goto bad;
452         }
453
454         command = _cmd_data_v1[dmt->type].cmd;
455
456         if (dmt->type == DM_DEVICE_TABLE)
457                 dmi->flags |= DM_STATUS_TABLE_FLAG;
458
459         log_debug("dm %s %s %s %s", _cmd_data_v1[dmt->type].name, dmi->name,
460                   dmi->uuid, dmt->newname ? dmt->newname : "");
461         if (dmt->type == DM_DEVICE_LIST) {
462                 if (!_dm_names_v1(dmi))
463                         goto bad;
464         } else if (ioctl(_control_fd, command, dmi) < 0) {
465                 if (_log_suppress)
466                         log_verbose("device-mapper ioctl cmd %d failed: %s",
467                                     _IOC_NR(command), strerror(errno));
468                 else
469                         log_error("device-mapper ioctl cmd %d failed: %s",
470                                   _IOC_NR(command), strerror(errno));
471                 goto bad;
472         }
473
474         switch (dmt->type) {
475         case DM_DEVICE_CREATE:
476                 add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev));
477                 break;
478
479         case DM_DEVICE_REMOVE:
480                 rm_dev_node(dmt->dev_name);
481                 break;
482
483         case DM_DEVICE_RENAME:
484                 rename_dev_node(dmt->dev_name, dmt->newname);
485                 break;
486
487         case DM_DEVICE_MKNODES:
488                 if (dmi->flags & DM_EXISTS_FLAG)
489                         add_dev_node(dmt->dev_name, MAJOR(dmi->dev),
490                                      MINOR(dmi->dev));
491                 else
492                         rm_dev_node(dmt->dev_name);
493                 break;
494
495         case DM_DEVICE_STATUS:
496         case DM_DEVICE_TABLE:
497                 if (!_unmarshal_status_v1(dmt, dmi))
498                         goto bad;
499                 break;
500
501         case DM_DEVICE_SUSPEND:
502         case DM_DEVICE_RESUME:
503                 dmt->type = DM_DEVICE_INFO;
504                 if (!dm_task_run(dmt))
505                         goto bad;
506                 free(dmi);      /* We'll use what info returned */
507                 return 1;
508         }
509
510         dmt->dmi.v1 = dmi;
511         return 1;
512
513       bad:
514         free(dmi);
515         return 0;
516 }
517
518 #endif
519
520 /*
521  * Protocol Version 4 functions.
522  */
523
524 int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
525 {
526         unsigned int *v;
527
528 #ifdef DM_COMPAT
529         if (_dm_version == 1)
530                 return _dm_task_get_driver_version_v1(dmt, version, size);
531 #endif
532
533         if (!dmt->dmi.v4) {
534                 version[0] = '\0';
535                 return 0;
536         }
537
538         v = dmt->dmi.v4->version;
539         snprintf(version, size, "%u.%u.%u", v[0], v[1], v[2]);
540         return 1;
541 }
542
543 static int _check_version(char *version, size_t size, int log_suppress)
544 {
545         struct dm_task *task;
546         int r;
547
548         if (!(task = dm_task_create(DM_DEVICE_VERSION))) {
549                 log_error("Failed to get device-mapper version");
550                 version[0] = '\0';
551                 return 0;
552         }
553
554         if (log_suppress)
555                 _log_suppress = 1;
556
557         r = dm_task_run(task);
558         dm_task_get_driver_version(task, version, size);
559         dm_task_destroy(task);
560         _log_suppress = 0;
561
562         return r;
563 }
564
565 /*
566  * Find out device-mapper's major version number the first time 
567  * this is called and whether or not we support it.
568  */
569 int dm_check_version(void)
570 {
571         char libversion[64], dmversion[64];
572         const char *compat = "";
573
574         if (_version_checked)
575                 return _version_ok;
576
577         _version_checked = 1;
578
579         if (_check_version(dmversion, sizeof(dmversion), _dm_compat))
580                 return 1;
581
582         if (!_dm_compat)
583                 goto bad;
584
585         log_verbose("device-mapper ioctl protocol version %d failed. "
586                     "Trying protocol version 1.", _dm_version);
587         _dm_version = 1;
588         if (_check_version(dmversion, sizeof(dmversion), 0)) {
589                 log_verbose("Using device-mapper ioctl protocol version 1");
590                 return 1;
591         }
592
593         compat = "(compat)";
594
595         dm_get_library_version(libversion, sizeof(libversion));
596
597         log_error("Incompatible libdevmapper %s%s and kernel driver %s",
598                   libversion, compat, dmversion);
599
600       bad:
601         _version_ok = 0;
602         return 0;
603 }
604
605 void *dm_get_next_target(struct dm_task *dmt, void *next,
606                          uint64_t *start, uint64_t *length,
607                          char **target_type, char **params)
608 {
609         struct target *t = (struct target *) next;
610
611         if (!t)
612                 t = dmt->head;
613
614         if (!t)
615                 return NULL;
616
617         *start = t->start;
618         *length = t->length;
619         *target_type = t->type;
620         *params = t->params;
621
622         return t->next;
623 }
624
625 /* Unmarshall the target info returned from a status call */
626 static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi)
627 {
628         char *outbuf = (char *) dmi + dmi->data_start;
629         char *outptr = outbuf;
630         uint32_t i;
631         struct dm_target_spec *spec;
632
633         for (i = 0; i < dmi->target_count; i++) {
634                 spec = (struct dm_target_spec *) outptr;
635                 if (!dm_task_add_target(dmt, spec->sector_start,
636                                         spec->length,
637                                         spec->target_type,
638                                         outptr + sizeof(*spec)))
639                         return 0;
640
641                 outptr = outbuf + spec->next;
642         }
643
644         return 1;
645 }
646
647 int dm_format_dev(char *buf, int bufsize, uint32_t dev_major,
648                   uint32_t dev_minor)
649 {
650         int r;
651
652 #ifdef DM_COMPAT
653         if (_dm_version == 1)
654                 return _dm_format_dev_v1(buf, bufsize, dev_major, dev_minor);
655 #endif
656
657         if (bufsize < 8)
658                 return 0;
659
660         r = snprintf(buf, bufsize, "%03u:%03u", dev_major, dev_minor);
661         if (r < 0 || r > bufsize - 1)
662                 return 0;
663
664         return 1;
665 }
666
667 int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
668 {
669 #ifdef DM_COMPAT
670         if (_dm_version == 1)
671                 return _dm_task_get_info_v1(dmt, info);
672 #endif
673
674         if (!dmt->dmi.v4)
675                 return 0;
676
677         memset(info, 0, sizeof(*info));
678
679         info->exists = dmt->dmi.v4->flags & DM_EXISTS_FLAG ? 1 : 0;
680         if (!info->exists)
681                 return 1;
682
683         info->suspended = dmt->dmi.v4->flags & DM_SUSPEND_FLAG ? 1 : 0;
684         info->read_only = dmt->dmi.v4->flags & DM_READONLY_FLAG ? 1 : 0;
685         info->live_table = dmt->dmi.v4->flags & DM_ACTIVE_PRESENT_FLAG ? 1 : 0;
686         info->inactive_table = dmt->dmi.v4->flags & DM_INACTIVE_PRESENT_FLAG ?
687             1 : 0;
688         info->target_count = dmt->dmi.v4->target_count;
689         info->open_count = dmt->dmi.v4->open_count;
690         info->event_nr = dmt->dmi.v4->event_nr;
691         info->major = MAJOR(dmt->dmi.v4->dev);
692         info->minor = MINOR(dmt->dmi.v4->dev);
693
694         return 1;
695 }
696
697 const char *dm_task_get_name(struct dm_task *dmt)
698 {
699 #ifdef DM_COMPAT
700         if (_dm_version == 1)
701                 return _dm_task_get_name_v1(dmt);
702 #endif
703
704         return (dmt->dmi.v4->name);
705 }
706
707 const char *dm_task_get_uuid(struct dm_task *dmt)
708 {
709 #ifdef DM_COMPAT
710         if (_dm_version == 1)
711                 return _dm_task_get_uuid_v1(dmt);
712 #endif
713
714         return (dmt->dmi.v4->uuid);
715 }
716
717 struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
718 {
719 #ifdef DM_COMPAT
720         if (_dm_version == 1)
721                 return _dm_task_get_deps_v1(dmt);
722 #endif
723
724         return (struct dm_deps *) (((void *) dmt->dmi.v4) +
725                                    dmt->dmi.v4->data_start);
726 }
727
728 struct dm_names *dm_task_get_names(struct dm_task *dmt)
729 {
730 #ifdef DM_COMPAT
731         if (_dm_version == 1)
732                 return _dm_task_get_names_v1(dmt);
733 #endif
734
735         return (struct dm_names *) (((void *) dmt->dmi.v4) +
736                                     dmt->dmi.v4->data_start);
737 }
738
739 int dm_task_set_ro(struct dm_task *dmt)
740 {
741         dmt->read_only = 1;
742         return 1;
743 }
744
745 int dm_task_set_newname(struct dm_task *dmt, const char *newname)
746 {
747         if (!(dmt->newname = strdup(newname))) {
748                 log_error("dm_task_set_newname: strdup(%s) failed", newname);
749                 return 0;
750         }
751
752         return 1;
753 }
754
755 int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr)
756 {
757         dmt->event_nr = event_nr;
758
759         return 1;
760 }
761
762 struct target *create_target(uint64_t start, uint64_t len, const char *type,
763                              const char *params)
764 {
765         struct target *t = malloc(sizeof(*t));
766
767         if (!t) {
768                 log_error("create_target: malloc(%d) failed", sizeof(*t));
769                 return NULL;
770         }
771
772         memset(t, 0, sizeof(*t));
773
774         if (!(t->params = strdup(params))) {
775                 log_error("create_target: strdup(params) failed");
776                 goto bad;
777         }
778
779         if (!(t->type = strdup(type))) {
780                 log_error("create_target: strdup(type) failed");
781                 goto bad;
782         }
783
784         t->start = start;
785         t->length = len;
786         return t;
787
788       bad:
789         free(t->params);
790         free(t->type);
791         free(t);
792         return NULL;
793 }
794
795 static void *_add_target(struct target *t, void *out, void *end)
796 {
797         void *out_sp = out;
798         struct dm_target_spec sp;
799         size_t sp_size = sizeof(struct dm_target_spec);
800         int len;
801         const char no_space[] = "Ran out of memory building ioctl parameter";
802
803         out += sp_size;
804         if (out >= end) {
805                 log_error(no_space);
806                 return NULL;
807         }
808
809         sp.status = 0;
810         sp.sector_start = t->start;
811         sp.length = t->length;
812         strncpy(sp.target_type, t->type, sizeof(sp.target_type));
813
814         len = strlen(t->params);
815
816         if ((out + len + 1) >= end) {
817                 log_error(no_space);
818
819                 log_error("t->params= '%s'", t->params);
820                 return NULL;
821         }
822         strcpy((char *) out, t->params);
823         out += len + 1;
824
825         /* align next block */
826         out = _align(out, ALIGNMENT);
827
828         sp.next = out - out_sp;
829         memcpy(out_sp, &sp, sp_size);
830
831         return out;
832 }
833
834 static struct dm_ioctl *_flatten(struct dm_task *dmt)
835 {
836         const size_t min_size = 16 * 1024;
837         const int (*version)[3];
838
839         struct dm_ioctl *dmi;
840         struct target *t;
841         size_t len = sizeof(struct dm_ioctl);
842         void *b, *e;
843         int count = 0;
844
845         for (t = dmt->head; t; t = t->next) {
846                 len += sizeof(struct dm_target_spec);
847                 len += strlen(t->params) + 1 + ALIGNMENT;
848                 count++;
849         }
850
851         if (count && dmt->newname) {
852                 log_error("targets and newname are incompatible");
853                 return NULL;
854         }
855
856         if (dmt->newname)
857                 len += strlen(dmt->newname) + 1;
858
859         /*
860          * Give len a minimum size so that we have space to store
861          * dependencies or status information.
862          */
863         if (len < min_size)
864                 len = min_size;
865
866         if (!(dmi = malloc(len)))
867                 return NULL;
868
869         memset(dmi, 0, len);
870
871         version = &_cmd_data_v4[dmt->type].version;
872
873         dmi->version[0] = (*version)[0];
874         dmi->version[1] = (*version)[1];
875         dmi->version[2] = (*version)[2];
876
877         dmi->data_size = len;
878         dmi->data_start = sizeof(struct dm_ioctl);
879
880         if (dmt->dev_name)
881                 strncpy(dmi->name, dmt->dev_name, sizeof(dmi->name));
882
883         if (dmt->type == DM_DEVICE_SUSPEND)
884                 dmi->flags |= DM_SUSPEND_FLAG;
885         if (dmt->read_only)
886                 dmi->flags |= DM_READONLY_FLAG;
887
888         if (dmt->minor >= 0) {
889                 if (dmt->major <= 0) {
890                         log_error("Missing major number for persistent device");
891                         return NULL;
892                 }
893                 dmi->flags |= DM_PERSISTENT_DEV_FLAG;
894                 dmi->dev = MKDEV(dmt->major, dmt->minor);
895         }
896
897         if (dmt->uuid)
898                 strncpy(dmi->uuid, dmt->uuid, sizeof(dmi->uuid));
899
900         dmi->target_count = count;
901         dmi->event_nr = dmt->event_nr;
902
903         b = (void *) (dmi + 1);
904         e = (void *) ((char *) dmi + len);
905
906         for (t = dmt->head; t; t = t->next)
907                 if (!(b = _add_target(t, b, e)))
908                         goto bad;
909
910         if (dmt->newname)
911                 strcpy(b, dmt->newname);
912
913         return dmi;
914
915       bad:
916         free(dmi);
917         return NULL;
918 }
919
920 static int _create_and_load_v4(struct dm_task *dmt)
921 {
922         struct dm_task *task;
923         int r;
924
925         /* Use new task struct to create the device */
926         if (!(task = dm_task_create(DM_DEVICE_CREATE))) {
927                 log_error("Failed to create device-mapper task struct");
928                 return 0;
929         }
930
931         /* Copy across relevant fields */
932         if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) {
933                 dm_task_destroy(task);
934                 return 0;
935         }
936
937         if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid)) {
938                 dm_task_destroy(task);
939                 return 0;
940         }
941
942         task->major = dmt->major;
943         task->minor = dmt->minor;
944
945         r = dm_task_run(task);
946         dm_task_destroy(task);
947         if (!r)
948                 return r;
949
950         /* Next load the table */
951         if (!(task = dm_task_create(DM_DEVICE_RELOAD))) {
952                 log_error("Failed to create device-mapper task struct");
953                 return 0;
954         }
955
956         /* Copy across relevant fields */
957         if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) {
958                 dm_task_destroy(task);
959                 return 0;
960         }
961
962         task->read_only = dmt->read_only;
963         task->head = dmt->head;
964         task->tail = dmt->tail;
965
966         r = dm_task_run(task);
967
968         task->head = NULL;
969         task->tail = NULL;
970         dm_task_destroy(task);
971         if (!r)
972                 return r;
973
974         /* Use the original structure last so the info will be correct */
975         dmt->type = DM_DEVICE_RESUME;
976         dmt->uuid = NULL;
977         free(dmt->uuid);
978
979         r = dm_task_run(dmt);
980
981         return r;
982 }
983
984 int dm_task_run(struct dm_task *dmt)
985 {
986         struct dm_ioctl *dmi = NULL;
987         unsigned int command;
988
989 #ifdef DM_COMPAT
990         if (_dm_version == 1)
991                 return _dm_task_run_v1(dmt);
992 #endif
993
994         if ((unsigned) dmt->type >=
995             (sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) {
996                 log_error("Internal error: unknown device-mapper task %d",
997                           dmt->type);
998                 goto bad;
999         }
1000
1001         command = _cmd_data_v4[dmt->type].cmd;
1002
1003         /* Old-style creation had a table supplied */
1004         if (dmt->type == DM_DEVICE_CREATE && dmt->head)
1005                 return _create_and_load_v4(dmt);
1006
1007         if (!_open_control())
1008                 return 0;
1009
1010         dmi = _flatten(dmt);
1011         if (!dmi) {
1012                 log_error("Couldn't create ioctl argument");
1013                 return 0;
1014         }
1015
1016         if (dmt->type == DM_DEVICE_TABLE)
1017                 dmi->flags |= DM_STATUS_TABLE_FLAG;
1018
1019         dmi->flags |= DM_EXISTS_FLAG;   /* FIXME */
1020         log_debug("dm %s %s %s %s", _cmd_data_v4[dmt->type].name, dmi->name,
1021                   dmi->uuid, dmt->newname ? dmt->newname : "");
1022         if (ioctl(_control_fd, command, dmi) < 0) {
1023                 if (errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) ||
1024                                        (dmt->type == DM_DEVICE_MKNODES))) {
1025                         dmi->flags &= ~DM_EXISTS_FLAG;  /* FIXME */
1026                         goto ignore_error;
1027                 }
1028                 if (_log_suppress)
1029                         log_verbose("device-mapper ioctl cmd %d failed: %s",
1030                                     _IOC_NR(command), strerror(errno));
1031                 else
1032                         log_error("device-mapper ioctl cmd %d failed: %s",
1033                                   _IOC_NR(command), strerror(errno));
1034                 goto bad;
1035         }
1036
1037       ignore_error:
1038         switch (dmt->type) {
1039         case DM_DEVICE_CREATE:
1040                 add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev));
1041                 break;
1042
1043         case DM_DEVICE_REMOVE:
1044                 rm_dev_node(dmt->dev_name);
1045                 break;
1046
1047         case DM_DEVICE_RENAME:
1048                 rename_dev_node(dmt->dev_name, dmt->newname);
1049                 break;
1050
1051         case DM_DEVICE_MKNODES:
1052                 if (dmi->flags & DM_EXISTS_FLAG)
1053                         add_dev_node(dmt->dev_name, MAJOR(dmi->dev),
1054                                      MINOR(dmi->dev));
1055                 else
1056                         rm_dev_node(dmt->dev_name);
1057                 break;
1058
1059         case DM_DEVICE_STATUS:
1060         case DM_DEVICE_TABLE:
1061         case DM_DEVICE_WAITEVENT:
1062                 if (!_unmarshal_status(dmt, dmi))
1063                         goto bad;
1064                 break;
1065         }
1066
1067         dmt->dmi.v4 = dmi;
1068         return 1;
1069
1070       bad:
1071         free(dmi);
1072         return 0;
1073 }
1074
1075 void dm_lib_release(void)
1076 {
1077         if (_control_fd != -1) {
1078                 close(_control_fd);
1079                 _control_fd = -1;
1080         }
1081         update_devs();
1082 }
1083
1084 void dm_lib_exit(void)
1085 {
1086         if (_control_fd != -1) {
1087                 close(_control_fd);
1088                 _control_fd = -1;
1089         }
1090         _version_ok = 1;
1091         _version_checked = 0;
1092 }