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