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