multipathd: move recovery mode code to function
[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                         enter_recovery_mode(mpp);
1002         }
1003         return 0;
1004 }
1005
1006 int
1007 cli_restore_all_queueing(void *v, char **reply, int *len, void *data)
1008 {
1009         struct vectors * vecs = (struct vectors *)data;
1010         struct multipath *mpp;
1011         int i;
1012
1013         condlog(2, "restore queueing (operator)");
1014         vector_foreach_slot(vecs->mpvec, mpp, i) {
1015                 struct config *conf = get_multipath_config();
1016                 mpp->disable_queueing = 0;
1017                 select_no_path_retry(conf, mpp);
1018                 put_multipath_config(conf);
1019                 if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
1020                     mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
1021                         dm_queue_if_no_path(mpp->alias, 1);
1022                         if (mpp->nr_active > 0)
1023                                 mpp->retry_tick = 0;
1024                         else
1025                                 enter_recovery_mode(mpp);
1026                 }
1027         }
1028         return 0;
1029 }
1030
1031 int
1032 cli_disable_queueing(void *v, char **reply, int *len, void *data)
1033 {
1034         struct vectors * vecs = (struct vectors *)data;
1035         char * mapname = get_keyparam(v, MAP);
1036         struct multipath *mpp;
1037         int minor;
1038
1039         mapname = convert_dev(mapname, 0);
1040         condlog(2, "%s: disable map queueing (operator)", mapname);
1041         if (sscanf(mapname, "dm-%d", &minor) == 1)
1042                 mpp = find_mp_by_minor(vecs->mpvec, minor);
1043         else
1044                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
1045
1046         if (!mpp) {
1047                 condlog(0, "%s: invalid map name, cannot disable queueing", mapname);
1048                 return 1;
1049         }
1050
1051         if (mpp->nr_active == 0)
1052                 mpp->stat_map_failures++;
1053         mpp->retry_tick = 0;
1054         mpp->no_path_retry = NO_PATH_RETRY_FAIL;
1055         mpp->disable_queueing = 1;
1056         dm_queue_if_no_path(mpp->alias, 0);
1057         return 0;
1058 }
1059
1060 int
1061 cli_disable_all_queueing(void *v, char **reply, int *len, void *data)
1062 {
1063         struct vectors * vecs = (struct vectors *)data;
1064         struct multipath *mpp;
1065         int i;
1066
1067         condlog(2, "disable queueing (operator)");
1068         vector_foreach_slot(vecs->mpvec, mpp, i) {
1069                 if (mpp->nr_active == 0)
1070                         mpp->stat_map_failures++;
1071                 mpp->retry_tick = 0;
1072                 mpp->no_path_retry = NO_PATH_RETRY_FAIL;
1073                 mpp->disable_queueing = 1;
1074                 dm_queue_if_no_path(mpp->alias, 0);
1075         }
1076         return 0;
1077 }
1078
1079 int
1080 cli_switch_group(void * v, char ** reply, int * len, void * data)
1081 {
1082         char * mapname = get_keyparam(v, MAP);
1083         int groupnum = atoi(get_keyparam(v, GROUP));
1084
1085         mapname = convert_dev(mapname, 0);
1086         condlog(2, "%s: switch to path group #%i (operator)", mapname, groupnum);
1087
1088         return dm_switchgroup(mapname, groupnum);
1089 }
1090
1091 int
1092 cli_reconfigure(void * v, char ** reply, int * len, void * data)
1093 {
1094         condlog(2, "reconfigure (operator)");
1095
1096         if (set_config_state(DAEMON_CONFIGURE) == ETIMEDOUT) {
1097                 condlog(2, "timeout starting reconfiguration");
1098                 return 1;
1099         }
1100         return 0;
1101 }
1102
1103 int
1104 cli_suspend(void * v, char ** reply, int * len, void * data)
1105 {
1106         struct vectors * vecs = (struct vectors *)data;
1107         char * param = get_keyparam(v, MAP);
1108         int r;
1109         struct multipath * mpp;
1110
1111         param = convert_dev(param, 0);
1112         mpp = find_mp_by_alias(vecs->mpvec, param);
1113         if (!mpp)
1114                 return 1;
1115
1116         if (mpp->wait_for_udev) {
1117                 condlog(2, "%s: device not fully created, failing suspend",
1118                         mpp->alias);
1119                 return 1;
1120         }
1121
1122         r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param, 0);
1123
1124         condlog(2, "%s: suspend (operator)", param);
1125
1126         if (!r) /* error */
1127                 return 1;
1128
1129         dm_get_info(param, &mpp->dmi);
1130         return 0;
1131 }
1132
1133 int
1134 cli_resume(void * v, char ** reply, int * len, void * data)
1135 {
1136         struct vectors * vecs = (struct vectors *)data;
1137         char * param = get_keyparam(v, MAP);
1138         int r;
1139         struct multipath * mpp;
1140         uint16_t udev_flags;
1141
1142         param = convert_dev(param, 0);
1143         mpp = find_mp_by_alias(vecs->mpvec, param);
1144         if (!mpp)
1145                 return 1;
1146
1147         udev_flags = (mpp->skip_kpartx)? MPATH_UDEV_NO_KPARTX_FLAG : 0;
1148         if (mpp->wait_for_udev) {
1149                 condlog(2, "%s: device not fully created, failing resume",
1150                         mpp->alias);
1151                 return 1;
1152         }
1153
1154         r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, udev_flags);
1155
1156         condlog(2, "%s: resume (operator)", param);
1157
1158         if (!r) /* error */
1159                 return 1;
1160
1161         dm_get_info(param, &mpp->dmi);
1162         return 0;
1163 }
1164
1165 int
1166 cli_reinstate(void * v, char ** reply, int * len, void * data)
1167 {
1168         struct vectors * vecs = (struct vectors *)data;
1169         char * param = get_keyparam(v, PATH);
1170         struct path * pp;
1171
1172         param = convert_dev(param, 1);
1173         pp = find_path_by_dev(vecs->pathvec, param);
1174
1175         if (!pp)
1176                  pp = find_path_by_devt(vecs->pathvec, param);
1177
1178         if (!pp || !pp->mpp || !pp->mpp->alias)
1179                 return 1;
1180
1181         condlog(2, "%s: reinstate path %s (operator)",
1182                 pp->mpp->alias, pp->dev_t);
1183
1184         checker_enable(&pp->checker);
1185         return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
1186 }
1187
1188 int
1189 cli_reassign (void * v, char ** reply, int * len, void * data)
1190 {
1191         struct vectors * vecs = (struct vectors *)data;
1192         char * param = get_keyparam(v, MAP);
1193         struct multipath *mpp;
1194
1195         param = convert_dev(param, 0);
1196         mpp = find_mp_by_alias(vecs->mpvec, param);
1197         if (!mpp)
1198                 return 1;
1199
1200         if (mpp->wait_for_udev) {
1201                 condlog(2, "%s: device not fully created, failing reassign",
1202                         mpp->alias);
1203                 return 1;
1204         }
1205
1206         condlog(3, "%s: reset devices (operator)", param);
1207
1208         dm_reassign(param);
1209         return 0;
1210 }
1211
1212 int
1213 cli_fail(void * v, char ** reply, int * len, void * data)
1214 {
1215         struct vectors * vecs = (struct vectors *)data;
1216         char * param = get_keyparam(v, PATH);
1217         struct path * pp;
1218         int r;
1219
1220         param = convert_dev(param, 1);
1221         pp = find_path_by_dev(vecs->pathvec, param);
1222
1223         if (!pp)
1224                  pp = find_path_by_devt(vecs->pathvec, param);
1225
1226         if (!pp || !pp->mpp || !pp->mpp->alias)
1227                 return 1;
1228
1229         condlog(2, "%s: fail path %s (operator)",
1230                 pp->mpp->alias, pp->dev_t);
1231
1232         r = dm_fail_path(pp->mpp->alias, pp->dev_t);
1233         /*
1234          * Suspend path checking to avoid auto-reinstating the path
1235          */
1236         if (!r)
1237                 checker_disable(&pp->checker);
1238         return r;
1239 }
1240
1241 int
1242 show_blacklist (char ** r, int * len)
1243 {
1244         char *c = NULL;
1245         char *reply = NULL;
1246         unsigned int maxlen = INITIAL_REPLY_LEN;
1247         int again = 1;
1248         struct config *conf = get_multipath_config();
1249
1250         reply = MALLOC(maxlen);
1251
1252         while (again) {
1253                 if (!reply) {
1254                         put_multipath_config(conf);
1255                         return 1;
1256                 }
1257
1258                 c = reply;
1259                 c += snprint_blacklist_report(conf, c, maxlen);
1260                 again = ((c - reply) == maxlen);
1261                 REALLOC_REPLY(reply, again, maxlen);
1262         }
1263
1264         *r = reply;
1265         *len = (int)(c - reply + 1);
1266         put_multipath_config(conf);
1267
1268         return 0;
1269 }
1270
1271 int
1272 cli_list_blacklist (void * v, char ** reply, int * len, void * data)
1273 {
1274         condlog(3, "list blacklist (operator)");
1275
1276         return show_blacklist(reply, len);
1277 }
1278
1279 int
1280 show_devices (char ** r, int * len, struct vectors *vecs)
1281 {
1282         char *c = NULL;
1283         char *reply = NULL;
1284         unsigned int maxlen = INITIAL_REPLY_LEN;
1285         int again = 1;
1286         struct config *conf = get_multipath_config();
1287
1288         reply = MALLOC(maxlen);
1289
1290         while (again) {
1291                 if (!reply) {
1292                         put_multipath_config(conf);
1293                         return 1;
1294                 }
1295
1296                 c = reply;
1297                 c += snprint_devices(conf, c, maxlen, vecs);
1298                 again = ((c - reply) == maxlen);
1299                 REALLOC_REPLY(reply, again, maxlen);
1300         }
1301
1302         *r = reply;
1303         *len = (int)(c - reply + 1);
1304         put_multipath_config(conf);
1305
1306         return 0;
1307 }
1308
1309 int
1310 cli_list_devices (void * v, char ** reply, int * len, void * data)
1311 {
1312         struct vectors * vecs = (struct vectors *)data;
1313
1314         condlog(3, "list devices (operator)");
1315
1316         return show_devices(reply, len, vecs);
1317 }
1318
1319 int
1320 cli_quit (void * v, char ** reply, int * len, void * data)
1321 {
1322         return 0;
1323 }
1324
1325 int
1326 cli_shutdown (void * v, char ** reply, int * len, void * data)
1327 {
1328         condlog(3, "shutdown (operator)");
1329         exit_daemon();
1330         return 0;
1331 }
1332
1333 int
1334 cli_getprstatus (void * v, char ** reply, int * len, void * data)
1335 {
1336         struct multipath * mpp;
1337         struct vectors * vecs = (struct vectors *)data;
1338         char * param = get_keyparam(v, MAP);
1339
1340         param = convert_dev(param, 0);
1341         get_path_layout(vecs->pathvec, 0);
1342         mpp = find_mp_by_str(vecs->mpvec, param);
1343
1344         if (!mpp)
1345                 return 1;
1346
1347         condlog(3, "%s: prflag = %u", param, (unsigned int)mpp->prflag);
1348
1349         *len = asprintf(reply, "%d", mpp->prflag);
1350         if (*len < 0)
1351                 return 1;
1352
1353         condlog(3, "%s: reply = %s", param, *reply);
1354
1355         return 0;
1356 }
1357
1358 int
1359 cli_setprstatus(void * v, char ** reply, int * len, void * data)
1360 {
1361         struct multipath * mpp;
1362         struct vectors * vecs = (struct vectors *)data;
1363         char * param = get_keyparam(v, MAP);
1364
1365         param = convert_dev(param, 0);
1366         get_path_layout(vecs->pathvec, 0);
1367         mpp = find_mp_by_str(vecs->mpvec, param);
1368
1369         if (!mpp)
1370                 return 1;
1371
1372         if (!mpp->prflag) {
1373                 mpp->prflag = 1;
1374                 condlog(2, "%s: prflag set", param);
1375         }
1376
1377
1378         return 0;
1379 }
1380
1381 int
1382 cli_unsetprstatus(void * v, char ** reply, int * len, void * data)
1383 {
1384         struct multipath * mpp;
1385         struct vectors * vecs = (struct vectors *)data;
1386         char * param = get_keyparam(v, MAP);
1387
1388         param = convert_dev(param, 0);
1389         get_path_layout(vecs->pathvec, 0);
1390         mpp = find_mp_by_str(vecs->mpvec, param);
1391
1392         if (!mpp)
1393                 return 1;
1394
1395         if (mpp->prflag) {
1396                 mpp->prflag = 0;
1397                 condlog(2, "%s: prflag unset", param);
1398         }
1399
1400         return 0;
1401 }
1402
1403 int
1404 cli_getprkey(void * v, char ** reply, int * len, void * data)
1405 {
1406         struct multipath * mpp;
1407         struct vectors * vecs = (struct vectors *)data;
1408         char *mapname = get_keyparam(v, MAP);
1409
1410         mapname = convert_dev(mapname, 0);
1411         condlog(3, "%s: get persistent reservation key (operator)", mapname);
1412         mpp = find_mp_by_str(vecs->mpvec, mapname);
1413
1414         if (!mpp)
1415                 return 1;
1416
1417         *reply = malloc(20);
1418
1419         if (!get_be64(mpp->reservation_key)) {
1420                 sprintf(*reply, "none\n");
1421                 *len = strlen(*reply) + 1;
1422                 return 0;
1423         }
1424         snprintf(*reply, 20, "0x%" PRIx64 "\n",
1425                  get_be64(mpp->reservation_key));
1426         (*reply)[19] = '\0';
1427         *len = strlen(*reply) + 1;
1428         return 0;
1429 }
1430
1431 int
1432 cli_unsetprkey(void * v, char ** reply, int * len, void * data)
1433 {
1434         struct multipath * mpp;
1435         struct vectors * vecs = (struct vectors *)data;
1436         char *mapname = get_keyparam(v, MAP);
1437         int ret;
1438         struct config *conf;
1439
1440         mapname = convert_dev(mapname, 0);
1441         condlog(3, "%s: unset persistent reservation key (operator)", mapname);
1442         mpp = find_mp_by_str(vecs->mpvec, mapname);
1443
1444         if (!mpp)
1445                 return 1;
1446
1447         conf = get_multipath_config();
1448         ret = set_prkey(conf, mpp, 0);
1449         put_multipath_config(conf);
1450
1451         return ret;
1452 }
1453
1454 int
1455 cli_setprkey(void * v, char ** reply, int * len, void * data)
1456 {
1457         struct multipath * mpp;
1458         struct vectors * vecs = (struct vectors *)data;
1459         char *mapname = get_keyparam(v, MAP);
1460         char *keyparam = get_keyparam(v, KEY);
1461         uint64_t prkey;
1462         int ret;
1463         struct config *conf;
1464
1465         mapname = convert_dev(mapname, 0);
1466         condlog(3, "%s: set persistent reservation key (operator)", mapname);
1467         mpp = find_mp_by_str(vecs->mpvec, mapname);
1468
1469         if (!mpp)
1470                 return 1;
1471
1472         if (parse_prkey(keyparam, &prkey) != 0) {
1473                 condlog(0, "%s: invalid prkey : '%s'", mapname, keyparam);
1474                 return 1;
1475         }
1476
1477         conf = get_multipath_config();
1478         ret = set_prkey(conf, mpp, prkey);
1479         put_multipath_config(conf);
1480
1481         return ret;
1482 }