[multipathd]
[platform/upstream/multipath-tools.git] / libmultipath / devmapper.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <libdevmapper.h>
5 #include <ctype.h>
6 #include <linux/kdev_t.h>
7 #include <unistd.h>
8
9 #include "vector.h"
10 #include "structs.h"
11 #include "debug.h"
12 #include "memory.h"
13
14 #define MAX_WAIT 5
15 #define LOOPS_PER_SEC 5
16
17 extern int
18 dm_prereq (char * str, int x, int y, int z)
19 {
20         int r = 1;
21         struct dm_task *dmt;
22         struct dm_versions *target;
23         struct dm_versions *last_target;
24
25         if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
26                 return 1;
27
28         dm_task_no_open_count(dmt);
29
30         if (!dm_task_run(dmt))
31                 goto out;
32
33         target = dm_task_get_versions(dmt);
34
35         /* Fetch targets and print 'em */
36         do {
37                 last_target = target;
38
39                 if (!strncmp(str, target->name, strlen(str)) &&
40                     /* dummy prereq on multipath version */
41                     target->version[0] >= x &&
42                     target->version[1] >= y &&
43                     target->version[2] >= z
44                    )
45                         r = 0;
46
47                 target = (void *) target + target->next;
48         } while (last_target != target);
49
50         out:
51         dm_task_destroy(dmt);
52         return r;
53 }
54
55 extern int
56 dm_simplecmd (int task, const char *name) {
57         int r = 0;
58         struct dm_task *dmt;
59
60         if (!(dmt = dm_task_create (task)))
61                 return 0;
62
63         if (!dm_task_set_name (dmt, name))
64                 goto out;
65
66         dm_task_no_open_count(dmt);
67
68         r = dm_task_run (dmt);
69
70         out:
71         dm_task_destroy (dmt);
72         return r;
73 }
74
75 extern int
76 dm_addmap (int task, const char *name, const char *target,
77            const char *params, unsigned long size) {
78         int r = 0;
79         struct dm_task *dmt;
80
81         if (!(dmt = dm_task_create (task)))
82                 return 0;
83
84         if (!dm_task_set_name (dmt, name))
85                 goto addout;
86
87         if (!dm_task_add_target (dmt, 0, size, target, params))
88                 goto addout;
89
90         dm_task_no_open_count(dmt);
91
92         r = dm_task_run (dmt);
93
94         addout:
95         dm_task_destroy (dmt);
96         return r;
97 }
98
99 extern int
100 dm_map_present (char * str)
101 {
102         int r = 0;
103         struct dm_task *dmt;
104         struct dm_info info;
105
106         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
107                 return 0;
108
109         if (!dm_task_set_name(dmt, str))
110                 goto out;
111
112         dm_task_no_open_count(dmt);
113
114         if (!dm_task_run(dmt))
115                 goto out;
116
117         if (!dm_task_get_info(dmt, &info))
118                 goto out;
119
120         if (info.exists)
121                 r = 1;
122 out:
123         dm_task_destroy(dmt);
124         return r;
125 }
126
127 extern int
128 dm_get_map(char * name, unsigned long * size, char * outparams)
129 {
130         int r = 1;
131         struct dm_task *dmt;
132         void *next = NULL;
133         uint64_t start, length;
134         char *target_type = NULL;
135         char *params = NULL;
136
137         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
138                 return 1;
139
140         if (!dm_task_set_name(dmt, name))
141                 goto out;
142
143         dm_task_no_open_count(dmt);
144
145         if (!dm_task_run(dmt))
146                 goto out;
147
148         /* Fetch 1st target */
149         next = dm_get_next_target(dmt, next, &start, &length,
150                                   &target_type, &params);
151
152         if (size)
153                 *size = length;
154
155         if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
156                 r = 0;
157 out:
158         dm_task_destroy(dmt);
159         return r;
160 }
161
162 extern int
163 dm_get_status(char * name, char * outstatus)
164 {
165         int r = 1;
166         struct dm_task *dmt;
167         void *next = NULL;
168         uint64_t start, length;
169         char *target_type;
170         char *status;
171
172         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
173                 return 1;
174
175         if (!dm_task_set_name(dmt, name))
176                 goto out;
177
178         dm_task_no_open_count(dmt);
179
180         if (!dm_task_run(dmt))
181                 goto out;
182
183         /* Fetch 1st target */
184         next = dm_get_next_target(dmt, next, &start, &length,
185                                   &target_type, &status);
186
187         if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
188                 r = 0;
189 out:
190         dm_task_destroy(dmt);
191         return r;
192 }
193
194 extern int
195 dm_type(char * name, char * type)
196 {
197         int r = 0;
198         struct dm_task *dmt;
199         void *next = NULL;
200         uint64_t start, length;
201         char *target_type = NULL;
202         char *params;
203
204         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
205                 return 0;
206
207         if (!dm_task_set_name(dmt, name))
208                 goto out;
209
210         dm_task_no_open_count(dmt);
211
212         if (!dm_task_run(dmt))
213                 goto out;
214
215         /* Fetch 1st target */
216         next = dm_get_next_target(dmt, next, &start, &length,
217                                   &target_type, &params);
218
219         if (0 == strcmp(target_type, type))
220                 r = 1;
221
222 out:
223         dm_task_destroy(dmt);
224         return r;
225 }
226
227 int
228 dm_get_opencount (char * mapname)
229 {
230         int r = -1;
231         struct dm_task *dmt;
232         struct dm_info info;
233
234         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
235                 return 0;
236
237         if (!dm_task_set_name(dmt, mapname))
238                 goto out;
239
240         if (!dm_task_run(dmt))
241                 goto out;
242
243         if (!dm_task_get_info(dmt, &info))
244                 goto out;
245
246         r = info.open_count;
247 out:
248         dm_task_destroy(dmt);
249         return r;
250 }
251         
252 int
253 dm_get_minor (char * mapname)
254 {
255         int r = -1;
256         struct dm_task *dmt;
257         struct dm_info info;
258
259         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
260                 return 0;
261
262         if (!dm_task_set_name(dmt, mapname))
263                 goto out;
264
265         if (!dm_task_run(dmt))
266                 goto out;
267
268         if (!dm_task_get_info(dmt, &info))
269                 goto out;
270
271         r = info.minor;
272 out:
273         dm_task_destroy(dmt);
274         return r;
275 }
276         
277 extern int
278 dm_flush_maps (char * type)
279 {
280         int r = 0;
281         struct dm_task *dmt;
282         struct dm_names *names;
283         unsigned next = 0;
284
285         if (!(dmt = dm_task_create (DM_DEVICE_LIST)))
286                 return 0;
287
288         dm_task_no_open_count(dmt);
289
290         if (!dm_task_run (dmt))
291                 goto out;
292
293         if (!(names = dm_task_get_names (dmt)))
294                 goto out;
295
296         if (!names->dev)
297                 goto out;
298
299         do {
300                 if (dm_type(names->name, type) &&
301                     dm_get_opencount(names->name) == 0 &&
302                     !dm_simplecmd(DM_DEVICE_REMOVE, names->name))
303                         r++;
304
305                 next = names->next;
306                 names = (void *) names + next;
307         } while (next);
308
309         out:
310         dm_task_destroy (dmt);
311         return r;
312 }
313
314 int
315 dm_fail_path(char * mapname, char * path)
316 {
317         int r = 1;
318         struct dm_task *dmt;
319         char str[32];
320
321         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
322                 return 1;
323
324         if (!dm_task_set_name(dmt, mapname))
325                 goto out;
326
327         if (!dm_task_set_sector(dmt, 0))
328                 goto out;
329
330         if (snprintf(str, 32, "fail_path %s\n", path) > 32)
331                 goto out;
332
333         if (!dm_task_set_message(dmt, str))
334                 goto out;
335
336         dm_task_no_open_count(dmt);
337
338         if (!dm_task_run(dmt))
339                 goto out;
340
341         r = 0;
342 out:
343         dm_task_destroy(dmt);
344         return r;
345 }
346
347 int
348 dm_reinstate(char * mapname, char * path)
349 {
350         int r = 1;
351         struct dm_task *dmt;
352         char str[32];
353
354         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
355                 return 1;
356
357         if (!dm_task_set_name(dmt, mapname))
358                 goto out;
359
360         if (!dm_task_set_sector(dmt, 0))
361                 goto out;
362
363         if (snprintf(str, 32, "reinstate_path %s\n", path) > 32)
364                 goto out;
365
366         if (!dm_task_set_message(dmt, str))
367                 goto out;
368
369         dm_task_no_open_count(dmt);
370
371         if (!dm_task_run(dmt))
372                 goto out;
373
374         r = 0;
375 out:
376         dm_task_destroy(dmt);
377         return r;
378 }
379
380 int
381 dm_switchgroup(char * mapname, int index)
382 {
383         int r = 0;
384         struct dm_task *dmt;
385         char str[24];
386
387         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
388                 return 0;
389
390         if (!dm_task_set_name(dmt, mapname))
391                 goto out;
392
393         if (!dm_task_set_sector(dmt, 0))
394                 goto out;
395
396         snprintf(str, 24, "switch_group %i\n", index);
397         condlog(3, "message %s 0 %s", mapname, str);
398
399         if (!dm_task_set_message(dmt, str))
400                 goto out;
401
402         dm_task_no_open_count(dmt);
403
404         if (!dm_task_run(dmt))
405                 goto out;
406
407         r = 1;
408
409         out:
410         dm_task_destroy(dmt);
411
412         return r;
413 }
414
415 int
416 dm_get_maps (vector mp, char * type)
417 {
418         struct multipath * mpp;
419         int r = 1;
420         struct dm_task *dmt;
421         struct dm_names *names;
422         unsigned next = 0;
423
424         if (!type || !mp)
425                 return 1;
426
427         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
428                 return 1;
429
430         dm_task_no_open_count(dmt);
431
432         if (!dm_task_run(dmt))
433                 goto out;
434
435         if (!(names = dm_task_get_names(dmt)))
436                 goto out;
437
438         if (!names->dev) {
439                 r = 0; /* this is perfectly valid */
440                 goto out;
441         }
442
443         do {
444                 if (dm_type(names->name, type)) {
445                         mpp = alloc_multipath();
446
447                         if (!mpp)
448                                 goto out;
449
450                         if (dm_get_map(names->name, &mpp->size, mpp->params))
451                                 goto out1;
452
453                         if (dm_get_status(names->name, mpp->status))
454                                 goto out1;
455
456                         mpp->alias = MALLOC(strlen(names->name) + 1);
457
458                         if (!mpp->alias)
459                                 goto out1;
460
461                         strncat(mpp->alias, names->name, strlen(names->name));
462
463                         if (!vector_alloc_slot(mp))
464                                 goto out1;
465                         
466                         vector_set_slot(mp, mpp);
467                         mpp = NULL;
468                 }
469                 next = names->next;
470                 names = (void *) names + next;
471         } while (next);
472
473         r = 0;
474         goto out;
475 out1:
476         free_multipath(mpp, KEEP_PATHS);
477 out:
478         dm_task_destroy (dmt);
479         return r;
480 }
481
482 int
483 dm_geteventnr (char *name)
484 {
485         struct dm_task *dmt;
486         struct dm_info info;
487
488         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
489                 return 0;
490
491         if (!dm_task_set_name(dmt, name))
492                 goto out;
493
494         dm_task_no_open_count(dmt);
495
496         if (!dm_task_run(dmt))
497                 goto out;
498
499         if (!dm_task_get_info(dmt, &info)) {
500                 info.event_nr = 0;
501                 goto out;
502         }
503
504         if (!info.exists) {
505                 info.event_nr = 0;
506                 goto out;
507         }
508
509 out:
510         dm_task_destroy(dmt);
511
512         return info.event_nr;
513 }
514
515 char *
516 dm_mapname(int major, int minor, char *type)
517 {
518         struct dm_task *dmt;
519         void *next = NULL;
520         uint64_t start, length;
521         char *target_type = NULL;
522         char *params;
523         int r;
524         int loop = MAX_WAIT * LOOPS_PER_SEC;
525
526         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
527                 return NULL;
528
529         if (!dm_task_set_major(dmt, major) ||
530             !dm_task_set_minor(dmt, minor))
531                 goto bad;
532
533         dm_task_no_open_count(dmt);
534
535         /*
536          * device map might not be ready when we get here from
537          * uevent trigger
538          */
539         while (--loop) {
540                 r = dm_task_run(dmt);
541
542                 if (r)
543                         break;
544
545                 usleep(1000 * 1000 / LOOPS_PER_SEC);
546         }
547
548         if (!r)
549                 goto bad;
550
551         if (!type)
552                 goto good;
553
554         do {
555                 next = dm_get_next_target(dmt, next, &start, &length,
556                                           &target_type, &params);
557                 if (target_type && strcmp(target_type, type))
558                         goto bad;
559         } while (next);
560
561 good:
562         dm_task_destroy(dmt);
563         return strdup(dm_task_get_name(dmt));
564 bad:
565         dm_task_destroy(dmt);
566         return NULL;
567 }
568