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