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