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