[lib] abstract a little more devmapper internals
[platform/upstream/multipath-tools.git] / libmultipath / devmapper.c
1 /*
2  * snippets copied from device-mapper dmsetup.c
3  * Copyright (c) 2004, 2005 Christophe Varoqui
4  * Copyright (c) 2005 Kiyoshi Ueda, NEC
5  * Copyright (c) 2005 Patrick Caulfield, Redhat
6  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <string.h>
11 #include <libdevmapper.h>
12 #include <ctype.h>
13 #include <linux/kdev_t.h>
14 #include <unistd.h>
15 #include <errno.h>
16
17 #include "checkers.h"
18 #include "vector.h"
19 #include "structs.h"
20 #include "debug.h"
21 #include "memory.h"
22 #include "devmapper.h"
23 #include "config.h"
24
25 #include "log_pthread.h"
26 #include <sys/types.h>
27 #include <time.h>
28
29 #define MAX_WAIT 5
30 #define LOOPS_PER_SEC 5
31
32 #define UUID_PREFIX "mpath-"
33 #define UUID_PREFIX_LEN 6
34
35 static void
36 dm_write_log (int level, const char *file, int line, const char *f, ...)
37 {
38         va_list ap;
39         int thres;
40
41         if (level > 6)
42                 level = 6;
43
44         thres = (conf) ? conf->verbosity : 0;
45         if (thres <= 3 || level > thres)
46                 return;
47
48         va_start(ap, f);
49         if (!logsink) {
50                 time_t t = time(NULL);
51                 struct tm *tb = localtime(&t);
52                 char buff[16];
53
54                 strftime(buff, sizeof(buff), "%b %d %H:%M:%S", tb);
55                 buff[sizeof(buff)-1] = '\0';
56
57                 fprintf(stdout, "%s | ", buff);
58                 fprintf(stdout, "libdevmapper: %s(%i): ", file, line);
59                 vfprintf(stdout, f, ap);
60                 fprintf(stdout, "\n");
61         } else {
62                 condlog(level, "libdevmapper: %s(%i): ", file, line);
63                 log_safe(level + 3, f, ap);
64         }
65         va_end(ap);
66
67         return;
68 }
69
70 extern void
71 dm_init(void) {
72         dm_log_init(&dm_write_log);
73         dm_log_init_verbose(conf ? conf->verbosity + 3 : 0);
74 }
75
76 static int
77 dm_libprereq (void)
78 {
79         char version[64];
80         int v[3];
81         int minv[3] = {1, 2, 8};
82
83         dm_get_library_version(version, sizeof(version));
84         condlog(3, "libdevmapper version %s", version);
85         sscanf(version, "%d.%d.%d ", &v[0], &v[1], &v[2]);
86
87         if ((v[0] > minv[0]) ||
88             ((v[0] ==  minv[0]) && (v[1] > minv[1])) ||
89             ((v[0] == minv[0]) && (v[1] == minv[1]) && (v[2] >= minv[2])))
90                 return 0;
91         condlog(0, "libdevmapper version must be >= %d.%.2d.%.2d",
92                 minv[0], minv[1], minv[2]);
93         return 1;
94 }
95
96 static int
97 dm_drvprereq (char * str)
98 {
99         int r = 2;
100         struct dm_task *dmt;
101         struct dm_versions *target;
102         struct dm_versions *last_target;
103         int minv[3] = {1, 0, 3};
104         unsigned int *v;
105
106         if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
107                 return 3;
108
109         dm_task_no_open_count(dmt);
110
111         if (!dm_task_run(dmt)) {
112                 condlog(0, "Can not communicate with kernel DM");
113                 goto out;
114         }
115         target = dm_task_get_versions(dmt);
116
117         do {
118                 last_target = target;
119                 if (!strncmp(str, target->name, strlen(str))) {
120                         r = 1;
121                         break;
122                 }
123                 target = (void *) target + target->next;
124         } while (last_target != target);
125
126         if (r == 2) {
127                 condlog(0, "DM multipath kernel driver not loaded");
128                 goto out;
129         }
130         v = target->version;
131         if ((v[0] > minv[0]) ||
132             ((v[0] == minv[0]) && (v[1] > minv[1])) ||
133             ((v[0] == minv[0]) && (v[1] == minv[1]) && (v[2] >= minv[2]))) {
134                 r = 0;
135                 goto out;
136         }
137         condlog(0, "DM multipath kernel driver must be >= %u.%.2u.%.2u",
138                 minv[0], minv[1], minv[2]);
139 out:
140         dm_task_destroy(dmt);
141         return r;
142 }
143
144 extern int
145 dm_prereq (void)
146 {
147         if (dm_libprereq())
148                 return 1;
149         return dm_drvprereq(TGT_MPATH);
150 }
151
152 extern int
153 dm_simplecmd (int task, const char *name) {
154         int r = 0;
155         struct dm_task *dmt;
156
157         if (!(dmt = dm_task_create (task)))
158                 return 0;
159
160         if (!dm_task_set_name (dmt, name))
161                 goto out;
162
163         dm_task_no_open_count(dmt);
164         dm_task_skip_lockfs(dmt);       /* for DM_DEVICE_RESUME */
165 #ifdef LIBDM_API_FLUSH
166         dm_task_no_flush(dmt);          /* for DM_DEVICE_SUSPEND/RESUME */
167 #endif
168
169         r = dm_task_run (dmt);
170
171         out:
172         dm_task_destroy (dmt);
173         return r;
174 }
175
176 extern int
177 dm_addmap (int task, const char *name, const char *target,
178            const char *params, unsigned long long size, const char *uuid) {
179         int r = 0;
180         struct dm_task *dmt;
181         char *prefixed_uuid = NULL;
182
183         if (!(dmt = dm_task_create (task)))
184                 return 0;
185
186         if (!dm_task_set_name (dmt, name))
187                 goto addout;
188
189         if (!dm_task_add_target (dmt, 0, size, target, params))
190                 goto addout;
191
192         if (uuid){
193                 prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(uuid) + 1);
194                 if (!prefixed_uuid) {
195                         condlog(0, "cannot create prefixed uuid : %s\n",
196                                 strerror(errno));
197                         goto addout;
198                 }
199                 sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid);
200                 if (!dm_task_set_uuid(dmt, prefixed_uuid))
201                         goto freeout;
202         }
203
204         dm_task_no_open_count(dmt);
205
206         r = dm_task_run (dmt);
207
208         freeout:
209         if (prefixed_uuid)
210                 free(prefixed_uuid);
211
212         addout:
213         dm_task_destroy (dmt);
214
215         return r;
216 }
217
218 extern int
219 dm_addmap_create (const char *name, const char *params,
220                   unsigned long long size, const char *uuid) {
221         int r;
222         r = dm_addmap(DM_DEVICE_CREATE, name, TGT_MPATH, params, size, uuid);
223         /*
224          * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
225          * Failing the second part leaves an empty map. Clean it up.
226          */
227         if (!r && dm_map_present(name)) {
228                 condlog(3, "%s: failed to load map (a path might be in use)",
229                         name);
230                 dm_flush_map(name);
231         }
232         return r;
233 }
234
235 extern int
236 dm_addmap_reload (const char *name, const char *params,
237                   unsigned long long size, const char *uuid) {
238         int r;
239         r = dm_addmap(DM_DEVICE_RELOAD, name, TGT_MPATH, params, size, uuid);
240         return r;
241 }
242
243 extern int
244 dm_map_present (const char * str)
245 {
246         int r = 0;
247         struct dm_task *dmt;
248         struct dm_info info;
249
250         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
251                 return 0;
252
253         if (!dm_task_set_name(dmt, str))
254                 goto out;
255
256         dm_task_no_open_count(dmt);
257
258         if (!dm_task_run(dmt))
259                 goto out;
260
261         if (!dm_task_get_info(dmt, &info))
262                 goto out;
263
264         if (info.exists)
265                 r = 1;
266 out:
267         dm_task_destroy(dmt);
268         return r;
269 }
270
271 extern int
272 dm_get_map(char * name, unsigned long long * size, char * outparams)
273 {
274         int r = 1;
275         struct dm_task *dmt;
276         void *next = NULL;
277         uint64_t start, length;
278         char *target_type = NULL;
279         char *params = NULL;
280
281         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
282                 return 1;
283
284         if (!dm_task_set_name(dmt, name))
285                 goto out;
286
287         dm_task_no_open_count(dmt);
288
289         if (!dm_task_run(dmt))
290                 goto out;
291
292         /* Fetch 1st target */
293         next = dm_get_next_target(dmt, next, &start, &length,
294                                   &target_type, &params);
295
296         if (size)
297                 *size = length;
298
299         if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
300                 r = 0;
301 out:
302         dm_task_destroy(dmt);
303         return r;
304 }
305
306 extern int
307 dm_get_uuid(char *name, char *uuid)
308 {
309         struct dm_task *dmt;
310         const char *uuidtmp;
311         int r = 1;
312
313         dmt = dm_task_create(DM_DEVICE_INFO);
314         if (!dmt)
315                 return 1;
316
317         if (!dm_task_set_name (dmt, name))
318                 goto uuidout;
319
320         if (!dm_task_run(dmt))
321                 goto uuidout;
322
323         uuidtmp = dm_task_get_uuid(dmt);
324         if (uuidtmp) {
325                 if (!strncmp(uuidtmp, UUID_PREFIX, UUID_PREFIX_LEN))
326                         strcpy(uuid, uuidtmp + UUID_PREFIX_LEN);
327                 else
328                         strcpy(uuid, uuidtmp);
329         }
330         else
331                 uuid[0] = '\0';
332
333         r = 0;
334 uuidout:
335         dm_task_destroy(dmt);
336         return r;
337 }
338
339 extern int
340 dm_get_status(char * name, char * outstatus)
341 {
342         int r = 1;
343         struct dm_task *dmt;
344         void *next = NULL;
345         uint64_t start, length;
346         char *target_type;
347         char *status;
348
349         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
350                 return 1;
351
352         if (!dm_task_set_name(dmt, name))
353                 goto out;
354
355         dm_task_no_open_count(dmt);
356
357         if (!dm_task_run(dmt))
358                 goto out;
359
360         /* Fetch 1st target */
361         next = dm_get_next_target(dmt, next, &start, &length,
362                                   &target_type, &status);
363
364         if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
365                 r = 0;
366 out:
367         if (r)
368                 condlog(0, "%s: error getting map status string", name);
369
370         dm_task_destroy(dmt);
371         return r;
372 }
373
374 /*
375  * returns:
376  *    1 : match
377  *    0 : no match
378  *   -1 : empty map
379  */
380 extern int
381 dm_type(const char * name, char * type)
382 {
383         int r = 0;
384         struct dm_task *dmt;
385         void *next = NULL;
386         uint64_t start, length;
387         char *target_type = NULL;
388         char *params;
389
390         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
391                 return 0;
392
393         if (!dm_task_set_name(dmt, name))
394                 goto out;
395
396         dm_task_no_open_count(dmt);
397
398         if (!dm_task_run(dmt))
399                 goto out;
400
401         /* Fetch 1st target */
402         next = dm_get_next_target(dmt, next, &start, &length,
403                                   &target_type, &params);
404
405         if (!target_type)
406                 r = -1;
407         else if (!strcmp(target_type, type))
408                 r = 1;
409
410 out:
411         dm_task_destroy(dmt);
412         return r;
413 }
414
415 static int
416 dm_dev_t (const char * mapname, char * dev_t, int len)
417 {
418         int r = 1;
419         struct dm_task *dmt;
420         struct dm_info info;
421
422         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
423                 return 0;
424
425         if (!dm_task_set_name(dmt, mapname))
426                 goto out;
427
428         if (!dm_task_run(dmt))
429                 goto out;
430
431         if (!dm_task_get_info(dmt, &info))
432                 goto out;
433
434         r = info.open_count;
435         if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
436                     goto out;
437
438         r = 0;
439 out:
440         dm_task_destroy(dmt);
441         return r;
442 }
443         
444 int
445 dm_get_opencount (const char * mapname)
446 {
447         int r = -1;
448         struct dm_task *dmt;
449         struct dm_info info;
450
451         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
452                 return 0;
453
454         if (!dm_task_set_name(dmt, mapname))
455                 goto out;
456
457         if (!dm_task_run(dmt))
458                 goto out;
459
460         if (!dm_task_get_info(dmt, &info))
461                 goto out;
462
463         r = info.open_count;
464 out:
465         dm_task_destroy(dmt);
466         return r;
467 }
468         
469 int
470 dm_get_minor (char * mapname)
471 {
472         int r = -1;
473         struct dm_task *dmt;
474         struct dm_info info;
475
476         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
477                 return 0;
478
479         if (!dm_task_set_name(dmt, mapname))
480                 goto out;
481
482         if (!dm_task_run(dmt))
483                 goto out;
484
485         if (!dm_task_get_info(dmt, &info))
486                 goto out;
487
488         r = info.minor;
489 out:
490         dm_task_destroy(dmt);
491         return r;
492 }
493         
494 extern int
495 dm_flush_map (const char * mapname)
496 {
497         int r;
498
499         if (!dm_map_present(mapname))
500                 return 0;
501
502         if (dm_type(mapname, TGT_MPATH) <= 0)
503                 return 1;
504
505         if (dm_remove_partmaps(mapname))
506                 return 1;
507
508         if (dm_get_opencount(mapname)) {
509                 condlog(2, "%s: map in use", mapname);
510                 return 1;
511         }       
512
513         r = dm_simplecmd(DM_DEVICE_REMOVE, mapname);
514
515         if (r) {
516                 condlog(4, "multipath map %s removed", mapname);
517                 return 0;
518         }
519         return 1;
520 }
521
522 extern int
523 dm_flush_maps (void)
524 {
525         int r = 0;
526         struct dm_task *dmt;
527         struct dm_names *names;
528         unsigned next = 0;
529
530         if (!(dmt = dm_task_create (DM_DEVICE_LIST)))
531                 return 0;
532
533         dm_task_no_open_count(dmt);
534
535         if (!dm_task_run (dmt))
536                 goto out;
537
538         if (!(names = dm_task_get_names (dmt)))
539                 goto out;
540
541         if (!names->dev)
542                 goto out;
543
544         do {
545                 r += dm_flush_map(names->name);
546                 next = names->next;
547                 names = (void *) names + next;
548         } while (next);
549
550         out:
551         dm_task_destroy (dmt);
552         return r;
553 }
554
555 int
556 dm_message(char * mapname, char * message)
557 {
558         int r = 1;
559         struct dm_task *dmt;
560
561         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
562                 return 1;
563
564         if (!dm_task_set_name(dmt, mapname))
565                 goto out;
566
567         if (!dm_task_set_sector(dmt, 0))
568                 goto out;
569
570         if (!dm_task_set_message(dmt, message))
571                 goto out;
572
573         dm_task_no_open_count(dmt);
574
575         if (!dm_task_run(dmt))
576                 goto out;
577
578         r = 0;
579 out:
580         if (r)
581                 condlog(0, "DM message failed [%s]", message);
582
583         dm_task_destroy(dmt);
584         return r;
585 }
586
587 int
588 dm_fail_path(char * mapname, char * path)
589 {
590         char message[32];
591
592         if (snprintf(message, 32, "fail_path %s\n", path) > 32)
593                 return 1;
594
595         return dm_message(mapname, message);
596 }
597
598 int
599 dm_reinstate_path(char * mapname, char * path)
600 {
601         char message[32];
602
603         if (snprintf(message, 32, "reinstate_path %s\n", path) > 32)
604                 return 1;
605
606         return dm_message(mapname, message);
607 }
608
609 int
610 dm_queue_if_no_path(char *mapname, int enable)
611 {
612         char *message;
613
614         if (enable)
615                 message = "queue_if_no_path\n";
616         else
617                 message = "fail_if_no_path\n";
618
619         return dm_message(mapname, message);
620 }
621
622 int
623 dm_set_pg_timeout(char *mapname, int timeout_val)
624 {
625         char message[24];
626
627         if (snprintf(message, 24, "set_pg_timeout %d", timeout_val) >= 24)
628                 return 1;
629         return dm_message(mapname, message);
630 }
631
632 static int
633 dm_groupmsg (char * msg, char * mapname, int index)
634 {
635         char message[32];
636
637         if (snprintf(message, 32, "%s_group %i\n", msg, index) > 32)
638                 return 1;
639
640         return dm_message(mapname, message);
641 }
642
643 int
644 dm_switchgroup(char * mapname, int index)
645 {
646         return dm_groupmsg("switch", mapname, index);
647 }
648
649 int
650 dm_enablegroup(char * mapname, int index)
651 {
652         return dm_groupmsg("enable", mapname, index);
653 }
654
655 int
656 dm_disablegroup(char * mapname, int index)
657 {
658         return dm_groupmsg("disable", mapname, index);
659 }
660
661 int
662 dm_get_maps (vector mp)
663 {
664         struct multipath * mpp;
665         int r = 1;
666         int info;
667         struct dm_task *dmt;
668         struct dm_names *names;
669         unsigned next = 0;
670
671         if (!mp)
672                 return 1;
673
674         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
675                 return 1;
676
677         dm_task_no_open_count(dmt);
678
679         if (!dm_task_run(dmt))
680                 goto out;
681
682         if (!(names = dm_task_get_names(dmt)))
683                 goto out;
684
685         if (!names->dev) {
686                 r = 0; /* this is perfectly valid */
687                 goto out;
688         }
689
690         do {
691                 info = dm_type(names->name, TGT_MPATH);
692
693                 if (info <= 0)
694                         goto next;
695
696                 mpp = alloc_multipath();
697
698                 if (!mpp)
699                         goto out;
700
701                 mpp->alias = STRDUP(names->name);
702
703                 if (!mpp->alias)
704                         goto out1;
705
706                 if (info > 0) {
707                         if (dm_get_map(names->name, &mpp->size, mpp->params))
708                                 goto out1;
709
710                         if (dm_get_status(names->name, mpp->status))
711                                 goto out1;
712
713                         dm_get_uuid(names->name, mpp->wwid);
714                         dm_get_info(names->name, &mpp->dmi);
715                 }
716
717                 if (!vector_alloc_slot(mp))
718                         goto out1;
719
720                 vector_set_slot(mp, mpp);
721                 mpp = NULL;
722 next:
723                 next = names->next;
724                 names = (void *) names + next;
725         } while (next);
726
727         r = 0;
728         goto out;
729 out1:
730         free_multipath(mpp, KEEP_PATHS);
731 out:
732         dm_task_destroy (dmt);
733         return r;
734 }
735
736 extern int
737 dm_get_name(char *uuid, char *name)
738 {
739         vector vec;
740         struct multipath *mpp;
741         int i;
742
743         vec = vector_alloc();
744
745         if (!vec)
746                 return 0;
747
748         if (dm_get_maps(vec)) {
749                 vector_free(vec);
750                 return 0;
751         }
752
753         vector_foreach_slot(vec, mpp, i) {
754                 if (!strcmp(uuid, mpp->wwid)) {
755                         vector_free(vec);
756                         strcpy(name, mpp->alias);
757                         return 1;
758                 }
759         }
760
761         vector_free(vec);
762         return 0;
763 }
764
765 int
766 dm_geteventnr (char *name)
767 {
768         struct dm_task *dmt;
769         struct dm_info info;
770
771         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
772                 return 0;
773
774         if (!dm_task_set_name(dmt, name))
775                 goto out;
776
777         dm_task_no_open_count(dmt);
778
779         if (!dm_task_run(dmt))
780                 goto out;
781
782         if (!dm_task_get_info(dmt, &info)) {
783                 info.event_nr = 0;
784                 goto out;
785         }
786
787         if (!info.exists) {
788                 info.event_nr = 0;
789                 goto out;
790         }
791
792 out:
793         dm_task_destroy(dmt);
794
795         return info.event_nr;
796 }
797
798 char *
799 dm_mapname(int major, int minor)
800 {
801         char * response = NULL;
802         const char *map;
803         struct dm_task *dmt;
804         int r;
805         int loop = MAX_WAIT * LOOPS_PER_SEC;
806
807         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
808                 return NULL;
809
810         if (!dm_task_set_major(dmt, major) ||
811             !dm_task_set_minor(dmt, minor))
812                 goto bad;
813
814         dm_task_no_open_count(dmt);
815
816         /*
817          * device map might not be ready when we get here from
818          * daemon uev_trigger -> uev_add_map
819          */
820         while (--loop) {
821                 r = dm_task_run(dmt);
822
823                 if (r)
824                         break;
825
826                 usleep(1000 * 1000 / LOOPS_PER_SEC);
827         }
828
829         if (!r) {
830                 condlog(0, "%i:%i: timeout fetching map name", major, minor);
831                 goto bad;
832         }
833
834         map = dm_task_get_name(dmt);
835         if (map && strlen(map))
836                 response = STRDUP((char *)dm_task_get_name(dmt));
837
838         dm_task_destroy(dmt);
839         return response;
840 bad:
841         dm_task_destroy(dmt);
842         condlog(0, "%i:%i: error fetching map name", major, minor);
843         return NULL;
844 }
845
846 int
847 dm_remove_partmaps (const char * mapname)
848 {
849         struct dm_task *dmt;
850         struct dm_names *names;
851         unsigned next = 0;
852         char params[PARAMS_SIZE];
853         unsigned long long size;
854         char dev_t[32];
855         int r = 1;
856
857         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
858                 return 1;
859
860         dm_task_no_open_count(dmt);
861
862         if (!dm_task_run(dmt))
863                 goto out;
864
865         if (!(names = dm_task_get_names(dmt)))
866                 goto out;
867
868         if (!names->dev) {
869                 r = 0; /* this is perfectly valid */
870                 goto out;
871         }
872
873         if (dm_dev_t(mapname, &dev_t[0], 32))
874                 goto out;
875
876         do {
877                 if (
878                     /*
879                      * if devmap target is "linear"
880                      */
881                     (dm_type(names->name, TGT_PART) > 0) &&
882
883                     /*
884                      * and the multipath mapname and the part mapname start
885                      * the same
886                      */
887                     !strncmp(names->name, mapname, strlen(mapname)) &&
888
889                     /*
890                      * and the opencount is 0 for us to allow removal
891                      */
892                     !dm_get_opencount(names->name) &&
893
894                     /*
895                      * and we can fetch the map table from the kernel
896                      */
897                     !dm_get_map(names->name, &size, &params[0]) &&
898
899                     /*
900                      * and the table maps over the multipath map
901                      */
902                     strstr(params, dev_t)
903                    ) {
904                                 /*
905                                  * then it's a kpartx generated partition.
906                                  * remove it.
907                                  */
908                                 condlog(4, "partition map %s removed",
909                                         names->name);
910                                 dm_simplecmd(DM_DEVICE_REMOVE, names->name);
911                    }
912
913                 next = names->next;
914                 names = (void *) names + next;
915         } while (next);
916
917         r = 0;
918 out:
919         dm_task_destroy (dmt);
920         return r;
921 }
922
923 static struct dm_info *
924 alloc_dminfo (void)
925 {
926         return MALLOC(sizeof(struct dm_info));
927 }
928
929 int
930 dm_get_info (char * mapname, struct dm_info ** dmi)
931 {
932         int r = 1;
933         struct dm_task *dmt = NULL;
934         
935         if (!mapname)
936                 return 1;
937
938         if (!*dmi)
939                 *dmi = alloc_dminfo();
940
941         if (!*dmi)
942                 return 1;
943
944         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
945                 goto out;
946
947         if (!dm_task_set_name(dmt, mapname))
948                 goto out;
949
950         dm_task_no_open_count(dmt);
951
952         if (!dm_task_run(dmt))
953                 goto out;
954
955         if (!dm_task_get_info(dmt, *dmi))
956                 goto out;
957
958         r = 0;
959 out:
960         if (r)
961                 memset(*dmi, 0, sizeof(struct dm_info));
962
963         if (dmt)
964                 dm_task_destroy(dmt);
965
966         return r;
967 }
968
969 int
970 dm_rename_partmaps (char * old, char * new)
971 {
972         struct dm_task *dmt;
973         struct dm_names *names;
974         unsigned next = 0;
975         char buff[PARAMS_SIZE];
976         unsigned long long size;
977         char dev_t[32];
978         int r = 1;
979
980         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
981                 return 1;
982
983         dm_task_no_open_count(dmt);
984
985         if (!dm_task_run(dmt))
986                 goto out;
987
988         if (!(names = dm_task_get_names(dmt)))
989                 goto out;
990
991         if (!names->dev) {
992                 r = 0; /* this is perfectly valid */
993                 goto out;
994         }
995
996         if (dm_dev_t(old, &dev_t[0], 32))
997                 goto out;
998
999         do {
1000                 if (
1001                     /*
1002                      * if devmap target is "linear"
1003                      */
1004                     (dm_type(names->name, TGT_PART) > 0) &&
1005
1006                     /*
1007                      * and the multipath mapname and the part mapname start
1008                      * the same
1009                      */
1010                     !strncmp(names->name, old, strlen(old)) &&
1011
1012                     /*
1013                      * and we can fetch the map table from the kernel
1014                      */
1015                     !dm_get_map(names->name, &size, &buff[0]) &&
1016
1017                     /*
1018                      * and the table maps over the multipath map
1019                      */
1020                     strstr(buff, dev_t)
1021                    ) {
1022                                 /*
1023                                  * then it's a kpartx generated partition.
1024                                  * Rename it.
1025                                  */
1026                                 snprintf(buff, PARAMS_SIZE, "%s%s",
1027                                          new, names->name + strlen(old));
1028                                 dm_rename(names->name, buff);
1029                                 condlog(4, "partition map %s renamed",
1030                                         names->name);
1031                    }
1032
1033                 next = names->next;
1034                 names = (void *) names + next;
1035         } while (next);
1036
1037         r = 0;
1038 out:
1039         dm_task_destroy (dmt);
1040         return r;
1041 }
1042
1043 int
1044 dm_rename (char * old, char * new)
1045 {
1046         int r = 0;
1047         struct dm_task *dmt;
1048
1049         if (dm_rename_partmaps(old, new))
1050                 return r;
1051
1052         if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
1053                 return r;
1054
1055         if (!dm_task_set_name(dmt, old))
1056                 goto out;
1057
1058         if (!dm_task_set_newname(dmt, new))
1059                 goto out;
1060         
1061         dm_task_no_open_count(dmt);
1062
1063         if (!dm_task_run(dmt))
1064                 goto out;
1065
1066         r = 1;
1067 out:
1068         dm_task_destroy(dmt);
1069         return r;
1070 }