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