4469fa848de83f4e703567025d9821a174fcf50f
[platform/upstream/multipath-tools.git] / kpartx / devmapper.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdint.h>
8 #include <libdevmapper.h>
9 #include <ctype.h>
10 #include <errno.h>
11 #include <sys/sysmacros.h>
12 #include "devmapper.h"
13
14 #define _UUID_PREFIX "part"
15 #define UUID_PREFIX _UUID_PREFIX "%d-"
16 #define _UUID_PREFIX_LEN (sizeof(_UUID_PREFIX) - 1)
17 #define MAX_PREFIX_LEN (_UUID_PREFIX_LEN + 4)
18 #define PARAMS_SIZE 1024
19
20 int dm_prereq(char * str, int x, int y, int z)
21 {
22         int r = 1;
23         struct dm_task *dmt;
24         struct dm_versions *target;
25         struct dm_versions *last_target;
26
27         if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
28                 return 1;
29
30         dm_task_no_open_count(dmt);
31
32         if (!dm_task_run(dmt))
33                 goto out;
34
35         target = dm_task_get_versions(dmt);
36
37         /* Fetch targets and print 'em */
38         do {
39                 last_target = target;
40
41                 if (!strncmp(str, target->name, strlen(str)) &&
42                     /* dummy prereq on multipath version */
43                     target->version[0] >= x &&
44                     target->version[1] >= y &&
45                     target->version[2] >= z
46                    )
47                         r = 0;
48
49                 target = (void *) target + target->next;
50         } while (last_target != target);
51
52 out:
53         dm_task_destroy(dmt);
54         return r;
55 }
56
57 int dm_simplecmd(int task, const char *name, int no_flush, uint16_t udev_flags)
58 {
59         int r = 0;
60         int udev_wait_flag = (task == DM_DEVICE_RESUME ||
61                               task == DM_DEVICE_REMOVE);
62 #ifdef LIBDM_API_COOKIE
63         uint32_t cookie = 0;
64 #endif
65         struct dm_task *dmt;
66
67         if (!(dmt = dm_task_create(task)))
68                 return 0;
69
70         if (!dm_task_set_name(dmt, name))
71                 goto out;
72
73         dm_task_no_open_count(dmt);
74         dm_task_skip_lockfs(dmt);
75
76         if (no_flush)
77                 dm_task_no_flush(dmt);
78
79 #ifdef LIBDM_API_COOKIE
80         if (!udev_sync)
81                 udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
82         if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags))
83                 goto out;
84 #endif
85         r = dm_task_run(dmt);
86 #ifdef LIBDM_API_COOKIE
87         if (udev_wait_flag)
88                         dm_udev_wait(cookie);
89 #endif
90 out:
91         dm_task_destroy(dmt);
92         return r;
93 }
94
95 static void
96 strip_slash (char * device)
97 {
98         char * p = device;
99
100         while (*(p++) != 0x0) {
101
102                 if (*p == '/')
103                         *p = '!';
104         }
105 }
106
107 static int format_partname(char *buf, size_t bufsiz,
108                            const char *mapname, const char *delim, int part)
109 {
110         if (snprintf(buf, bufsiz, "%s%s%d", mapname, delim, part) >= bufsiz)
111                 return 0;
112         strip_slash(buf);
113         return 1;
114 }
115
116 static char *make_prefixed_uuid(int part, const char *uuid)
117 {
118         char *prefixed_uuid;
119         int len = MAX_PREFIX_LEN + strlen(uuid) + 1;
120
121         prefixed_uuid = malloc(len);
122         if (!prefixed_uuid) {
123                 fprintf(stderr, "cannot create prefixed uuid : %s\n",
124                         strerror(errno));
125                 return NULL;
126         }
127         snprintf(prefixed_uuid, len, UUID_PREFIX "%s", part, uuid);
128         return prefixed_uuid;
129 }
130
131 int dm_addmap(int task, const char *name, const char *target,
132               const char *params, uint64_t size, int ro, const char *uuid,
133               int part, mode_t mode, uid_t uid, gid_t gid)
134 {
135         int r = 0;
136         struct dm_task *dmt;
137         char *prefixed_uuid = NULL;
138 #ifdef LIBDM_API_COOKIE
139         uint32_t cookie = 0;
140         uint16_t udev_flags = 0;
141 #endif
142
143         if (!(dmt = dm_task_create (task)))
144                 return 0;
145
146         if (!dm_task_set_name (dmt, name))
147                 goto addout;
148
149         if (!dm_task_add_target (dmt, 0, size, target, params))
150                 goto addout;
151
152         if (ro && !dm_task_set_ro (dmt))
153                         goto addout;
154
155         if (task == DM_DEVICE_CREATE && uuid) {
156                 prefixed_uuid = make_prefixed_uuid(part, uuid);
157                 if (prefixed_uuid == NULL)
158                         goto addout;
159                 if (!dm_task_set_uuid(dmt, prefixed_uuid))
160                         goto addout;
161         }
162
163         if (!dm_task_set_mode(dmt, mode))
164                 goto addout;
165         if (!dm_task_set_uid(dmt, uid))
166                 goto addout;
167         if (!dm_task_set_gid(dmt, gid))
168                 goto addout;
169
170         dm_task_no_open_count(dmt);
171
172 #ifdef LIBDM_API_COOKIE
173         if (!udev_sync)
174                 udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK;
175         if (task == DM_DEVICE_CREATE &&
176             !dm_task_set_cookie(dmt, &cookie, udev_flags))
177                 goto addout;
178 #endif
179         r = dm_task_run (dmt);
180 #ifdef LIBDM_API_COOKIE
181         if (task == DM_DEVICE_CREATE)
182                         dm_udev_wait(cookie);
183 #endif
184 addout:
185         dm_task_destroy (dmt);
186         free(prefixed_uuid);
187
188         return r;
189 }
190
191 static int dm_map_present(char *str, char **uuid)
192 {
193         int r = 0;
194         struct dm_task *dmt;
195         const char *uuidtmp;
196         struct dm_info info;
197
198         if (uuid)
199                 *uuid = NULL;
200
201         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
202                 return 0;
203
204         if (!dm_task_set_name(dmt, str))
205                 goto out;
206
207         dm_task_no_open_count(dmt);
208
209         if (!dm_task_run(dmt))
210                 goto out;
211
212         if (!dm_task_get_info(dmt, &info))
213                 goto out;
214
215         if (!info.exists)
216                 goto out;
217
218         r = 1;
219         if (uuid) {
220                 uuidtmp = dm_task_get_uuid(dmt);
221                 if (uuidtmp && strlen(uuidtmp))
222                         *uuid = strdup(uuidtmp);
223         }
224 out:
225         dm_task_destroy(dmt);
226         return r;
227 }
228
229 static int dm_rename (const char *old, const char *new)
230 {
231         int r = 0;
232         struct dm_task *dmt;
233         uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK;
234         uint32_t cookie = 0;
235
236         dmt = dm_task_create(DM_DEVICE_RENAME);
237         if (!dmt)
238                 return r;
239
240         if (!dm_task_set_name(dmt, old) ||
241             !dm_task_set_newname(dmt, new) ||
242             !dm_task_no_open_count(dmt) ||
243             !dm_task_set_cookie(dmt, &cookie, udev_flags))
244                 goto out;
245
246         r = dm_task_run(dmt);
247         dm_udev_wait(cookie);
248
249 out:
250         dm_task_destroy(dmt);
251         return r;
252 }
253
254 static const char *dm_find_uuid(const char *uuid)
255 {
256         struct dm_task *dmt;
257         const char *name = NULL, *tmp;
258
259         if ((dmt = dm_task_create(DM_DEVICE_INFO)) == NULL)
260                 return NULL;
261
262         if (!dm_task_set_uuid(dmt, uuid) ||
263             !dm_task_run(dmt))
264                 goto out;
265
266         tmp = dm_task_get_name(dmt);
267         if (tmp != NULL && *tmp != '\0')
268                 name = strdup(tmp);
269
270 out:
271         dm_task_destroy(dmt);
272         return name;
273 }
274
275 char *
276 dm_mapname(int major, int minor)
277 {
278         struct dm_task *dmt;
279         char *mapname = NULL;
280         const char *map;
281
282         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
283                 return NULL;
284
285         dm_task_no_open_count(dmt);
286         dm_task_set_major(dmt, major);
287         dm_task_set_minor(dmt, minor);
288
289         if (!dm_task_run(dmt))
290                 goto out;
291
292         map = dm_task_get_name(dmt);
293         if (map && strlen(map))
294                 mapname = strdup(map);
295
296 out:
297         dm_task_destroy(dmt);
298         return mapname;
299 }
300
301 /*
302  * dm_get_first_dep
303  *
304  * Return the device number of the first dependend device
305  * for a given target.
306  */
307 dev_t dm_get_first_dep(char *devname)
308 {
309         struct dm_task *dmt;
310         struct dm_deps *dm_deps;
311         dev_t ret = 0;
312
313         if ((dmt = dm_task_create(DM_DEVICE_DEPS)) == NULL) {
314                 return ret;
315         }
316         if (!dm_task_set_name(dmt, devname)) {
317                 goto out;
318         }
319         if (!dm_task_run(dmt)) {
320                 goto out;
321         }
322         if ((dm_deps = dm_task_get_deps(dmt)) == NULL) {
323                 goto out;
324         }
325         if (dm_deps->count > 0) {
326                 ret = dm_deps->device[0];
327         }
328 out:
329         dm_task_destroy(dmt);
330
331         return ret;
332 }
333
334 char *
335 dm_mapuuid(const char *mapname)
336 {
337         struct dm_task *dmt;
338         const char *tmp;
339         char *uuid = NULL;
340
341         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
342                 return NULL;
343
344         if (!dm_task_set_name(dmt, mapname))
345                 goto out;
346         dm_task_no_open_count(dmt);
347
348         if (!dm_task_run(dmt))
349                 goto out;
350
351         tmp = dm_task_get_uuid(dmt);
352         if (tmp[0] != '\0')
353                 uuid = strdup(tmp);
354 out:
355         dm_task_destroy(dmt);
356         return uuid;
357 }
358
359 int
360 dm_devn (const char * mapname, int *major, int *minor)
361 {
362         int r = 1;
363         struct dm_task *dmt;
364         struct dm_info info;
365
366         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
367                 return 0;
368
369         if (!dm_task_set_name(dmt, mapname))
370                 goto out;
371
372         if (!dm_task_run(dmt))
373                 goto out;
374
375         if (!dm_task_get_info(dmt, &info) || info.exists == 0)
376                 goto out;
377
378         *major = info.major;
379         *minor = info.minor;
380
381         r = 0;
382 out:
383         dm_task_destroy(dmt);
384         return r;
385 }
386
387 static int
388 dm_get_map(const char *mapname, char * outparams)
389 {
390         int r = 1;
391         struct dm_task *dmt;
392         uint64_t start, length;
393         char *target_type = NULL;
394         char *params = NULL;
395
396         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
397                 return 1;
398
399         if (!dm_task_set_name(dmt, mapname))
400                 goto out;
401         dm_task_no_open_count(dmt);
402
403         if (!dm_task_run(dmt))
404                 goto out;
405
406         /* Fetch 1st target */
407         dm_get_next_target(dmt, NULL, &start, &length,
408                            &target_type, &params);
409
410         if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
411                 r = 0;
412 out:
413         dm_task_destroy(dmt);
414         return r;
415 }
416
417 static int
418 dm_get_opencount (const char * mapname)
419 {
420         int r = -1;
421         struct dm_task *dmt;
422         struct dm_info info;
423
424         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
425                 return 0;
426
427         if (!dm_task_set_name(dmt, mapname))
428                 goto out;
429
430         if (!dm_task_run(dmt))
431                 goto out;
432
433         if (!dm_task_get_info(dmt, &info))
434                 goto out;
435
436         if (!info.exists)
437                 goto out;
438
439         r = info.open_count;
440 out:
441         dm_task_destroy(dmt);
442         return r;
443 }
444
445 /*
446  * returns:
447  *    1 : match
448  *    0 : no match
449  *   -1 : empty map
450  */
451 static int
452 dm_type(const char * name, char * type)
453 {
454         int r = 0;
455         struct dm_task *dmt;
456         uint64_t start, length;
457         char *target_type = NULL;
458         char *params;
459
460         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
461                 return 0;
462
463         if (!dm_task_set_name(dmt, name))
464                 goto out;
465
466         dm_task_no_open_count(dmt);
467
468         if (!dm_task_run(dmt))
469                 goto out;
470
471         /* Fetch 1st target */
472         if (dm_get_next_target(dmt, NULL, &start, &length,
473                                &target_type, &params) != NULL)
474                 /* more than one target */
475                 r = -1;
476         else if (!target_type)
477                 r = -1;
478         else if (!strcmp(target_type, type))
479                 r = 1;
480
481 out:
482         dm_task_destroy(dmt);
483         return r;
484 }
485
486 /*
487  * returns:
488  *    0 : if both uuids end with same suffix which starts with UUID_PREFIX
489  *    1 : otherwise
490  */
491 int
492 dm_compare_uuid(const char *mapuuid, const char *partname)
493 {
494         char *partuuid;
495         int r = 1;
496
497         partuuid = dm_mapuuid(partname);
498         if (!partuuid)
499                 return 1;
500
501         if (!strncmp(partuuid, _UUID_PREFIX, _UUID_PREFIX_LEN)) {
502                 char *p = partuuid + _UUID_PREFIX_LEN;
503                 /* skip partition number */
504                 while (isdigit(*p))
505                         p++;
506                 if (p != partuuid + _UUID_PREFIX_LEN && *p == '-' &&
507                     !strcmp(mapuuid, p + 1))
508                         r = 0;
509         }
510         free(partuuid);
511         return r;
512 }
513
514 struct remove_data {
515         int verbose;
516 };
517
518 static int
519 do_foreach_partmaps (const char * mapname, const char *uuid,
520                      dev_t devt,
521                      int (*partmap_func)(const char *, void *),
522                      void *data)
523 {
524         struct dm_task *dmt;
525         struct dm_names *names;
526         struct remove_data *rd = data;
527         unsigned next = 0;
528         char params[PARAMS_SIZE];
529         int major, minor;
530         char dev_t[32];
531         int r = 1;
532         int is_dmdev = 1;
533
534         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
535                 return 1;
536
537         dm_task_no_open_count(dmt);
538
539         if (!dm_task_run(dmt))
540                 goto out;
541
542         if (!(names = dm_task_get_names(dmt)))
543                 goto out;
544
545         if (!names->dev) {
546                 r = 0; /* this is perfectly valid */
547                 goto out;
548         }
549
550         if (dm_devn(mapname, &major, &minor) ||
551             (major != major(devt) || minor != minor(devt)))
552                 /*
553                  * The latter could happen if a dm device "/dev/mapper/loop0"
554                  * exits while kpartx is called on "/dev/loop0".
555                  */
556                 is_dmdev = 0;
557
558         sprintf(dev_t, "%d:%d", major(devt), minor(devt));
559         do {
560                 /*
561                  * skip our devmap
562                  */
563                 if (is_dmdev && !strcmp(names->name, mapname))
564                         goto next;
565
566                 /*
567                  * skip if we cannot fetch the map table from the kernel
568                  */
569                 if (dm_get_map(names->name, &params[0]))
570                         goto next;
571
572                 /*
573                  * skip if the table does not map over the multipath map
574                  */
575                 if (!strstr(params, dev_t))
576                         goto next;
577
578                 /*
579                  * skip if devmap target is not "linear"
580                  */
581                 if (dm_type(names->name, "linear") != 1) {
582                         if (rd->verbose)
583                                 printf("%s: is not a linear target. Not removing\n",
584                                        names->name);
585                         goto next;
586                 }
587
588                 /*
589                  * skip if uuids don't match
590                  */
591                 if (uuid && dm_compare_uuid(uuid, names->name)) {
592                         if (rd->verbose)
593                                 printf("%s: is not a kpartx partition. Not removing\n",
594                                        names->name);
595                         goto next;
596                 }
597
598                 if (partmap_func(names->name, data) != 0)
599                         goto out;
600         next:
601                 next = names->next;
602                 names = (void *) names + next;
603         } while (next);
604
605         r = 0;
606 out:
607         dm_task_destroy (dmt);
608         return r;
609 }
610
611 static int
612 remove_partmap(const char *name, void *data)
613 {
614         struct remove_data *rd = (struct remove_data *)data;
615         int r = 0;
616
617         if (dm_get_opencount(name)) {
618                 if (rd->verbose)
619                         printf("%s is in use. Not removing", name);
620                 return 1;
621         }
622         if (!dm_simplecmd(DM_DEVICE_REMOVE, name, 0, 0)) {
623                 if (rd->verbose)
624                         printf("%s: failed to remove\n", name);
625                 r = 1;
626         } else if (rd->verbose)
627                 printf("del devmap : %s\n", name);
628         return r;
629 }
630
631 int
632 dm_remove_partmaps (char * mapname, char *uuid, dev_t devt, int verbose)
633 {
634         struct remove_data rd = { verbose };
635         return do_foreach_partmaps(mapname, uuid, devt, remove_partmap, &rd);
636 }
637
638 int dm_find_part(const char *parent, const char *delim, int part,
639                  const char *parent_uuid,
640                  char *name, size_t namesiz, char **part_uuid, int verbose)
641 {
642         int r;
643         char params[PARAMS_SIZE];
644         const char *tmp;
645         char *uuid;
646         int major, minor;
647         char dev_t[32];
648
649         if (!format_partname(name, namesiz, parent, delim, part)) {
650                 if (verbose)
651                         fprintf(stderr, "partname too small\n");
652                 return 0;
653         }
654
655         r = dm_map_present(name, part_uuid);
656         if (r == 1 || parent_uuid == NULL || *parent_uuid == '\0')
657                 return r;
658
659         uuid = make_prefixed_uuid(part, parent_uuid);
660         if (!uuid)
661                 return 0;
662
663         tmp = dm_find_uuid(uuid);
664         if (tmp == NULL)
665                 return r;
666
667         /* Sanity check on partition, see dm_foreach_partmaps */
668         if (dm_type(tmp, "linear") != 1)
669                 goto out;
670
671         /*
672          * Try nondm uuid first. That way we avoid confusing
673          * a device name with a device mapper name.
674          */
675         if (!nondm_parse_uuid(parent_uuid, &major, &minor) &&
676             dm_devn(parent, &major, &minor))
677                 goto out;
678         snprintf(dev_t, sizeof(dev_t), "%d:%d", major, minor);
679
680         if (dm_get_map(tmp, params))
681                 goto out;
682
683         if (!strstr(params, dev_t))
684                 goto out;
685
686         if (verbose)
687                 fprintf(stderr, "found map %s for uuid %s, renaming to %s\n",
688                        tmp, uuid, name);
689
690         r = dm_rename(tmp, name);
691         if (r == 0) {
692                 free(uuid);
693                 if (verbose)
694                         fprintf(stderr, "renaming %s->%s failed\n", tmp, name);
695         } else
696                 *part_uuid = uuid;
697 out:
698         free((void*)tmp);
699         return r;
700 }
701
702 char *nondm_create_uuid(dev_t devt)
703 {
704 #define NONDM_UUID_BUFLEN (34 + sizeof(NONDM_UUID_PREFIX) + \
705                            sizeof(NONDM_UUID_SUFFIX))
706         static char uuid_buf[NONDM_UUID_BUFLEN];
707         snprintf(uuid_buf, sizeof(uuid_buf), "%s_%u:%u_%s",
708                  NONDM_UUID_PREFIX, major(devt), minor(devt),
709                  NONDM_UUID_SUFFIX);
710         uuid_buf[NONDM_UUID_BUFLEN-1] = '\0';
711         return uuid_buf;
712 }
713
714 int nondm_parse_uuid(const char *uuid, int *major, int *minor)
715 {
716         const char *p;
717         char *e;
718         int ma, mi;
719
720         if (strncmp(uuid, NONDM_UUID_PREFIX "_", sizeof(NONDM_UUID_PREFIX)))
721                 return 0;
722         p = uuid + sizeof(NONDM_UUID_PREFIX);
723         ma = strtoul(p, &e, 10);
724         if (e == p || *e != ':')
725                 return 0;
726         p = e + 1;
727         mi = strtoul(p, &e, 10);
728         if (e == p || *e != '_')
729                 return 0;
730         p = e + 1;
731         if (strcmp(p, NONDM_UUID_SUFFIX))
732                 return 0;
733
734         *major = ma;
735         *minor = mi;
736         return 1;
737 }