[multipath] new '-f' command line flag
[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_map (char * mapname, char * type)
279 {
280         if (!dm_type(mapname, type) || dm_get_opencount(mapname))
281                 return 1;
282
283         return dm_simplecmd(DM_DEVICE_REMOVE, mapname);
284 }
285
286 extern int
287 dm_flush_maps (char * type)
288 {
289         int r = 0;
290         struct dm_task *dmt;
291         struct dm_names *names;
292         unsigned next = 0;
293
294         if (!(dmt = dm_task_create (DM_DEVICE_LIST)))
295                 return 0;
296
297         dm_task_no_open_count(dmt);
298
299         if (!dm_task_run (dmt))
300                 goto out;
301
302         if (!(names = dm_task_get_names (dmt)))
303                 goto out;
304
305         if (!names->dev)
306                 goto out;
307
308         do {
309                 r += dm_flush_map(names->name, type);
310                 next = names->next;
311                 names = (void *) names + next;
312         } while (next);
313
314         out:
315         dm_task_destroy (dmt);
316         return r;
317 }
318
319 int
320 dm_fail_path(char * mapname, char * path)
321 {
322         int r = 1;
323         struct dm_task *dmt;
324         char str[32];
325
326         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
327                 return 1;
328
329         if (!dm_task_set_name(dmt, mapname))
330                 goto out;
331
332         if (!dm_task_set_sector(dmt, 0))
333                 goto out;
334
335         if (snprintf(str, 32, "fail_path %s\n", path) > 32)
336                 goto out;
337
338         if (!dm_task_set_message(dmt, str))
339                 goto out;
340
341         dm_task_no_open_count(dmt);
342
343         if (!dm_task_run(dmt))
344                 goto out;
345
346         r = 0;
347 out:
348         dm_task_destroy(dmt);
349         return r;
350 }
351
352 int
353 dm_reinstate(char * mapname, char * path)
354 {
355         int r = 1;
356         struct dm_task *dmt;
357         char str[32];
358
359         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
360                 return 1;
361
362         if (!dm_task_set_name(dmt, mapname))
363                 goto out;
364
365         if (!dm_task_set_sector(dmt, 0))
366                 goto out;
367
368         if (snprintf(str, 32, "reinstate_path %s\n", path) > 32)
369                 goto out;
370
371         if (!dm_task_set_message(dmt, str))
372                 goto out;
373
374         dm_task_no_open_count(dmt);
375
376         if (!dm_task_run(dmt))
377                 goto out;
378
379         r = 0;
380 out:
381         dm_task_destroy(dmt);
382         return r;
383 }
384
385 static int
386 dm_groupmsg (char * msg, char * mapname, int index)
387 {
388         int r = 0;
389         struct dm_task *dmt;
390         char str[24];
391
392         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
393                 return 0;
394
395         if (!dm_task_set_name(dmt, mapname))
396                 goto out;
397
398         if (!dm_task_set_sector(dmt, 0))
399                 goto out;
400
401         snprintf(str, 24, "%s_group %i\n", msg, index);
402         condlog(3, "message %s 0 %s", mapname, str);
403
404         if (!dm_task_set_message(dmt, str))
405                 goto out;
406
407         dm_task_no_open_count(dmt);
408
409         if (!dm_task_run(dmt))
410                 goto out;
411
412         r = 1;
413
414         out:
415         dm_task_destroy(dmt);
416
417         return r;
418 }
419
420 int
421 dm_switchgroup(char * mapname, int index)
422 {
423         return dm_groupmsg("switch", mapname,index);
424 }
425
426 int
427 dm_enablegroup(char * mapname, int index)
428 {
429         return dm_groupmsg("enable", mapname,index);
430 }
431
432 int
433 dm_disablegroup(char * mapname, int index)
434 {
435         return dm_groupmsg("disable", mapname,index);
436 }
437
438 int
439 dm_get_maps (vector mp, char * type)
440 {
441         struct multipath * mpp;
442         int r = 1;
443         struct dm_task *dmt;
444         struct dm_names *names;
445         unsigned next = 0;
446
447         if (!type || !mp)
448                 return 1;
449
450         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
451                 return 1;
452
453         dm_task_no_open_count(dmt);
454
455         if (!dm_task_run(dmt))
456                 goto out;
457
458         if (!(names = dm_task_get_names(dmt)))
459                 goto out;
460
461         if (!names->dev) {
462                 r = 0; /* this is perfectly valid */
463                 goto out;
464         }
465
466         do {
467                 if (dm_type(names->name, type)) {
468                         mpp = alloc_multipath();
469
470                         if (!mpp)
471                                 goto out;
472
473                         if (dm_get_map(names->name, &mpp->size, mpp->params))
474                                 goto out1;
475
476                         if (dm_get_status(names->name, mpp->status))
477                                 goto out1;
478
479                         mpp->alias = MALLOC(strlen(names->name) + 1);
480
481                         if (!mpp->alias)
482                                 goto out1;
483
484                         strncat(mpp->alias, names->name, strlen(names->name));
485
486                         if (!vector_alloc_slot(mp))
487                                 goto out1;
488                         
489                         vector_set_slot(mp, mpp);
490                         mpp = NULL;
491                 }
492                 next = names->next;
493                 names = (void *) names + next;
494         } while (next);
495
496         r = 0;
497         goto out;
498 out1:
499         free_multipath(mpp, KEEP_PATHS);
500 out:
501         dm_task_destroy (dmt);
502         return r;
503 }
504
505 int
506 dm_geteventnr (char *name)
507 {
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, name))
515                 goto out;
516
517         dm_task_no_open_count(dmt);
518
519         if (!dm_task_run(dmt))
520                 goto out;
521
522         if (!dm_task_get_info(dmt, &info)) {
523                 info.event_nr = 0;
524                 goto out;
525         }
526
527         if (!info.exists) {
528                 info.event_nr = 0;
529                 goto out;
530         }
531
532 out:
533         dm_task_destroy(dmt);
534
535         return info.event_nr;
536 }
537
538 char *
539 dm_mapname(int major, int minor, char *type)
540 {
541         struct dm_task *dmt;
542         void *next = NULL;
543         uint64_t start, length;
544         char *target_type = NULL;
545         char *params;
546         int r;
547         int loop = MAX_WAIT * LOOPS_PER_SEC;
548
549         if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
550                 return NULL;
551
552         if (!dm_task_set_major(dmt, major) ||
553             !dm_task_set_minor(dmt, minor))
554                 goto bad;
555
556         dm_task_no_open_count(dmt);
557
558         /*
559          * device map might not be ready when we get here from
560          * uevent trigger
561          */
562         while (--loop) {
563                 r = dm_task_run(dmt);
564
565                 if (r)
566                         break;
567
568                 usleep(1000 * 1000 / LOOPS_PER_SEC);
569         }
570
571         if (!r)
572                 goto bad;
573
574         if (!type)
575                 goto good;
576
577         do {
578                 next = dm_get_next_target(dmt, next, &start, &length,
579                                           &target_type, &params);
580                 if (target_type && strcmp(target_type, type))
581                         goto bad;
582         } while (next);
583
584 good:
585         dm_task_destroy(dmt);
586         return strdup(dm_task_get_name(dmt));
587 bad:
588         dm_task_destroy(dmt);
589         return NULL;
590 }
591