mpathpersist: fix aptpl support
[multipath-tools/.git] / multipathd / cli_handlers.c
1 /*
2  * Copyright (c) 2005 Christophe Varoqui
3  */
4
5 #define _GNU_SOURCE
6
7 #include "checkers.h"
8 #include "memory.h"
9 #include "vector.h"
10 #include "structs.h"
11 #include "structs_vec.h"
12 #include <libdevmapper.h>
13 #include "devmapper.h"
14 #include "discovery.h"
15 #include "config.h"
16 #include "configure.h"
17 #include "blacklist.h"
18 #include "debug.h"
19 #include "dm-generic.h"
20 #include "print.h"
21 #include "sysfs.h"
22 #include <errno.h>
23 #include <libudev.h>
24 #include <mpath_persist.h>
25 #include "util.h"
26 #include "prkey.h"
27 #include "propsel.h"
28 #include "main.h"
29 #include "cli.h"
30 #include "uevent.h"
31 #include "foreign.h"
32 #include "cli_handlers.h"
33
34 int
35 show_paths (char ** r, int * len, struct vectors * vecs, char * style,
36             int pretty)
37 {
38         int i;
39         struct path * pp;
40         char * c;
41         char * reply, * header;
42         unsigned int maxlen = INITIAL_REPLY_LEN;
43         int again = 1;
44
45         get_path_layout(vecs->pathvec, 1);
46         foreign_path_layout();
47
48         reply = MALLOC(maxlen);
49
50         while (again) {
51                 if (!reply)
52                         return 1;
53
54                 c = reply;
55
56                 if (pretty)
57                         c += snprint_path_header(c, reply + maxlen - c,
58                                                  style);
59                 header = c;
60
61                 vector_foreach_slot(vecs->pathvec, pp, i)
62                         c += snprint_path(c, reply + maxlen - c,
63                                           style, pp, pretty);
64
65                 c += snprint_foreign_paths(c, reply + maxlen - c,
66                                            style, pretty);
67
68                 again = ((c - reply) == (maxlen - 1));
69
70                 REALLOC_REPLY(reply, again, maxlen);
71         }
72
73         if (pretty && c == header) {
74                 /* No output - clear header */
75                 *reply = '\0';
76                 c = reply;
77         }
78
79         *r = reply;
80         *len = (int)(c - reply + 1);
81         return 0;
82 }
83
84 int
85 show_path (char ** r, int * len, struct vectors * vecs, struct path *pp,
86            char * style)
87 {
88         char * c;
89         char * reply;
90         unsigned int maxlen = INITIAL_REPLY_LEN;
91         int again = 1;
92
93         get_path_layout(vecs->pathvec, 1);
94         reply = MALLOC(maxlen);
95
96         while (again) {
97                 if (!reply)
98                         return 1;
99
100                 c = reply;
101
102                 c += snprint_path(c, reply + maxlen - c, style, pp, 0);
103
104                 again = ((c - reply) == (maxlen - 1));
105
106                 REALLOC_REPLY(reply, again, maxlen);
107         }
108         *r = reply;
109         *len = (int)(c - reply + 1);
110         return 0;
111 }
112
113 int
114 show_map_topology (char ** r, int * len, struct multipath * mpp,
115                    struct vectors * vecs)
116 {
117         char * c;
118         char * reply;
119         unsigned int maxlen = INITIAL_REPLY_LEN;
120         int again = 1;
121
122         if (update_multipath(vecs, mpp->alias, 0))
123                 return 1;
124         reply = MALLOC(maxlen);
125
126         while (again) {
127                 if (!reply)
128                         return 1;
129
130                 c = reply;
131
132                 c += snprint_multipath_topology(c, reply + maxlen - c, mpp, 2);
133                 again = ((c - reply) == (maxlen - 1));
134
135                 REALLOC_REPLY(reply, again, maxlen);
136         }
137         *r = reply;
138         *len = (int)(c - reply + 1);
139         return 0;
140 }
141
142 int
143 show_maps_topology (char ** r, int * len, struct vectors * vecs)
144 {
145         int i;
146         struct multipath * mpp;
147         char * c;
148         char * reply;
149         unsigned int maxlen = INITIAL_REPLY_LEN;
150         int again = 1;
151
152         get_path_layout(vecs->pathvec, 0);
153         foreign_path_layout();
154
155         reply = MALLOC(maxlen);
156
157         while (again) {
158                 if (!reply)
159                         return 1;
160
161                 c = reply;
162
163                 vector_foreach_slot(vecs->mpvec, mpp, i) {
164                         if (update_multipath(vecs, mpp->alias, 0)) {
165                                 i--;
166                                 continue;
167                         }
168                         c += snprint_multipath_topology(c, reply + maxlen - c,
169                                                         mpp, 2);
170                 }
171                 c += snprint_foreign_topology(c, reply + maxlen - c, 2);
172
173                 again = ((c - reply) == (maxlen - 1));
174
175                 REALLOC_REPLY(reply, again, maxlen);
176         }
177
178         *r = reply;
179         *len = (int)(c - reply + 1);
180         return 0;
181 }
182
183 int
184 show_maps_json (char ** r, int * len, struct vectors * vecs)
185 {
186         int i;
187         struct multipath * mpp;
188         char * c;
189         char * reply;
190         unsigned int maxlen = INITIAL_REPLY_LEN;
191         int again = 1;
192
193         if (VECTOR_SIZE(vecs->mpvec) > 0)
194                 maxlen *= PRINT_JSON_MULTIPLIER * VECTOR_SIZE(vecs->mpvec);
195
196         vector_foreach_slot(vecs->mpvec, mpp, i) {
197                 if (update_multipath(vecs, mpp->alias, 0)) {
198                         return 1;
199                 }
200         }
201
202         reply = MALLOC(maxlen);
203
204         while (again) {
205                 if (!reply)
206                         return 1;
207
208                 c = reply;
209
210                 c += snprint_multipath_topology_json(c, maxlen, vecs);
211                 again = ((c - reply) == maxlen);
212
213                 REALLOC_REPLY(reply, again, maxlen);
214         }
215         *r = reply;
216         *len = (int)(c - reply);
217         return 0;
218 }
219
220 int
221 show_map_json (char ** r, int * len, struct multipath * mpp,
222                    struct vectors * vecs)
223 {
224         char * c;
225         char * reply;
226         unsigned int maxlen = INITIAL_REPLY_LEN;
227         int again = 1;
228
229         if (update_multipath(vecs, mpp->alias, 0))
230                 return 1;
231         reply = MALLOC(maxlen);
232
233         while (again) {
234                 if (!reply)
235                         return 1;
236
237                 c = reply;
238
239                 c += snprint_multipath_map_json(c, maxlen, mpp, 1);
240                 again = ((c - reply) == maxlen);
241
242                 REALLOC_REPLY(reply, again, maxlen);
243         }
244         *r = reply;
245         *len = (int)(c - reply);
246         return 0;
247 }
248
249 int
250 show_config (char ** r, int * len)
251 {
252         char * c;
253         char * reply;
254         unsigned int maxlen = INITIAL_REPLY_LEN;
255         int again = 1;
256         struct config *conf;
257         int fail = 0;
258
259         c = reply = MALLOC(maxlen);
260
261         conf = get_multipath_config();
262         pthread_cleanup_push(put_multipath_config, conf);
263         while (again) {
264                 if (!reply) {
265                         fail = 1;
266                         break;
267                 }
268                 c = reply;
269                 c += snprint_defaults(conf, c, reply + maxlen - c);
270                 again = ((c - reply) == maxlen);
271                 REALLOC_REPLY(reply, again, maxlen);
272                 if (again)
273                         continue;
274                 c += snprint_blacklist(conf, c, reply + maxlen - c);
275                 again = ((c - reply) == maxlen);
276                 REALLOC_REPLY(reply, again, maxlen);
277                 if (again)
278                         continue;
279                 c += snprint_blacklist_except(conf, c, reply + maxlen - c);
280                 again = ((c - reply) == maxlen);
281                 REALLOC_REPLY(reply, again, maxlen);
282                 if (again)
283                         continue;
284                 c += snprint_hwtable(conf, c, reply + maxlen - c,
285                                      conf->hwtable);
286                 again = ((c - reply) == maxlen);
287                 REALLOC_REPLY(reply, again, maxlen);
288                 if (again)
289                         continue;
290                 c += snprint_overrides(conf, c, reply + maxlen - c,
291                                        conf->overrides);
292                 again = ((c - reply) == maxlen);
293                 REALLOC_REPLY(reply, again, maxlen);
294                 if (again)
295                         continue;
296                 if (VECTOR_SIZE(conf->mptable) > 0) {
297                         c += snprint_mptable(conf, c, reply + maxlen - c,
298                                              conf->mptable);
299                         again = ((c - reply) == maxlen);
300                         REALLOC_REPLY(reply, again, maxlen);
301                 }
302         }
303         pthread_cleanup_pop(1);
304         if (fail)
305                 return 1;
306         *r = reply;
307         *len = (int)(c - reply + 1);
308         return 0;
309 }
310
311 void
312 reset_stats(struct multipath * mpp)
313 {
314         mpp->stat_switchgroup = 0;
315         mpp->stat_path_failures = 0;
316         mpp->stat_map_loads = 0;
317         mpp->stat_total_queueing_time = 0;
318         mpp->stat_queueing_timeouts = 0;
319         mpp->stat_map_failures = 0;
320 }
321
322 int
323 cli_list_config (void * v, char ** reply, int * len, void * data)
324 {
325         condlog(3, "list config (operator)");
326
327         return show_config(reply, len);
328 }
329
330 int
331 cli_list_paths (void * v, char ** reply, int * len, void * data)
332 {
333         struct vectors * vecs = (struct vectors *)data;
334
335         condlog(3, "list paths (operator)");
336
337         return show_paths(reply, len, vecs, PRINT_PATH_CHECKER, 1);
338 }
339
340 int
341 cli_list_paths_fmt (void * v, char ** reply, int * len, void * data)
342 {
343         struct vectors * vecs = (struct vectors *)data;
344         char * fmt = get_keyparam(v, FMT);
345
346         condlog(3, "list paths (operator)");
347
348         return show_paths(reply, len, vecs, fmt, 1);
349 }
350
351 int
352 cli_list_paths_raw (void * v, char ** reply, int * len, void * data)
353 {
354         struct vectors * vecs = (struct vectors *)data;
355         char * fmt = get_keyparam(v, FMT);
356
357         condlog(3, "list paths (operator)");
358
359         return show_paths(reply, len, vecs, fmt, 0);
360 }
361
362 int
363 cli_list_path (void * v, char ** reply, int * len, void * data)
364 {
365         struct vectors * vecs = (struct vectors *)data;
366         char * param = get_keyparam(v, PATH);
367         struct path *pp;
368
369         param = convert_dev(param, 1);
370         condlog(3, "%s: list path (operator)", param);
371
372         pp = find_path_by_dev(vecs->pathvec, param);
373
374         return show_path(reply, len, vecs, pp, "%o");
375 }
376
377 int
378 cli_list_map_topology (void * v, char ** reply, int * len, void * data)
379 {
380         struct multipath * mpp;
381         struct vectors * vecs = (struct vectors *)data;
382         char * param = get_keyparam(v, MAP);
383
384         param = convert_dev(param, 0);
385         get_path_layout(vecs->pathvec, 0);
386         mpp = find_mp_by_str(vecs->mpvec, param);
387
388         if (!mpp)
389                 return 1;
390
391         condlog(3, "list multipath %s (operator)", param);
392
393         return show_map_topology(reply, len, mpp, vecs);
394 }
395
396 int
397 cli_list_maps_topology (void * v, char ** reply, int * len, void * data)
398 {
399         struct vectors * vecs = (struct vectors *)data;
400
401         condlog(3, "list multipaths (operator)");
402
403         return show_maps_topology(reply, len, vecs);
404 }
405
406 int
407 cli_list_map_json (void * v, char ** reply, int * len, void * data)
408 {
409         struct multipath * mpp;
410         struct vectors * vecs = (struct vectors *)data;
411         char * param = get_keyparam(v, MAP);
412
413         param = convert_dev(param, 0);
414         get_path_layout(vecs->pathvec, 0);
415         mpp = find_mp_by_str(vecs->mpvec, param);
416
417         if (!mpp)
418                 return 1;
419
420         condlog(3, "list multipath json %s (operator)", param);
421
422         return show_map_json(reply, len, mpp, vecs);
423 }
424
425 int
426 cli_list_maps_json (void * v, char ** reply, int * len, void * data)
427 {
428         struct vectors * vecs = (struct vectors *)data;
429
430         condlog(3, "list multipaths json (operator)");
431
432         return show_maps_json(reply, len, vecs);
433 }
434
435 int
436 cli_list_wildcards (void * v, char ** reply, int * len, void * data)
437 {
438         char * c;
439
440         *reply = MALLOC(INITIAL_REPLY_LEN);
441
442         if (!*reply)
443                 return 1;
444
445         c = *reply;
446         c += snprint_wildcards(c, INITIAL_REPLY_LEN);
447
448         *len = INITIAL_REPLY_LEN;
449         return 0;
450 }
451
452 int
453 show_status (char ** r, int *len, struct vectors * vecs)
454 {
455         char * c;
456         char * reply;
457
458         unsigned int maxlen = INITIAL_REPLY_LEN;
459         reply = MALLOC(maxlen);
460
461         if (!reply)
462                 return 1;
463
464         c = reply;
465         c += snprint_status(c, reply + maxlen - c, vecs);
466
467         *r = reply;
468         *len = (int)(c - reply + 1);
469         return 0;
470 }
471
472 int
473 show_daemon (char ** r, int *len)
474 {
475         char * c;
476         char * reply;
477
478         unsigned int maxlen = INITIAL_REPLY_LEN;
479         reply = MALLOC(maxlen);
480
481         if (!reply)
482                 return 1;
483
484         c = reply;
485         c += snprintf(c, INITIAL_REPLY_LEN, "pid %d %s\n",
486                       daemon_pid, daemon_status());
487
488         *r = reply;
489         *len = (int)(c - reply + 1);
490         return 0;
491 }
492
493 int
494 show_map (char ** r, int *len, struct multipath * mpp, char * style,
495           int pretty)
496 {
497         char * c;
498         char * reply;
499         unsigned int maxlen = INITIAL_REPLY_LEN;
500         int again = 1;
501
502         reply = MALLOC(maxlen);
503         while (again) {
504                 if (!reply)
505                         return 1;
506
507                 c = reply;
508                 c += snprint_multipath(c, reply + maxlen - c, style,
509                                        mpp, pretty);
510
511                 again = ((c - reply) == (maxlen - 1));
512
513                 REALLOC_REPLY(reply, again, maxlen);
514         }
515         *r = reply;
516         *len = (int)(c - reply + 1);
517         return 0;
518 }
519
520 int
521 show_maps (char ** r, int *len, struct vectors * vecs, char * style,
522            int pretty)
523 {
524         int i;
525         struct multipath * mpp;
526         char * c, *header;
527         char * reply;
528         unsigned int maxlen = INITIAL_REPLY_LEN;
529         int again = 1;
530
531         get_multipath_layout(vecs->mpvec, 1);
532         foreign_multipath_layout();
533
534         reply = MALLOC(maxlen);
535
536         while (again) {
537                 if (!reply)
538                         return 1;
539
540                 c = reply;
541                 if (pretty)
542                         c += snprint_multipath_header(c, reply + maxlen - c,
543                                                       style);
544                 header = c;
545
546                 vector_foreach_slot(vecs->mpvec, mpp, i) {
547                         if (update_multipath(vecs, mpp->alias, 0)) {
548                                 i--;
549                                 continue;
550                         }
551                         c += snprint_multipath(c, reply + maxlen - c,
552                                                style, mpp, pretty);
553
554                 }
555                 c += snprint_foreign_multipaths(c, reply + maxlen - c,
556                                                 style, pretty);
557                 again = ((c - reply) == (maxlen - 1));
558
559                 REALLOC_REPLY(reply, again, maxlen);
560         }
561
562         if (pretty && c == header) {
563                 /* No output - clear header */
564                 *reply = '\0';
565                 c = reply;
566         }
567         *r = reply;
568         *len = (int)(c - reply + 1);
569         return 0;
570 }
571
572 int
573 cli_list_maps_fmt (void * v, char ** reply, int * len, void * data)
574 {
575         struct vectors * vecs = (struct vectors *)data;
576         char * fmt = get_keyparam(v, FMT);
577
578         condlog(3, "list maps (operator)");
579
580         return show_maps(reply, len, vecs, fmt, 1);
581 }
582
583 int
584 cli_list_maps_raw (void * v, char ** reply, int * len, void * data)
585 {
586         struct vectors * vecs = (struct vectors *)data;
587         char * fmt = get_keyparam(v, FMT);
588
589         condlog(3, "list maps (operator)");
590
591         return show_maps(reply, len, vecs, fmt, 0);
592 }
593
594 int
595 cli_list_map_fmt (void * v, char ** reply, int * len, void * data)
596 {
597         struct multipath * mpp;
598         struct vectors * vecs = (struct vectors *)data;
599         char * param = get_keyparam(v, MAP);
600         char * fmt = get_keyparam(v, FMT);
601
602         param = convert_dev(param, 0);
603         get_path_layout(vecs->pathvec, 0);
604         get_multipath_layout(vecs->mpvec, 1);
605         mpp = find_mp_by_str(vecs->mpvec, param);
606         if (!mpp)
607                 return 1;
608
609         condlog(3, "list map %s fmt %s (operator)", param, fmt);
610
611         return show_map(reply, len, mpp, fmt, 1);
612 }
613
614 int
615 cli_list_map_raw (void * v, char ** reply, int * len, void * data)
616 {
617         struct multipath * mpp;
618         struct vectors * vecs = (struct vectors *)data;
619         char * param = get_keyparam(v, MAP);
620         char * fmt = get_keyparam(v, FMT);
621
622         param = convert_dev(param, 0);
623         get_path_layout(vecs->pathvec, 0);
624         get_multipath_layout(vecs->mpvec, 1);
625         mpp = find_mp_by_str(vecs->mpvec, param);
626         if (!mpp)
627                 return 1;
628
629         condlog(3, "list map %s fmt %s (operator)", param, fmt);
630
631         return show_map(reply, len, mpp, fmt, 0);
632 }
633
634 int
635 cli_list_maps (void * v, char ** reply, int * len, void * data)
636 {
637         struct vectors * vecs = (struct vectors *)data;
638
639         condlog(3, "list maps (operator)");
640
641         return show_maps(reply, len, vecs, PRINT_MAP_NAMES, 1);
642 }
643
644 int
645 cli_list_status (void * v, char ** reply, int * len, void * data)
646 {
647         struct vectors * vecs = (struct vectors *)data;
648
649         condlog(3, "list status (operator)");
650
651         return show_status(reply, len, vecs);
652 }
653
654 int
655 cli_list_maps_status (void * v, char ** reply, int * len, void * data)
656 {
657         struct vectors * vecs = (struct vectors *)data;
658
659         condlog(3, "list maps status (operator)");
660
661         return show_maps(reply, len, vecs, PRINT_MAP_STATUS, 1);
662 }
663
664 int
665 cli_list_maps_stats (void * v, char ** reply, int * len, void * data)
666 {
667         struct vectors * vecs = (struct vectors *)data;
668
669         condlog(3, "list maps stats (operator)");
670
671         return show_maps(reply, len, vecs, PRINT_MAP_STATS, 1);
672 }
673
674 int
675 cli_list_daemon (void * v, char ** reply, int * len, void * data)
676 {
677         condlog(3, "list daemon (operator)");
678
679         return show_daemon(reply, len);
680 }
681
682 int
683 cli_reset_maps_stats (void * v, char ** reply, int * len, void * data)
684 {
685         struct vectors * vecs = (struct vectors *)data;
686         int i;
687         struct multipath * mpp;
688
689         condlog(3, "reset multipaths stats (operator)");
690
691         vector_foreach_slot(vecs->mpvec, mpp, i) {
692                 reset_stats(mpp);
693         }
694         return 0;
695 }
696
697 int
698 cli_reset_map_stats (void * v, char ** reply, int * len, void * data)
699 {
700         struct vectors * vecs = (struct vectors *)data;
701         struct multipath * mpp;
702         char * param = get_keyparam(v, MAP);
703
704         param = convert_dev(param, 0);
705         mpp = find_mp_by_str(vecs->mpvec, param);
706
707         if (!mpp)
708                 return 1;
709
710         condlog(3, "reset multipath %s stats (operator)", param);
711         reset_stats(mpp);
712         return 0;
713 }
714
715 int
716 cli_add_path (void * v, char ** reply, int * len, void * data)
717 {
718         struct vectors * vecs = (struct vectors *)data;
719         char * param = get_keyparam(v, PATH);
720         struct path *pp;
721         int r;
722         struct config *conf;
723         int invalid = 0;
724
725         param = convert_dev(param, 1);
726         condlog(2, "%s: add path (operator)", param);
727         conf = get_multipath_config();
728         pthread_cleanup_push(put_multipath_config, conf);
729         if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
730                            param) > 0)
731                 invalid = 1;
732         pthread_cleanup_pop(1);
733         if (invalid)
734                 goto blacklisted;
735
736         pp = find_path_by_dev(vecs->pathvec, param);
737         if (pp) {
738                 condlog(2, "%s: path already in pathvec", param);
739                 if (pp->mpp)
740                         return 0;
741         } else {
742                 struct udev_device *udevice;
743
744                 udevice = udev_device_new_from_subsystem_sysname(udev,
745                                                                  "block",
746                                                                  param);
747                 conf = get_multipath_config();
748                 pthread_cleanup_push(put_multipath_config, conf);
749                 r = store_pathinfo(vecs->pathvec, conf,
750                                    udevice, DI_ALL, &pp);
751                 pthread_cleanup_pop(1);
752                 udev_device_unref(udevice);
753                 if (!pp) {
754                         if (r == 2)
755                                 goto blacklisted;
756                         condlog(0, "%s: failed to store path info", param);
757                         return 1;
758                 }
759                 pp->checkint = conf->checkint;
760         }
761         return ev_add_path(pp, vecs, 1);
762 blacklisted:
763         *reply = strdup("blacklisted\n");
764         *len = strlen(*reply) + 1;
765         condlog(2, "%s: path blacklisted", param);
766         return 0;
767 }
768
769 int
770 cli_del_path (void * v, char ** reply, int * len, void * data)
771 {
772         struct vectors * vecs = (struct vectors *)data;
773         char * param = get_keyparam(v, PATH);
774         struct path *pp;
775
776         param = convert_dev(param, 1);
777         condlog(2, "%s: remove path (operator)", param);
778         pp = find_path_by_dev(vecs->pathvec, param);
779         if (!pp) {
780                 condlog(0, "%s: path already removed", param);
781                 return 1;
782         }
783         return ev_remove_path(pp, vecs, 1);
784 }
785
786 int
787 cli_add_map (void * v, char ** reply, int * len, void * data)
788 {
789         struct vectors * vecs = (struct vectors *)data;
790         char * param = get_keyparam(v, MAP);
791         int major, minor;
792         char dev_path[PATH_SIZE];
793         char *refwwid, *alias = NULL;
794         int rc, count = 0;
795         struct config *conf;
796         int invalid = 0;
797
798         param = convert_dev(param, 0);
799         condlog(2, "%s: add map (operator)", param);
800
801         conf = get_multipath_config();
802         pthread_cleanup_push(put_multipath_config, conf);
803         if (filter_wwid(conf->blist_wwid, conf->elist_wwid, param, NULL) > 0)
804                 invalid = 1;
805         pthread_cleanup_pop(1);
806         if (invalid) {
807                 *reply = strdup("blacklisted\n");
808                 *len = strlen(*reply) + 1;
809                 condlog(2, "%s: map blacklisted", param);
810                 return 1;
811         }
812         do {
813                 if (dm_get_major_minor(param, &major, &minor) < 0)
814                         condlog(2, "%s: not a device mapper table", param);
815                 else {
816                         sprintf(dev_path, "dm-%d", minor);
817                         alias = dm_mapname(major, minor);
818                 }
819                 /*if there is no mapname found, we first create the device*/
820                 if (!alias && !count) {
821                         condlog(2, "%s: mapname not found for %d:%d",
822                                 param, major, minor);
823                         rc = get_refwwid(CMD_NONE, param, DEV_DEVMAP,
824                                          vecs->pathvec, &refwwid);
825                         if (refwwid) {
826                                 if (coalesce_paths(vecs, NULL, refwwid,
827                                                    FORCE_RELOAD_NONE, CMD_NONE))
828                                         condlog(2, "%s: coalesce_paths failed",
829                                                                         param);
830                                 dm_lib_release();
831                                 FREE(refwwid);
832                         }
833                 } /*we attempt to create device only once*/
834                 count++;
835         } while (!alias && (count < 2));
836
837         if (!alias) {
838                 condlog(2, "%s: add map failed", param);
839                 return 1;
840         }
841         rc = ev_add_map(dev_path, alias, vecs);
842         FREE(alias);
843         return rc;
844 }
845
846 int
847 cli_del_map (void * v, char ** reply, int * len, void * data)
848 {
849         struct vectors * vecs = (struct vectors *)data;
850         char * param = get_keyparam(v, MAP);
851         int major, minor;
852         char *alias;
853         int rc;
854
855         param = convert_dev(param, 0);
856         condlog(2, "%s: remove map (operator)", param);
857         if (dm_get_major_minor(param, &major, &minor) < 0) {
858                 condlog(2, "%s: not a device mapper table", param);
859                 return 1;
860         }
861         alias = dm_mapname(major, minor);
862         if (!alias) {
863                 condlog(2, "%s: mapname not found for %d:%d",
864                         param, major, minor);
865                 return 1;
866         }
867         rc = ev_remove_map(param, alias, minor, vecs);
868         FREE(alias);
869         return rc;
870 }
871
872 int
873 cli_reload(void *v, char **reply, int *len, void *data)
874 {
875         struct vectors * vecs = (struct vectors *)data;
876         char * mapname = get_keyparam(v, MAP);
877         struct multipath *mpp;
878         int minor;
879
880         mapname = convert_dev(mapname, 0);
881         condlog(2, "%s: reload map (operator)", mapname);
882         if (sscanf(mapname, "dm-%d", &minor) == 1)
883                 mpp = find_mp_by_minor(vecs->mpvec, minor);
884         else
885                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
886
887         if (!mpp) {
888                 condlog(0, "%s: invalid map name. cannot reload", mapname);
889                 return 1;
890         }
891         if (mpp->wait_for_udev) {
892                 condlog(2, "%s: device not fully created, failing reload",
893                         mpp->alias);
894                 return 1;
895         }
896
897         return reload_map(vecs, mpp, 0, 1);
898 }
899
900 int resize_map(struct multipath *mpp, unsigned long long size,
901                struct vectors * vecs)
902 {
903         char params[PARAMS_SIZE] = {0};
904         unsigned long long orig_size = mpp->size;
905
906         mpp->size = size;
907         update_mpp_paths(mpp, vecs->pathvec);
908         setup_map(mpp, params, PARAMS_SIZE, vecs);
909         mpp->action = ACT_RESIZE;
910         mpp->force_udev_reload = 1;
911         if (domap(mpp, params, 1) <= 0) {
912                 condlog(0, "%s: failed to resize map : %s", mpp->alias,
913                         strerror(errno));
914                 mpp->size = orig_size;
915                 return 1;
916         }
917         return 0;
918 }
919
920 int
921 cli_resize(void *v, char **reply, int *len, void *data)
922 {
923         struct vectors * vecs = (struct vectors *)data;
924         char * mapname = get_keyparam(v, MAP);
925         struct multipath *mpp;
926         int minor;
927         unsigned long long size;
928         struct pathgroup *pgp;
929         struct path *pp;
930
931         mapname = convert_dev(mapname, 0);
932         condlog(2, "%s: resize map (operator)", mapname);
933         if (sscanf(mapname, "dm-%d", &minor) == 1)
934                 mpp = find_mp_by_minor(vecs->mpvec, minor);
935         else
936                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
937
938         if (!mpp) {
939                 condlog(0, "%s: invalid map name. cannot resize", mapname);
940                 return 1;
941         }
942
943         if (mpp->wait_for_udev) {
944                 condlog(2, "%s: device not fully created, failing resize",
945                         mpp->alias);
946                 return 1;
947         }
948
949         pgp = VECTOR_SLOT(mpp->pg, 0);
950
951         if (!pgp){
952                 condlog(0, "%s: couldn't get path group. cannot resize",
953                         mapname);
954                 return 1;
955         }
956         pp = VECTOR_SLOT(pgp->paths, 0);
957
958         if (!pp){
959                 condlog(0, "%s: couldn't get path. cannot resize", mapname);
960                 return 1;
961         }
962         if (!pp->udev || sysfs_get_size(pp, &size)) {
963                 condlog(0, "%s: couldn't get size for sysfs. cannot resize",
964                         mapname);
965                 return 1;
966         }
967         if (size == mpp->size) {
968                 condlog(0, "%s: map is still the same size (%llu)", mapname,
969                         mpp->size);
970                 return 0;
971         }
972         condlog(3, "%s old size is %llu, new size is %llu", mapname, mpp->size,
973                 size);
974
975         if (resize_map(mpp, size, vecs) != 0)
976                 return 1;
977
978         dm_lib_release();
979         if (setup_multipath(vecs, mpp) != 0)
980                 return 1;
981         sync_map_state(mpp);
982
983         return 0;
984 }
985
986 int
987 cli_force_no_daemon_q(void * v, char ** reply, int * len, void * data)
988 {
989         struct config *conf;
990
991         condlog(2, "force queue_without_daemon (operator)");
992         conf = get_multipath_config();
993         if (conf->queue_without_daemon == QUE_NO_DAEMON_OFF)
994                 conf->queue_without_daemon = QUE_NO_DAEMON_FORCE;
995         put_multipath_config(conf);
996         return 0;
997 }
998
999 int
1000 cli_restore_no_daemon_q(void * v, char ** reply, int * len, void * data)
1001 {
1002         struct config *conf;
1003
1004         condlog(2, "restore queue_without_daemon (operator)");
1005         conf = get_multipath_config();
1006         if (conf->queue_without_daemon == QUE_NO_DAEMON_FORCE)
1007                 conf->queue_without_daemon = QUE_NO_DAEMON_OFF;
1008         put_multipath_config(conf);
1009         return 0;
1010 }
1011
1012 int
1013 cli_restore_queueing(void *v, char **reply, int *len, void *data)
1014 {
1015         struct vectors * vecs = (struct vectors *)data;
1016         char * mapname = get_keyparam(v, MAP);
1017         struct multipath *mpp;
1018         int minor;
1019         struct config *conf;
1020
1021         mapname = convert_dev(mapname, 0);
1022         condlog(2, "%s: restore map queueing (operator)", mapname);
1023         if (sscanf(mapname, "dm-%d", &minor) == 1)
1024                 mpp = find_mp_by_minor(vecs->mpvec, minor);
1025         else
1026                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
1027
1028         if (!mpp) {
1029                 condlog(0, "%s: invalid map name, cannot restore queueing", mapname);
1030                 return 1;
1031         }
1032
1033         mpp->disable_queueing = 0;
1034         conf = get_multipath_config();
1035         pthread_cleanup_push(put_multipath_config, conf);
1036         select_no_path_retry(conf, mpp);
1037         pthread_cleanup_pop(1);
1038
1039         if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
1040                         mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
1041                 dm_queue_if_no_path(mpp->alias, 1);
1042                 if (mpp->no_path_retry > 0) {
1043                         if (mpp->nr_active > 0)
1044                                 mpp->retry_tick = 0;
1045                         else
1046                                 enter_recovery_mode(mpp);
1047                 }
1048         }
1049         return 0;
1050 }
1051
1052 int
1053 cli_restore_all_queueing(void *v, char **reply, int *len, void *data)
1054 {
1055         struct vectors * vecs = (struct vectors *)data;
1056         struct multipath *mpp;
1057         int i;
1058
1059         condlog(2, "restore queueing (operator)");
1060         vector_foreach_slot(vecs->mpvec, mpp, i) {
1061                 mpp->disable_queueing = 0;
1062                 struct config *conf = get_multipath_config();
1063                 pthread_cleanup_push(put_multipath_config, conf);
1064                 select_no_path_retry(conf, mpp);
1065                 pthread_cleanup_pop(1);
1066                 if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
1067                     mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
1068                         dm_queue_if_no_path(mpp->alias, 1);
1069                         if (mpp->no_path_retry > 0) {
1070                                 if (mpp->nr_active > 0)
1071                                         mpp->retry_tick = 0;
1072                                 else
1073                                         enter_recovery_mode(mpp);
1074                         }
1075                 }
1076         }
1077         return 0;
1078 }
1079
1080 int
1081 cli_disable_queueing(void *v, char **reply, int *len, void *data)
1082 {
1083         struct vectors * vecs = (struct vectors *)data;
1084         char * mapname = get_keyparam(v, MAP);
1085         struct multipath *mpp;
1086         int minor;
1087
1088         mapname = convert_dev(mapname, 0);
1089         condlog(2, "%s: disable map queueing (operator)", mapname);
1090         if (sscanf(mapname, "dm-%d", &minor) == 1)
1091                 mpp = find_mp_by_minor(vecs->mpvec, minor);
1092         else
1093                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
1094
1095         if (!mpp) {
1096                 condlog(0, "%s: invalid map name, cannot disable queueing", mapname);
1097                 return 1;
1098         }
1099
1100         if (mpp->nr_active == 0)
1101                 mpp->stat_map_failures++;
1102         mpp->retry_tick = 0;
1103         mpp->no_path_retry = NO_PATH_RETRY_FAIL;
1104         mpp->disable_queueing = 1;
1105         dm_queue_if_no_path(mpp->alias, 0);
1106         return 0;
1107 }
1108
1109 int
1110 cli_disable_all_queueing(void *v, char **reply, int *len, void *data)
1111 {
1112         struct vectors * vecs = (struct vectors *)data;
1113         struct multipath *mpp;
1114         int i;
1115
1116         condlog(2, "disable queueing (operator)");
1117         vector_foreach_slot(vecs->mpvec, mpp, i) {
1118                 if (mpp->nr_active == 0)
1119                         mpp->stat_map_failures++;
1120                 mpp->retry_tick = 0;
1121                 mpp->no_path_retry = NO_PATH_RETRY_FAIL;
1122                 mpp->disable_queueing = 1;
1123                 dm_queue_if_no_path(mpp->alias, 0);
1124         }
1125         return 0;
1126 }
1127
1128 int
1129 cli_switch_group(void * v, char ** reply, int * len, void * data)
1130 {
1131         char * mapname = get_keyparam(v, MAP);
1132         int groupnum = atoi(get_keyparam(v, GROUP));
1133
1134         mapname = convert_dev(mapname, 0);
1135         condlog(2, "%s: switch to path group #%i (operator)", mapname, groupnum);
1136
1137         return dm_switchgroup(mapname, groupnum);
1138 }
1139
1140 int
1141 cli_reconfigure(void * v, char ** reply, int * len, void * data)
1142 {
1143         condlog(2, "reconfigure (operator)");
1144
1145         if (set_config_state(DAEMON_CONFIGURE) == ETIMEDOUT) {
1146                 condlog(2, "timeout starting reconfiguration");
1147                 return 1;
1148         }
1149         return 0;
1150 }
1151
1152 int
1153 cli_suspend(void * v, char ** reply, int * len, void * data)
1154 {
1155         struct vectors * vecs = (struct vectors *)data;
1156         char * param = get_keyparam(v, MAP);
1157         int r;
1158         struct multipath * mpp;
1159
1160         param = convert_dev(param, 0);
1161         mpp = find_mp_by_alias(vecs->mpvec, param);
1162         if (!mpp)
1163                 return 1;
1164
1165         if (mpp->wait_for_udev) {
1166                 condlog(2, "%s: device not fully created, failing suspend",
1167                         mpp->alias);
1168                 return 1;
1169         }
1170
1171         r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param, 0);
1172
1173         condlog(2, "%s: suspend (operator)", param);
1174
1175         if (!r) /* error */
1176                 return 1;
1177
1178         dm_get_info(param, &mpp->dmi);
1179         return 0;
1180 }
1181
1182 int
1183 cli_resume(void * v, char ** reply, int * len, void * data)
1184 {
1185         struct vectors * vecs = (struct vectors *)data;
1186         char * param = get_keyparam(v, MAP);
1187         int r;
1188         struct multipath * mpp;
1189         uint16_t udev_flags;
1190
1191         param = convert_dev(param, 0);
1192         mpp = find_mp_by_alias(vecs->mpvec, param);
1193         if (!mpp)
1194                 return 1;
1195
1196         udev_flags = (mpp->skip_kpartx)? MPATH_UDEV_NO_KPARTX_FLAG : 0;
1197         if (mpp->wait_for_udev) {
1198                 condlog(2, "%s: device not fully created, failing resume",
1199                         mpp->alias);
1200                 return 1;
1201         }
1202
1203         r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, udev_flags);
1204
1205         condlog(2, "%s: resume (operator)", param);
1206
1207         if (!r) /* error */
1208                 return 1;
1209
1210         dm_get_info(param, &mpp->dmi);
1211         return 0;
1212 }
1213
1214 int
1215 cli_reinstate(void * v, char ** reply, int * len, void * data)
1216 {
1217         struct vectors * vecs = (struct vectors *)data;
1218         char * param = get_keyparam(v, PATH);
1219         struct path * pp;
1220
1221         param = convert_dev(param, 1);
1222         pp = find_path_by_dev(vecs->pathvec, param);
1223
1224         if (!pp)
1225                  pp = find_path_by_devt(vecs->pathvec, param);
1226
1227         if (!pp || !pp->mpp || !pp->mpp->alias)
1228                 return 1;
1229
1230         condlog(2, "%s: reinstate path %s (operator)",
1231                 pp->mpp->alias, pp->dev_t);
1232
1233         checker_enable(&pp->checker);
1234         return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
1235 }
1236
1237 int
1238 cli_reassign (void * v, char ** reply, int * len, void * data)
1239 {
1240         struct vectors * vecs = (struct vectors *)data;
1241         char * param = get_keyparam(v, MAP);
1242         struct multipath *mpp;
1243
1244         param = convert_dev(param, 0);
1245         mpp = find_mp_by_alias(vecs->mpvec, param);
1246         if (!mpp)
1247                 return 1;
1248
1249         if (mpp->wait_for_udev) {
1250                 condlog(2, "%s: device not fully created, failing reassign",
1251                         mpp->alias);
1252                 return 1;
1253         }
1254
1255         condlog(3, "%s: reset devices (operator)", param);
1256
1257         dm_reassign(param);
1258         return 0;
1259 }
1260
1261 int
1262 cli_fail(void * v, char ** reply, int * len, void * data)
1263 {
1264         struct vectors * vecs = (struct vectors *)data;
1265         char * param = get_keyparam(v, PATH);
1266         struct path * pp;
1267         int r;
1268
1269         param = convert_dev(param, 1);
1270         pp = find_path_by_dev(vecs->pathvec, param);
1271
1272         if (!pp)
1273                  pp = find_path_by_devt(vecs->pathvec, param);
1274
1275         if (!pp || !pp->mpp || !pp->mpp->alias)
1276                 return 1;
1277
1278         condlog(2, "%s: fail path %s (operator)",
1279                 pp->mpp->alias, pp->dev_t);
1280
1281         r = dm_fail_path(pp->mpp->alias, pp->dev_t);
1282         /*
1283          * Suspend path checking to avoid auto-reinstating the path
1284          */
1285         if (!r)
1286                 checker_disable(&pp->checker);
1287         return r;
1288 }
1289
1290 int
1291 show_blacklist (char ** r, int * len)
1292 {
1293         char *c = NULL;
1294         char *reply = NULL;
1295         unsigned int maxlen = INITIAL_REPLY_LEN;
1296         int again = 1;
1297         struct config *conf;
1298         int fail = 0;
1299
1300         reply = MALLOC(maxlen);
1301
1302         conf = get_multipath_config();
1303         pthread_cleanup_push(put_multipath_config, conf);
1304         while (again) {
1305                 if (!reply) {
1306                         fail = 1;
1307                         break;
1308                 }
1309
1310                 c = reply;
1311                 c += snprint_blacklist_report(conf, c, maxlen);
1312                 again = ((c - reply) == maxlen);
1313                 REALLOC_REPLY(reply, again, maxlen);
1314         }
1315         pthread_cleanup_pop(1);
1316
1317         if (fail)
1318                 return 1;
1319         *r = reply;
1320         *len = (int)(c - reply + 1);
1321         return 0;
1322 }
1323
1324 int
1325 cli_list_blacklist (void * v, char ** reply, int * len, void * data)
1326 {
1327         condlog(3, "list blacklist (operator)");
1328
1329         return show_blacklist(reply, len);
1330 }
1331
1332 int
1333 show_devices (char ** r, int * len, struct vectors *vecs)
1334 {
1335         char *c = NULL;
1336         char *reply = NULL;
1337         unsigned int maxlen = INITIAL_REPLY_LEN;
1338         int again = 1;
1339         struct config *conf;
1340         int fail = 0;
1341
1342         reply = MALLOC(maxlen);
1343
1344         conf = get_multipath_config();
1345         pthread_cleanup_push(put_multipath_config, conf);
1346         while (again) {
1347                 if (!reply) {
1348                         fail = 1;
1349                         break;
1350                 }
1351
1352                 c = reply;
1353                 c += snprint_devices(conf, c, maxlen, vecs);
1354                 again = ((c - reply) == maxlen);
1355                 REALLOC_REPLY(reply, again, maxlen);
1356         }
1357         pthread_cleanup_pop(1);
1358
1359         if (fail)
1360                 return 1;
1361         *r = reply;
1362         *len = (int)(c - reply + 1);
1363
1364         return 0;
1365 }
1366
1367 int
1368 cli_list_devices (void * v, char ** reply, int * len, void * data)
1369 {
1370         struct vectors * vecs = (struct vectors *)data;
1371
1372         condlog(3, "list devices (operator)");
1373
1374         return show_devices(reply, len, vecs);
1375 }
1376
1377 int
1378 cli_quit (void * v, char ** reply, int * len, void * data)
1379 {
1380         return 0;
1381 }
1382
1383 int
1384 cli_shutdown (void * v, char ** reply, int * len, void * data)
1385 {
1386         condlog(3, "shutdown (operator)");
1387         exit_daemon();
1388         return 0;
1389 }
1390
1391 int
1392 cli_getprstatus (void * v, char ** reply, int * len, void * data)
1393 {
1394         struct multipath * mpp;
1395         struct vectors * vecs = (struct vectors *)data;
1396         char * param = get_keyparam(v, MAP);
1397
1398         param = convert_dev(param, 0);
1399         get_path_layout(vecs->pathvec, 0);
1400         mpp = find_mp_by_str(vecs->mpvec, param);
1401
1402         if (!mpp)
1403                 return 1;
1404
1405         condlog(3, "%s: prflag = %u", param, (unsigned int)mpp->prflag);
1406
1407         *len = asprintf(reply, "%d", mpp->prflag);
1408         if (*len < 0)
1409                 return 1;
1410
1411         condlog(3, "%s: reply = %s", param, *reply);
1412
1413         return 0;
1414 }
1415
1416 int
1417 cli_setprstatus(void * v, char ** reply, int * len, void * data)
1418 {
1419         struct multipath * mpp;
1420         struct vectors * vecs = (struct vectors *)data;
1421         char * param = get_keyparam(v, MAP);
1422
1423         param = convert_dev(param, 0);
1424         get_path_layout(vecs->pathvec, 0);
1425         mpp = find_mp_by_str(vecs->mpvec, param);
1426
1427         if (!mpp)
1428                 return 1;
1429
1430         if (!mpp->prflag) {
1431                 mpp->prflag = 1;
1432                 condlog(2, "%s: prflag set", param);
1433         }
1434
1435
1436         return 0;
1437 }
1438
1439 int
1440 cli_unsetprstatus(void * v, char ** reply, int * len, void * data)
1441 {
1442         struct multipath * mpp;
1443         struct vectors * vecs = (struct vectors *)data;
1444         char * param = get_keyparam(v, MAP);
1445
1446         param = convert_dev(param, 0);
1447         get_path_layout(vecs->pathvec, 0);
1448         mpp = find_mp_by_str(vecs->mpvec, param);
1449
1450         if (!mpp)
1451                 return 1;
1452
1453         if (mpp->prflag) {
1454                 mpp->prflag = 0;
1455                 condlog(2, "%s: prflag unset", param);
1456         }
1457
1458         return 0;
1459 }
1460
1461 int
1462 cli_getprkey(void * v, char ** reply, int * len, void * data)
1463 {
1464         struct multipath * mpp;
1465         struct vectors * vecs = (struct vectors *)data;
1466         char *mapname = get_keyparam(v, MAP);
1467         char *flagstr = "";
1468
1469         mapname = convert_dev(mapname, 0);
1470         condlog(3, "%s: get persistent reservation key (operator)", mapname);
1471         mpp = find_mp_by_str(vecs->mpvec, mapname);
1472
1473         if (!mpp)
1474                 return 1;
1475
1476         *reply = malloc(20);
1477
1478         if (!get_be64(mpp->reservation_key)) {
1479                 sprintf(*reply, "none\n");
1480                 *len = strlen(*reply) + 1;
1481                 return 0;
1482         }
1483         if (mpp->sa_flags & MPATH_F_APTPL_MASK)
1484                 flagstr = ":aptpl";
1485         snprintf(*reply, 20, "0x%" PRIx64 "%s\n",
1486                  get_be64(mpp->reservation_key), flagstr);
1487         (*reply)[19] = '\0';
1488         *len = strlen(*reply) + 1;
1489         return 0;
1490 }
1491
1492 int
1493 cli_unsetprkey(void * v, char ** reply, int * len, void * data)
1494 {
1495         struct multipath * mpp;
1496         struct vectors * vecs = (struct vectors *)data;
1497         char *mapname = get_keyparam(v, MAP);
1498         int ret;
1499         struct config *conf;
1500
1501         mapname = convert_dev(mapname, 0);
1502         condlog(3, "%s: unset persistent reservation key (operator)", mapname);
1503         mpp = find_mp_by_str(vecs->mpvec, mapname);
1504
1505         if (!mpp)
1506                 return 1;
1507
1508         conf = get_multipath_config();
1509         pthread_cleanup_push(put_multipath_config, conf);
1510         ret = set_prkey(conf, mpp, 0, 0);
1511         pthread_cleanup_pop(1);
1512
1513         return ret;
1514 }
1515
1516 int
1517 cli_setprkey(void * v, char ** reply, int * len, void * data)
1518 {
1519         struct multipath * mpp;
1520         struct vectors * vecs = (struct vectors *)data;
1521         char *mapname = get_keyparam(v, MAP);
1522         char *keyparam = get_keyparam(v, KEY);
1523         uint64_t prkey;
1524         uint8_t flags;
1525         int ret;
1526         struct config *conf;
1527
1528         mapname = convert_dev(mapname, 0);
1529         condlog(3, "%s: set persistent reservation key (operator)", mapname);
1530         mpp = find_mp_by_str(vecs->mpvec, mapname);
1531
1532         if (!mpp)
1533                 return 1;
1534
1535         if (parse_prkey_flags(keyparam, &prkey, &flags) != 0) {
1536                 condlog(0, "%s: invalid prkey : '%s'", mapname, keyparam);
1537                 return 1;
1538         }
1539
1540         conf = get_multipath_config();
1541         pthread_cleanup_push(put_multipath_config, conf);
1542         ret = set_prkey(conf, mpp, prkey, flags);
1543         pthread_cleanup_pop(1);
1544
1545         return ret;
1546 }