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