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