Merge branch 'master' of git://git.kernel.org/pub/scm/linux/storage/multipath-tools/
[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 int
781 dm_get_name(char *uuid, char *name)
782 {
783         vector vec;
784         struct multipath *mpp;
785         int i, rc = 0;
786
787         vec = vector_alloc();
788
789         if (!vec)
790                 return 0;
791
792         if (dm_get_maps(vec)) {
793                 goto out;
794         }
795
796         vector_foreach_slot(vec, mpp, i) {
797                 if (!strcmp(uuid, mpp->wwid)) {
798                         strcpy(name, mpp->alias);
799                         rc=1;
800                         break;
801                 }
802         }
803 out:
804         vector_foreach_slot(vec, mpp, i) {
805                 free_multipath(mpp, KEEP_PATHS);
806         }
807         vector_free(vec);
808         return rc;
809 }
810
811 int
812 dm_geteventnr (char *name)
813 {
814         struct dm_task *dmt;
815         struct dm_info info;
816
817         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
818                 return 0;
819
820         if (!dm_task_set_name(dmt, name))
821                 goto out;
822
823         dm_task_no_open_count(dmt);
824
825         if (!dm_task_run(dmt))
826                 goto out;
827
828         if (!dm_task_get_info(dmt, &info)) {
829                 info.event_nr = 0;
830                 goto out;
831         }
832
833         if (!info.exists) {
834                 info.event_nr = 0;
835                 goto out;
836         }
837
838 out:
839         dm_task_destroy(dmt);
840
841         return info.event_nr;
842 }
843
844 char *
845 dm_mapname(int major, int minor)
846 {
847         char * response = NULL;
848         const char *map;
849         struct dm_task *dmt;
850         int r;
851         int loop = MAX_WAIT * LOOPS_PER_SEC;
852
853         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
854                 return NULL;
855
856         if (!dm_task_set_major(dmt, major) ||
857             !dm_task_set_minor(dmt, minor))
858                 goto bad;
859
860         dm_task_no_open_count(dmt);
861
862         /*
863          * device map might not be ready when we get here from
864          * daemon uev_trigger -> uev_add_map
865          */
866         while (--loop) {
867                 r = dm_task_run(dmt);
868
869                 if (r)
870                         break;
871
872                 usleep(1000 * 1000 / LOOPS_PER_SEC);
873         }
874
875         if (!r) {
876                 condlog(0, "%i:%i: timeout fetching map name", major, minor);
877                 goto bad;
878         }
879
880         map = dm_task_get_name(dmt);
881         if (map && strlen(map))
882                 response = STRDUP((char *)dm_task_get_name(dmt));
883
884         dm_task_destroy(dmt);
885         return response;
886 bad:
887         dm_task_destroy(dmt);
888         condlog(0, "%i:%i: error fetching map name", major, minor);
889         return NULL;
890 }
891
892 int
893 dm_remove_partmaps (const char * mapname, int need_sync)
894 {
895         struct dm_task *dmt;
896         struct dm_names *names;
897         unsigned next = 0;
898         char params[PARAMS_SIZE];
899         unsigned long long size;
900         char dev_t[32];
901         int r = 1;
902
903         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
904                 return 1;
905
906         dm_task_no_open_count(dmt);
907
908         if (!dm_task_run(dmt))
909                 goto out;
910
911         if (!(names = dm_task_get_names(dmt)))
912                 goto out;
913
914         if (!names->dev) {
915                 r = 0; /* this is perfectly valid */
916                 goto out;
917         }
918
919         if (dm_dev_t(mapname, &dev_t[0], 32))
920                 goto out;
921
922         do {
923                 if (
924                     /*
925                      * if devmap target is "linear"
926                      */
927                     (dm_type(names->name, TGT_PART) > 0) &&
928
929                     /*
930                      * and the multipath mapname and the part mapname start
931                      * the same
932                      */
933                     !strncmp(names->name, mapname, strlen(mapname)) &&
934
935                     /*
936                      * and the opencount is 0 for us to allow removal
937                      */
938                     !dm_get_opencount(names->name) &&
939
940                     /*
941                      * and we can fetch the map table from the kernel
942                      */
943                     !dm_get_map(names->name, &size, &params[0]) &&
944
945                     /*
946                      * and the table maps over the multipath map
947                      */
948                     strstr(params, dev_t)
949                    ) {
950                                 /*
951                                  * then it's a kpartx generated partition.
952                                  * remove it.
953                                  */
954                                 condlog(4, "partition map %s removed",
955                                         names->name);
956                                 dm_simplecmd_flush(DM_DEVICE_REMOVE, names->name, need_sync);
957                    }
958
959                 next = names->next;
960                 names = (void *) names + next;
961         } while (next);
962
963         r = 0;
964 out:
965         dm_task_destroy (dmt);
966         return r;
967 }
968
969 static struct dm_info *
970 alloc_dminfo (void)
971 {
972         return MALLOC(sizeof(struct dm_info));
973 }
974
975 int
976 dm_get_info (char * mapname, struct dm_info ** dmi)
977 {
978         int r = 1;
979         struct dm_task *dmt = NULL;
980
981         if (!mapname)
982                 return 1;
983
984         if (!*dmi)
985                 *dmi = alloc_dminfo();
986
987         if (!*dmi)
988                 return 1;
989
990         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
991                 goto out;
992
993         if (!dm_task_set_name(dmt, mapname))
994                 goto out;
995
996         dm_task_no_open_count(dmt);
997
998         if (!dm_task_run(dmt))
999                 goto out;
1000
1001         if (!dm_task_get_info(dmt, *dmi))
1002                 goto out;
1003
1004         r = 0;
1005 out:
1006         if (r) {
1007                 memset(*dmi, 0, sizeof(struct dm_info));
1008                 FREE(*dmi);
1009                 *dmi = NULL;
1010         }
1011
1012         if (dmt)
1013                 dm_task_destroy(dmt);
1014
1015         return r;
1016 }
1017
1018 int
1019 dm_rename_partmaps (char * old, char * new)
1020 {
1021         struct dm_task *dmt;
1022         struct dm_names *names;
1023         unsigned next = 0;
1024         char buff[PARAMS_SIZE];
1025         unsigned long long size;
1026         char dev_t[32];
1027         int r = 1;
1028
1029         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
1030                 return 1;
1031
1032         dm_task_no_open_count(dmt);
1033
1034         if (!dm_task_run(dmt))
1035                 goto out;
1036
1037         if (!(names = dm_task_get_names(dmt)))
1038                 goto out;
1039
1040         if (!names->dev) {
1041                 r = 0; /* this is perfectly valid */
1042                 goto out;
1043         }
1044
1045         if (dm_dev_t(old, &dev_t[0], 32))
1046                 goto out;
1047
1048         do {
1049                 if (
1050                     /*
1051                      * if devmap target is "linear"
1052                      */
1053                     (dm_type(names->name, TGT_PART) > 0) &&
1054
1055                     /*
1056                      * and the multipath mapname and the part mapname start
1057                      * the same
1058                      */
1059                     !strncmp(names->name, old, strlen(old)) &&
1060
1061                     /*
1062                      * and we can fetch the map table from the kernel
1063                      */
1064                     !dm_get_map(names->name, &size, &buff[0]) &&
1065
1066                     /*
1067                      * and the table maps over the multipath map
1068                      */
1069                     strstr(buff, dev_t)
1070                    ) {
1071                                 /*
1072                                  * then it's a kpartx generated partition.
1073                                  * Rename it.
1074                                  */
1075                                 snprintf(buff, PARAMS_SIZE, "%s%s",
1076                                          new, names->name + strlen(old));
1077                                 dm_rename(names->name, buff);
1078                                 condlog(4, "partition map %s renamed",
1079                                         names->name);
1080                    }
1081
1082                 next = names->next;
1083                 names = (void *) names + next;
1084         } while (next);
1085
1086         r = 0;
1087 out:
1088         dm_task_destroy (dmt);
1089         return r;
1090 }
1091
1092 int
1093 dm_rename (char * old, char * new)
1094 {
1095         int r = 0;
1096         struct dm_task *dmt;
1097
1098         if (dm_rename_partmaps(old, new))
1099                 return r;
1100
1101         if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
1102                 return r;
1103
1104         if (!dm_task_set_name(dmt, old))
1105                 goto out;
1106
1107         if (!dm_task_set_newname(dmt, new))
1108                 goto out;
1109
1110         dm_task_no_open_count(dmt);
1111
1112         if (!dm_task_set_cookie(dmt, &conf->cookie, 0))
1113                 goto out;
1114         if (!dm_task_run(dmt))
1115                 goto out;
1116
1117         r = 1;
1118 out:
1119         dm_task_destroy(dmt);
1120         return r;
1121 }