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