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