8367a7037879496f1c0b56628e2be13ac7925c1b
[multipath-tools/.git] / multipathd / cli_handlers.c
1 /*
2  * Copyright (c) 2005 Christophe Varoqui
3  */
4 #include <checkers.h>
5 #include <memory.h>
6 #include <vector.h>
7 #include <structs.h>
8 #include <structs_vec.h>
9 #include <libdevmapper.h>
10 #include <devmapper.h>
11 #include <config.h>
12 #include <configure.h>
13 #include <blacklist.h>
14 #include <debug.h>
15 #include <print.h>
16 #include <sysfs.h>
17 #include <errno.h>
18
19 #include "main.h"
20 #include "cli.h"
21
22 int
23 show_paths (char ** r, int * len, struct vectors * vecs, char * style)
24 {
25         int i;
26         struct path * pp;
27         char * c;
28         char * reply;
29         unsigned int maxlen = INITIAL_REPLY_LEN;
30         int again = 1;
31
32         get_path_layout(vecs->pathvec, 1);
33         reply = MALLOC(maxlen);
34
35         while (again) {
36                 if (!reply)
37                         return 1;
38
39                 c = reply;
40
41                 if (VECTOR_SIZE(vecs->pathvec) > 0)
42                         c += snprint_path_header(c, reply + maxlen - c,
43                                                  style);
44
45                 vector_foreach_slot(vecs->pathvec, pp, i)
46                         c += snprint_path(c, reply + maxlen - c,
47                                           style, pp);
48
49                 again = ((c - reply) == (maxlen - 1));
50
51                 if (again)
52                         reply = REALLOC(reply, maxlen *= 2);
53
54         }
55         *r = reply;
56         *len = (int)(c - reply + 1);
57         return 0;
58 }
59
60 int
61 show_map_topology (char ** r, int * len, struct multipath * mpp)
62 {
63         char * c;
64         char * reply;
65         unsigned int maxlen = INITIAL_REPLY_LEN;
66         int again = 1;
67
68         reply = MALLOC(maxlen);
69
70         while (again) {
71                 if (!reply)
72                         return 1;
73
74                 c = reply;
75
76                 c += snprint_multipath_topology(c, reply + maxlen - c, mpp, 2);
77                 again = ((c - reply) == (maxlen - 1));
78
79                 if (again)
80                         reply = REALLOC(reply, maxlen *= 2);
81
82         }
83         *r = reply;
84         *len = (int)(c - reply + 1);
85         return 0;
86 }
87
88 int
89 show_maps_topology (char ** r, int * len, struct vectors * vecs)
90 {
91         int i;
92         struct multipath * mpp;
93         char * c;
94         char * reply;
95         unsigned int maxlen = INITIAL_REPLY_LEN;
96         int again = 1;
97  
98         get_path_layout(vecs->pathvec, 0);
99         reply = MALLOC(maxlen);
100
101         while (again) {
102                 if (!reply)
103                         return 1;
104
105                 c = reply;
106
107                 vector_foreach_slot(vecs->mpvec, mpp, i)
108                         c += snprint_multipath_topology(c, reply + maxlen - c,
109                                                         mpp, 2);
110
111                 again = ((c - reply) == (maxlen - 1));
112
113                 if (again)
114                         reply = REALLOC(reply, maxlen *= 2);
115
116         }
117         *r = reply;
118         *len = (int)(c - reply + 1);
119         return 0;
120 }
121
122 int
123 show_config (char ** r, int * len)
124 {
125         char * c;
126         char * reply;
127         unsigned int maxlen = INITIAL_REPLY_LEN;
128         int again = 1;
129
130         reply = MALLOC(maxlen);
131
132         while (again) {
133                 if (!reply)
134                         return 1;
135                 c = reply;
136                 c += snprint_defaults(c, reply + maxlen - c);
137                 again = ((c - reply) == maxlen);
138                 if (again) {
139                         reply = REALLOC(reply, maxlen *= 2);
140                         continue;
141                 }
142                 c += snprint_blacklist(c, reply + maxlen - c);
143                 again = ((c - reply) == maxlen);
144                 if (again) {
145                         reply = REALLOC(reply, maxlen *= 2);
146                         continue;
147                 }
148                 c += snprint_blacklist_except(c, reply + maxlen - c);
149                 again = ((c - reply) == maxlen);
150                 if (again) {
151                         reply = REALLOC(reply, maxlen *= 2);
152                         continue;
153                 }
154                 c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable);
155                 again = ((c - reply) == maxlen);
156                 if (again) {
157                         reply = REALLOC(reply, maxlen *= 2);
158                         continue;
159                 }
160                 c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
161                 again = ((c - reply) == maxlen);
162                 if (again)
163                         reply = REALLOC(reply, maxlen *= 2);
164         }
165         *r = reply;
166         *len = (int)(c - reply + 1);
167         return 0;
168 }
169
170 int
171 cli_list_config (void * v, char ** reply, int * len, void * data)
172 {
173         condlog(3, "list config (operator)");
174
175         return show_config(reply, len);
176 }
177
178 int
179 cli_list_paths (void * v, char ** reply, int * len, void * data)
180 {
181         struct vectors * vecs = (struct vectors *)data;
182
183         condlog(3, "list paths (operator)");
184
185         return show_paths(reply, len, vecs, PRINT_PATH_CHECKER);
186 }
187
188 int
189 cli_list_paths_fmt (void * v, char ** reply, int * len, void * data)
190 {
191         struct vectors * vecs = (struct vectors *)data;
192         char * fmt = get_keyparam(v, FMT);
193
194         condlog(3, "list paths (operator)");
195
196         return show_paths(reply, len, vecs, fmt);
197 }
198
199 int
200 cli_list_map_topology (void * v, char ** reply, int * len, void * data)
201 {
202         struct multipath * mpp;
203         struct vectors * vecs = (struct vectors *)data;
204         char * param = get_keyparam(v, MAP);
205         
206         get_path_layout(vecs->pathvec, 0);
207         mpp = find_mp_by_str(vecs->mpvec, param);
208
209         if (!mpp)
210                 return 1;
211
212         condlog(3, "list multipath %s (operator)", param);
213
214         return show_map_topology(reply, len, mpp);
215 }
216
217 int
218 cli_list_maps_topology (void * v, char ** reply, int * len, void * data)
219 {
220         struct vectors * vecs = (struct vectors *)data;
221
222         condlog(3, "list multipaths (operator)");
223
224         return show_maps_topology(reply, len, vecs);
225 }
226
227 int
228 cli_list_wildcards (void * v, char ** reply, int * len, void * data)
229 {
230         char * c;
231
232         *reply = MALLOC(INITIAL_REPLY_LEN);
233
234         if (!*reply)
235                 return 1;
236
237         c = *reply;
238         c += snprint_wildcards(c, INITIAL_REPLY_LEN);
239
240         *len = INITIAL_REPLY_LEN;
241         return 0;
242 }
243
244 int
245 show_status (char ** r, int *len, struct vectors * vecs)
246 {
247         char * c;
248         char * reply;
249
250         unsigned int maxlen = INITIAL_REPLY_LEN;
251         reply = MALLOC(maxlen);
252
253         if (!reply)
254                 return 1;
255
256         c = reply;
257         c += snprint_status(c, reply + maxlen - c, vecs);
258
259         *r = reply;
260         *len = (int)(c - reply + 1);
261         return 0;
262 }
263
264 int
265 show_maps (char ** r, int *len, struct vectors * vecs, char * style)
266 {
267         int i;
268         struct multipath * mpp;
269         char * c;
270         char * reply;
271         unsigned int maxlen = INITIAL_REPLY_LEN;
272         int again = 1;
273
274         get_multipath_layout(vecs->mpvec, 1);
275         reply = MALLOC(maxlen);
276
277         while (again) {
278                 if (!reply)
279                         return 1;
280
281                 c = reply;
282                 if (VECTOR_SIZE(vecs->mpvec) > 0)
283                         c += snprint_multipath_header(c, reply + maxlen - c,
284                                                       style);
285
286                 vector_foreach_slot(vecs->mpvec, mpp, i)
287                         c += snprint_multipath(c, reply + maxlen - c,
288                                                style, mpp);
289
290                 again = ((c - reply) == (maxlen - 1));
291
292                 if (again)
293                         reply = REALLOC(reply, maxlen *= 2);
294         }
295         *r = reply;
296         *len = (int)(c - reply + 1);
297         return 0;
298 }
299
300 int
301 cli_list_maps_fmt (void * v, char ** reply, int * len, void * data)
302 {
303         struct vectors * vecs = (struct vectors *)data;
304         char * fmt = get_keyparam(v, FMT);
305
306         condlog(3, "list maps (operator)");
307
308         return show_maps(reply, len, vecs, fmt);
309 }
310
311 int
312 cli_list_maps (void * v, char ** reply, int * len, void * data)
313 {
314         struct vectors * vecs = (struct vectors *)data;
315
316         condlog(3, "list maps (operator)");
317
318         return show_maps(reply, len, vecs, PRINT_MAP_NAMES);
319 }
320
321 int
322 cli_list_status (void * v, char ** reply, int * len, void * data)
323 {
324         struct vectors * vecs = (struct vectors *)data;
325
326         condlog(3, "list status (operator)");
327
328         return show_status(reply, len, vecs);
329 }
330
331 int
332 cli_list_maps_status (void * v, char ** reply, int * len, void * data)
333 {
334         struct vectors * vecs = (struct vectors *)data;
335
336         condlog(3, "list maps status (operator)");
337
338         return show_maps(reply, len, vecs, PRINT_MAP_STATUS);
339 }
340
341 int
342 cli_list_maps_stats (void * v, char ** reply, int * len, void * data)
343 {
344         struct vectors * vecs = (struct vectors *)data;
345
346         condlog(3, "list maps stats (operator)");
347
348         return show_maps(reply, len, vecs, PRINT_MAP_STATS);
349 }
350
351 int
352 cli_add_path (void * v, char ** reply, int * len, void * data)
353 {
354         struct vectors * vecs = (struct vectors *)data;
355         char * param = get_keyparam(v, PATH);
356         int r;
357
358         condlog(2, "%s: add path (operator)", param);
359
360         if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
361             param) > 0 || (r = ev_add_path(param, vecs)) == 2) {
362                 *reply = strdup("blacklisted\n");
363                 *len = strlen(*reply) + 1;
364                 condlog(2, "%s: path blacklisted", param);
365                 return 0;
366         }
367         return r;
368 }
369
370 int
371 cli_del_path (void * v, char ** reply, int * len, void * data)
372 {
373         struct vectors * vecs = (struct vectors *)data;
374         char * param = get_keyparam(v, PATH);
375
376         condlog(2, "%s: remove path (operator)", param);
377
378         return ev_remove_path(param, vecs);
379 }
380
381 int
382 cli_add_map (void * v, char ** reply, int * len, void * data)
383 {
384         struct vectors * vecs = (struct vectors *)data;
385         char * param = get_keyparam(v, MAP);
386         int major, minor;
387         char dev_path[PATH_SIZE];
388         char *alias;
389         int rc;
390
391         condlog(2, "%s: add map (operator)", param);
392
393         if (filter_wwid(conf->blist_wwid, conf->elist_wwid, param) > 0) {
394                 *reply = strdup("blacklisted\n");
395                 *len = strlen(*reply) + 1;
396                 condlog(2, "%s: map blacklisted", param);
397                 return 0;
398         }
399         minor = dm_get_minor(param);
400         if (minor < 0) {
401                 condlog(2, "%s: not a device mapper table", param);
402                 return 0;
403         }
404         major = dm_get_major(param);
405         if (major < 0) {
406                 condlog(2, "%s: not a device mapper table", param);
407                 return 0;
408         }
409         sprintf(dev_path,"dm-%d", minor);
410         alias = dm_mapname(major, minor);
411         if (!alias) {
412                 condlog(2, "%s: mapname not found for %d:%d",
413                         param, major, minor);
414                 return 0;
415         }
416         rc = ev_add_map(dev_path, alias, vecs);
417         FREE(alias);
418         return rc;
419 }
420
421 int
422 cli_del_map (void * v, char ** reply, int * len, void * data)
423 {
424         struct vectors * vecs = (struct vectors *)data;
425         char * param = get_keyparam(v, MAP);
426         int major, minor;
427         char dev_path[PATH_SIZE];
428         char *alias;
429         int rc;
430
431         condlog(2, "%s: remove map (operator)", param);
432         minor = dm_get_minor(param);
433         if (minor < 0) {
434                 condlog(2, "%s: not a device mapper table", param);
435                 return 0;
436         }
437         major = dm_get_major(param);
438         if (major < 0) {
439                 condlog(2, "%s: not a device mapper table", param);
440                 return 0;
441         }
442         sprintf(dev_path,"dm-%d", minor);
443         alias = dm_mapname(major, minor);
444         if (!alias) {
445                 condlog(2, "%s: mapname not found for %d:%d",
446                         param, major, minor);
447                 return 0;
448         }
449         rc = ev_remove_map(param, alias, minor, vecs);
450         FREE(alias);
451         return rc;
452 }
453
454 int resize_map(struct multipath *mpp, unsigned long long size,
455                struct vectors * vecs)
456 {
457         char params[PARAMS_SIZE] = {0};
458
459         mpp->size = size;
460         update_mpp_paths(mpp, vecs->pathvec);
461         setup_map(mpp, params, PARAMS_SIZE);
462         mpp->action = ACT_RESIZE;
463         if (domap(mpp, params) <= 0) {
464                 condlog(0, "%s: failed to resize map : %s", mpp->alias,
465                         strerror(errno));
466                 return 1;
467         }
468         return 0;
469 }
470
471 int
472 cli_resize(void *v, char **reply, int *len, void *data)
473 {
474         struct vectors * vecs = (struct vectors *)data;
475         char * mapname = get_keyparam(v, MAP);
476         struct multipath *mpp;
477         int minor;
478         unsigned long long size;
479         struct pathgroup *pgp;
480         struct path *pp;
481
482         condlog(2, "%s: resize map (operator)", mapname);
483         if (sscanf(mapname, "dm-%d", &minor) == 1)
484                 mpp = find_mp_by_minor(vecs->mpvec, minor);
485         else
486                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
487
488         if (!mpp) {
489                 condlog(0, "%s: invalid map name. cannot resize", mapname);
490                 return 1;
491         }
492
493         pgp = VECTOR_SLOT(mpp->pg, 0);
494         pp = VECTOR_SLOT(pgp->paths, 0);
495         if (sysfs_get_size(pp->sysdev, &size)) {
496                 condlog(0, "%s: couldn't get size for sysfs. cannot resize",
497                         mapname);
498                 return 1;
499         }
500         if (size == mpp->size) {
501                 condlog(0, "%s: map is still the same size (%llu)", mapname,
502                         mpp->size);
503                 return 0;
504         }
505         condlog(3, "%s old size is %llu, new size is %llu", mapname, mpp->size,
506                 size);
507
508         if (resize_map(mpp, size, vecs) != 0)
509                 return 1;
510
511         dm_lib_release();
512         setup_multipath(vecs, mpp);
513         sync_map_state(mpp);
514
515         return 0;
516 }
517
518 int
519 cli_restore_queueing(void *v, char **reply, int *len, void *data)
520 {
521         struct vectors * vecs = (struct vectors *)data;
522         char * mapname = get_keyparam(v, MAP);
523         struct multipath *mpp;
524         int minor;
525
526         condlog(2, "%s: restore map queueing (operator)", mapname);
527         if (sscanf(mapname, "dm-%d", &minor) == 1)
528                 mpp = find_mp_by_minor(vecs->mpvec, minor);
529         else
530                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
531
532         if (!mpp) {
533                 condlog(0, "%s: invalid map name, cannot restore queueing", mapname);
534                 return 1;
535         }
536
537         if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
538                         mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
539                 dm_queue_if_no_path(mpp->alias, 1);
540                 if (mpp->nr_active > 0)
541                         mpp->retry_tick = 0;
542                 else
543                         mpp->retry_tick = mpp->no_path_retry * conf->checkint;
544         }
545         return 0;
546 }
547
548 int
549 cli_restore_all_queueing(void *v, char **reply, int *len, void *data)
550 {
551         struct vectors * vecs = (struct vectors *)data;
552         struct multipath *mpp;
553         int i;
554
555         condlog(2, "restore queueing (operator)");
556         vector_foreach_slot(vecs->mpvec, mpp, i) {
557                 if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
558                     mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
559                         dm_queue_if_no_path(mpp->alias, 1);
560                         if (mpp->nr_active > 0)
561                                 mpp->retry_tick = 0;
562                         else
563                                 mpp->retry_tick = mpp->no_path_retry * conf->checkint;
564                 }
565         }
566         return 0;
567 }
568
569 int
570 cli_disable_queueing(void *v, char **reply, int *len, void *data)
571 {
572         struct vectors * vecs = (struct vectors *)data;
573         char * mapname = get_keyparam(v, MAP);
574         struct multipath *mpp;
575         int minor;
576
577         condlog(2, "%s: disable map queueing (operator)", mapname);
578         if (sscanf(mapname, "dm-%d", &minor) == 1)
579                 mpp = find_mp_by_minor(vecs->mpvec, minor);
580         else
581                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
582
583         if (!mpp) {
584                 condlog(0, "%s: invalid map name, cannot disable queueing", mapname);
585                 return 1;
586         }
587
588         mpp->retry_tick = 0;
589         dm_queue_if_no_path(mpp->alias, 0);
590         return 0;
591 }
592
593 int
594 cli_disable_all_queueing(void *v, char **reply, int *len, void *data)
595 {
596         struct vectors * vecs = (struct vectors *)data;
597         struct multipath *mpp;
598         int i;
599
600         condlog(2, "disable queueing (operator)");
601         vector_foreach_slot(vecs->mpvec, mpp, i) {
602                 mpp->retry_tick = 0;
603                 dm_queue_if_no_path(mpp->alias, 0);
604         }
605         return 0;
606 }
607
608 int
609 cli_switch_group(void * v, char ** reply, int * len, void * data)
610 {
611         char * mapname = get_keyparam(v, MAP);
612         int groupnum = atoi(get_keyparam(v, GROUP));
613
614         condlog(2, "%s: switch to path group #%i (operator)", mapname, groupnum);
615
616         return dm_switchgroup(mapname, groupnum);
617 }
618
619 int
620 cli_reconfigure(void * v, char ** reply, int * len, void * data)
621 {
622         struct vectors * vecs = (struct vectors *)data;
623
624         condlog(2, "reconfigure (operator)");
625
626         return reconfigure(vecs);
627 }
628
629 int
630 cli_suspend(void * v, char ** reply, int * len, void * data)
631 {
632         struct vectors * vecs = (struct vectors *)data;
633         char * param = get_keyparam(v, MAP);
634         int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param);
635
636         condlog(2, "%s: suspend (operator)", param);
637
638         if (!r) /* error */
639                 return 1;
640
641         struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
642
643         if (!mpp)
644                 return 1;
645
646         dm_get_info(param, &mpp->dmi);
647         return 0;
648 }
649
650 int
651 cli_resume(void * v, char ** reply, int * len, void * data)
652 {
653         struct vectors * vecs = (struct vectors *)data;
654         char * param = get_keyparam(v, MAP);
655         int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param);
656
657         condlog(2, "%s: resume (operator)", param);
658
659         if (!r) /* error */
660                 return 1;
661
662         struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
663
664         if (!mpp)
665                 return 1;
666
667         dm_get_info(param, &mpp->dmi);
668         return 0;
669 }
670
671 int
672 cli_reinstate(void * v, char ** reply, int * len, void * data)
673 {
674         struct vectors * vecs = (struct vectors *)data;
675         char * param = get_keyparam(v, PATH);
676         struct path * pp;
677
678         pp = find_path_by_dev(vecs->pathvec, param);
679
680         if (!pp)
681                  pp = find_path_by_devt(vecs->pathvec, param);
682
683         if (!pp || !pp->mpp || !pp->mpp->alias)
684                 return 1;
685
686         condlog(2, "%s: reinstate path %s (operator)",
687                 pp->mpp->alias, pp->dev_t);
688
689         checker_enable(&pp->checker);
690         return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
691 }
692
693 int
694 cli_fail(void * v, char ** reply, int * len, void * data)
695 {
696         struct vectors * vecs = (struct vectors *)data;
697         char * param = get_keyparam(v, PATH);
698         struct path * pp;
699         int r;
700
701         pp = find_path_by_dev(vecs->pathvec, param);
702
703         if (!pp)
704                  pp = find_path_by_devt(vecs->pathvec, param);
705
706         if (!pp || !pp->mpp || !pp->mpp->alias)
707                 return 1;
708
709         condlog(2, "%s: fail path %s (operator)",
710                 pp->mpp->alias, pp->dev_t);
711
712         r = dm_fail_path(pp->mpp->alias, pp->dev_t);
713         /*
714          * Suspend path checking to avoid auto-reinstating the path
715          */
716         if (!r)
717                 checker_disable(&pp->checker);
718         return r;
719 }
720
721 int
722 show_blacklist (char ** r, int * len)
723 {
724         char *c = NULL;
725         char *reply = NULL;
726         unsigned int maxlen = INITIAL_REPLY_LEN;
727         int again = 1;
728
729         while (again) {
730                 reply = MALLOC(maxlen);
731                 if (!reply)
732                         return 1;
733
734                 c = reply;
735                 c += snprint_blacklist_report(c, maxlen);
736                 again = ((c - reply) == maxlen);
737                 if (again) {
738                         maxlen  *= 2;
739                         FREE(reply);
740                         continue;
741                 }
742         }
743
744         *r = reply;
745         *len = (int)(c - reply + 1);
746
747         return 0;
748 }
749
750 int
751 cli_list_blacklist (void * v, char ** reply, int * len, void * data)
752 {
753         condlog(3, "list blacklist (operator)");
754
755         return show_blacklist(reply, len);
756 }
757
758 int
759 show_devices (char ** r, int * len, struct vectors *vecs)
760 {
761         char *c = NULL;
762         char *reply = NULL;
763         unsigned int maxlen = INITIAL_REPLY_LEN;
764         int again = 1;
765
766         while (again) {
767                 reply = MALLOC(maxlen);
768                 if (!reply)
769                         return 1;
770
771                 c = reply;
772                 c += snprint_devices(c, maxlen, vecs);
773                 again = ((c - reply) == maxlen);
774                 if (again) {
775                         maxlen  *= 2;
776                         FREE(reply);
777                         continue;
778                 }
779         }
780
781         *r = reply;
782         *len = (int)(c - reply + 1);
783
784         return 0;
785 }
786
787 int
788 cli_list_devices (void * v, char ** reply, int * len, void * data)
789 {
790         struct vectors * vecs = (struct vectors *)data;
791
792         condlog(3, "list devices (operator)");
793
794         return show_devices(reply, len, vecs);
795 }
796
797 int
798 cli_quit (void * v, char ** reply, int * len, void * data)
799 {
800         return 0;
801 }