772531ecbd47991968fff3418389c0479185230c
[multipath-tools/.git] / multipathd / cli_handlers.c
1 /*
2  * Copyright (c) 2005 Christophe Varoqui
3  */
4 #include <checkers.h>
5 #include <memory.h>
6 #include <vector.h>
7 #include <structs.h>
8 #include <structs_vec.h>
9 #include <libdevmapper.h>
10 #include <devmapper.h>
11 #include <discovery.h>
12 #include <config.h>
13 #include <configure.h>
14 #include <blacklist.h>
15 #include <debug.h>
16 #include <print.h>
17 #include <sysfs.h>
18 #include <errno.h>
19 #include <libudev.h>
20 #include <util.h>
21
22 #include "main.h"
23 #include "cli.h"
24 #include "uevent.h"
25
26 #define REALLOC_REPLY(r, a, m)                                  \
27         do {                                                    \
28                 if ((a)) {                                      \
29                         (r) = REALLOC((r), (m) * 2);            \
30                         if ((r)) {                              \
31                                 memset((r) + (m), 0, (m));      \
32                                 (m) *= 2;                       \
33                         }                                       \
34                 }                                               \
35         } while (0)
36
37 int
38 show_paths (char ** r, int * len, struct vectors * vecs, char * style)
39 {
40         int i;
41         struct path * pp;
42         char * c;
43         char * reply;
44         unsigned int maxlen = INITIAL_REPLY_LEN;
45         int again = 1;
46
47         get_path_layout(vecs->pathvec, 1);
48         reply = MALLOC(maxlen);
49
50         while (again) {
51                 if (!reply)
52                         return 1;
53
54                 c = reply;
55
56                 if (VECTOR_SIZE(vecs->pathvec) > 0)
57                         c += snprint_path_header(c, reply + maxlen - c,
58                                                  style);
59
60                 vector_foreach_slot(vecs->pathvec, pp, i)
61                         c += snprint_path(c, reply + maxlen - c,
62                                           style, pp);
63
64                 again = ((c - reply) == (maxlen - 1));
65
66                 REALLOC_REPLY(reply, again, maxlen);
67         }
68         *r = reply;
69         *len = (int)(c - reply + 1);
70         return 0;
71 }
72
73 int
74 show_path (char ** r, int * len, struct vectors * vecs, struct path *pp,
75            char * style)
76 {
77         char * c;
78         char * reply;
79         unsigned int maxlen = INITIAL_REPLY_LEN;
80         int again = 1;
81
82         get_path_layout(vecs->pathvec, 1);
83         reply = MALLOC(maxlen);
84
85         while (again) {
86                 if (!reply)
87                         return 1;
88
89                 c = reply;
90
91                 c += snprint_path(c, reply + maxlen - c, style, pp);
92
93                 again = ((c - reply) == (maxlen - 1));
94
95                 REALLOC_REPLY(reply, again, maxlen);
96         }
97         *r = reply;
98         *len = (int)(c - reply + 1);
99         return 0;
100 }
101
102 int
103 show_map_topology (char ** r, int * len, struct multipath * mpp,
104                    struct vectors * vecs)
105 {
106         char * c;
107         char * reply;
108         unsigned int maxlen = INITIAL_REPLY_LEN;
109         int again = 1;
110
111         if (update_multipath(vecs, mpp->alias, 0))
112                 return 1;
113         reply = MALLOC(maxlen);
114
115         while (again) {
116                 if (!reply)
117                         return 1;
118
119                 c = reply;
120
121                 c += snprint_multipath_topology(c, reply + maxlen - c, mpp, 2);
122                 again = ((c - reply) == (maxlen - 1));
123
124                 REALLOC_REPLY(reply, again, maxlen);
125         }
126         *r = reply;
127         *len = (int)(c - reply + 1);
128         return 0;
129 }
130
131 int
132 show_maps_topology (char ** r, int * len, struct vectors * vecs)
133 {
134         int i;
135         struct multipath * mpp;
136         char * c;
137         char * reply;
138         unsigned int maxlen = INITIAL_REPLY_LEN;
139         int again = 1;
140  
141         get_path_layout(vecs->pathvec, 0);
142         reply = MALLOC(maxlen);
143
144         while (again) {
145                 if (!reply)
146                         return 1;
147
148                 c = reply;
149
150                 vector_foreach_slot(vecs->mpvec, mpp, i) {
151                         if (update_multipath(vecs, mpp->alias, 0)) {
152                                 i--;
153                                 continue;
154                         }
155                         c += snprint_multipath_topology(c, reply + maxlen - c,
156                                                         mpp, 2);
157                 }
158
159                 again = ((c - reply) == (maxlen - 1));
160
161                 REALLOC_REPLY(reply, again, maxlen);
162         }
163         *r = reply;
164         *len = (int)(c - reply + 1);
165         return 0;
166 }
167
168 int
169 show_config (char ** r, int * len)
170 {
171         char * c;
172         char * reply;
173         unsigned int maxlen = INITIAL_REPLY_LEN;
174         int again = 1;
175
176         reply = MALLOC(maxlen);
177
178         while (again) {
179                 if (!reply)
180                         return 1;
181                 c = reply;
182                 c += snprint_defaults(c, reply + maxlen - c);
183                 again = ((c - reply) == maxlen);
184                 if (again) {
185                         reply = REALLOC(reply, maxlen * 2);
186                         if (!reply)
187                                 return 1;
188                         memset(reply + maxlen, 0, maxlen);
189                         maxlen *= 2;
190                         continue;
191                 }
192                 c += snprint_blacklist(c, reply + maxlen - c);
193                 again = ((c - reply) == maxlen);
194                 if (again) {
195                         reply = REALLOC(reply, maxlen * 2);
196                         if (!reply)
197                                 return 1;
198                         memset(reply + maxlen, 0, maxlen);
199                         maxlen *= 2;
200                         continue;
201                 }
202                 c += snprint_blacklist_except(c, reply + maxlen - c);
203                 again = ((c - reply) == maxlen);
204                 if (again) {
205                         reply = REALLOC(reply, maxlen * 2);
206                         if (!reply)
207                                 return 1;
208                         memset(reply + maxlen, 0, maxlen);
209                         maxlen *= 2;
210                         continue;
211                 }
212                 c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable);
213                 again = ((c - reply) == maxlen);
214                 if (again) {
215                         reply = REALLOC(reply, maxlen * 2);
216                         if (!reply)
217                                 return 1;
218                         memset(reply + maxlen, 0, maxlen);
219                         maxlen *= 2;
220                         continue;
221                 }
222                 c += snprint_overrides(c, reply + maxlen - c, conf->overrides);
223                 again = ((c - reply) == maxlen);
224                 if (again) {
225                         reply = REALLOC(reply, maxlen * 2);
226                         if (!reply)
227                                 return 1;
228                         memset(reply + maxlen, 0, maxlen);
229                         maxlen *= 2;
230                         continue;
231                 }
232                 c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
233                 again = ((c - reply) == maxlen);
234                 REALLOC_REPLY(reply, again, maxlen);
235         }
236         *r = reply;
237         *len = (int)(c - reply + 1);
238         return 0;
239 }
240
241 int
242 cli_list_config (void * v, char ** reply, int * len, void * data)
243 {
244         condlog(3, "list config (operator)");
245
246         return show_config(reply, len);
247 }
248
249 int
250 cli_list_paths (void * v, char ** reply, int * len, void * data)
251 {
252         struct vectors * vecs = (struct vectors *)data;
253
254         condlog(3, "list paths (operator)");
255
256         return show_paths(reply, len, vecs, PRINT_PATH_CHECKER);
257 }
258
259 int
260 cli_list_paths_fmt (void * v, char ** reply, int * len, void * data)
261 {
262         struct vectors * vecs = (struct vectors *)data;
263         char * fmt = get_keyparam(v, FMT);
264
265         condlog(3, "list paths (operator)");
266
267         return show_paths(reply, len, vecs, fmt);
268 }
269
270 int
271 cli_list_path (void * v, char ** reply, int * len, void * data)
272 {
273         struct vectors * vecs = (struct vectors *)data;
274         char * param = get_keyparam(v, PATH);
275         struct path *pp;
276
277         param = convert_dev(param, 1);
278         condlog(3, "%s: list path (operator)", param);
279
280         pp = find_path_by_dev(vecs->pathvec, param);
281
282         return show_path(reply, len, vecs, pp, "%o");
283 }
284
285 int
286 cli_list_map_topology (void * v, char ** reply, int * len, void * data)
287 {
288         struct multipath * mpp;
289         struct vectors * vecs = (struct vectors *)data;
290         char * param = get_keyparam(v, MAP);
291         
292         param = convert_dev(param, 0);
293         get_path_layout(vecs->pathvec, 0);
294         mpp = find_mp_by_str(vecs->mpvec, param);
295
296         if (!mpp)
297                 return 1;
298
299         condlog(3, "list multipath %s (operator)", param);
300
301         return show_map_topology(reply, len, mpp, vecs);
302 }
303
304 int
305 cli_list_maps_topology (void * v, char ** reply, int * len, void * data)
306 {
307         struct vectors * vecs = (struct vectors *)data;
308
309         condlog(3, "list multipaths (operator)");
310
311         return show_maps_topology(reply, len, vecs);
312 }
313
314 int
315 cli_list_wildcards (void * v, char ** reply, int * len, void * data)
316 {
317         char * c;
318
319         *reply = MALLOC(INITIAL_REPLY_LEN);
320
321         if (!*reply)
322                 return 1;
323
324         c = *reply;
325         c += snprint_wildcards(c, INITIAL_REPLY_LEN);
326
327         *len = INITIAL_REPLY_LEN;
328         return 0;
329 }
330
331 int
332 show_status (char ** r, int *len, struct vectors * vecs)
333 {
334         char * c;
335         char * reply;
336
337         unsigned int maxlen = INITIAL_REPLY_LEN;
338         reply = MALLOC(maxlen);
339
340         if (!reply)
341                 return 1;
342
343         c = reply;
344         c += snprint_status(c, reply + maxlen - c, vecs);
345
346         *r = reply;
347         *len = (int)(c - reply + 1);
348         return 0;
349 }
350
351 int
352 show_daemon (char ** r, int *len)
353 {
354         char * c;
355         char * reply;
356
357         unsigned int maxlen = INITIAL_REPLY_LEN;
358         reply = MALLOC(maxlen);
359
360         if (!reply)
361                 return 1;
362
363         c = reply;
364         c += snprintf(c, INITIAL_REPLY_LEN, "pid %d %s\n",
365                       daemon_pid, daemon_status());
366
367         *r = reply;
368         *len = (int)(c - reply + 1);
369         return 0;
370 }
371
372 int
373 show_maps (char ** r, int *len, struct vectors * vecs, char * style)
374 {
375         int i;
376         struct multipath * mpp;
377         char * c;
378         char * reply;
379         unsigned int maxlen = INITIAL_REPLY_LEN;
380         int again = 1;
381
382         get_multipath_layout(vecs->mpvec, 1);
383         reply = MALLOC(maxlen);
384
385         while (again) {
386                 if (!reply)
387                         return 1;
388
389                 c = reply;
390                 if (VECTOR_SIZE(vecs->mpvec) > 0)
391                         c += snprint_multipath_header(c, reply + maxlen - c,
392                                                       style);
393
394                 vector_foreach_slot(vecs->mpvec, mpp, i)
395                         c += snprint_multipath(c, reply + maxlen - c,
396                                                style, mpp);
397
398                 again = ((c - reply) == (maxlen - 1));
399
400                 REALLOC_REPLY(reply, again, maxlen);
401         }
402         *r = reply;
403         *len = (int)(c - reply + 1);
404         return 0;
405 }
406
407 int
408 cli_list_maps_fmt (void * v, char ** reply, int * len, void * data)
409 {
410         struct vectors * vecs = (struct vectors *)data;
411         char * fmt = get_keyparam(v, FMT);
412
413         condlog(3, "list maps (operator)");
414
415         return show_maps(reply, len, vecs, fmt);
416 }
417
418 int
419 cli_list_maps (void * v, char ** reply, int * len, void * data)
420 {
421         struct vectors * vecs = (struct vectors *)data;
422
423         condlog(3, "list maps (operator)");
424
425         return show_maps(reply, len, vecs, PRINT_MAP_NAMES);
426 }
427
428 int
429 cli_list_status (void * v, char ** reply, int * len, void * data)
430 {
431         struct vectors * vecs = (struct vectors *)data;
432
433         condlog(3, "list status (operator)");
434
435         return show_status(reply, len, vecs);
436 }
437
438 int
439 cli_list_maps_status (void * v, char ** reply, int * len, void * data)
440 {
441         struct vectors * vecs = (struct vectors *)data;
442
443         condlog(3, "list maps status (operator)");
444
445         return show_maps(reply, len, vecs, PRINT_MAP_STATUS);
446 }
447
448 int
449 cli_list_maps_stats (void * v, char ** reply, int * len, void * data)
450 {
451         struct vectors * vecs = (struct vectors *)data;
452
453         condlog(3, "list maps stats (operator)");
454
455         return show_maps(reply, len, vecs, PRINT_MAP_STATS);
456 }
457
458 int
459 cli_list_daemon (void * v, char ** reply, int * len, void * data)
460 {
461         condlog(3, "list daemon (operator)");
462
463         return show_daemon(reply, len);
464 }
465
466 int
467 cli_add_path (void * v, char ** reply, int * len, void * data)
468 {
469         struct vectors * vecs = (struct vectors *)data;
470         char * param = get_keyparam(v, PATH);
471         struct path *pp;
472         int r;
473
474         param = convert_dev(param, 1);
475         condlog(2, "%s: add path (operator)", param);
476
477         if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
478                            param) > 0)
479                 goto blacklisted;
480
481         pp = find_path_by_dev(vecs->pathvec, param);
482         if (pp) {
483                 condlog(2, "%s: path already in pathvec", param);
484                 if (pp->mpp)
485                         return 0;
486         } else {
487                 struct udev_device *udevice;
488
489                 udevice = udev_device_new_from_subsystem_sysname(conf->udev,
490                                                                  "block",
491                                                                  param);
492                 r = store_pathinfo(vecs->pathvec, conf->hwtable,
493                                    udevice, DI_ALL, &pp);
494                 udev_device_unref(udevice);
495                 if (!pp) {
496                         if (r == 2)
497                                 goto blacklisted;
498                         condlog(0, "%s: failed to store path info", param);
499                         return 1;
500                 }
501                 pp->checkint = conf->checkint;
502         }
503         return ev_add_path(pp, vecs);
504 blacklisted:
505         *reply = strdup("blacklisted\n");
506         *len = strlen(*reply) + 1;
507         condlog(2, "%s: path blacklisted", param);
508         return 0;
509 }
510
511 int
512 cli_del_path (void * v, char ** reply, int * len, void * data)
513 {
514         struct vectors * vecs = (struct vectors *)data;
515         char * param = get_keyparam(v, PATH);
516         struct path *pp;
517
518         param = convert_dev(param, 1);
519         condlog(2, "%s: remove path (operator)", param);
520         pp = find_path_by_dev(vecs->pathvec, param);
521         if (!pp) {
522                 condlog(0, "%s: path already removed", param);
523                 return 0;
524         }
525         return ev_remove_path(pp, vecs);
526 }
527
528 int
529 cli_add_map (void * v, char ** reply, int * len, void * data)
530 {
531         struct vectors * vecs = (struct vectors *)data;
532         char * param = get_keyparam(v, MAP);
533         int major, minor;
534         char dev_path[PATH_SIZE];
535         char *alias;
536         int rc;
537
538         param = convert_dev(param, 0);
539         condlog(2, "%s: add map (operator)", param);
540
541         if (filter_wwid(conf->blist_wwid, conf->elist_wwid, param, NULL) > 0) {
542                 *reply = strdup("blacklisted\n");
543                 *len = strlen(*reply) + 1;
544                 condlog(2, "%s: map blacklisted", param);
545                 return 0;
546         }
547         minor = dm_get_minor(param);
548         if (minor < 0) {
549                 condlog(2, "%s: not a device mapper table", param);
550                 return 0;
551         }
552         major = dm_get_major(param);
553         if (major < 0) {
554                 condlog(2, "%s: not a device mapper table", param);
555                 return 0;
556         }
557         sprintf(dev_path,"dm-%d", minor);
558         alias = dm_mapname(major, minor);
559         if (!alias) {
560                 condlog(2, "%s: mapname not found for %d:%d",
561                         param, major, minor);
562                 return 0;
563         }
564         rc = ev_add_map(dev_path, alias, vecs);
565         FREE(alias);
566         return rc;
567 }
568
569 int
570 cli_del_map (void * v, char ** reply, int * len, void * data)
571 {
572         struct vectors * vecs = (struct vectors *)data;
573         char * param = get_keyparam(v, MAP);
574         int major, minor;
575         char dev_path[PATH_SIZE];
576         char *alias;
577         int rc;
578
579         param = convert_dev(param, 0);
580         condlog(2, "%s: remove map (operator)", param);
581         minor = dm_get_minor(param);
582         if (minor < 0) {
583                 condlog(2, "%s: not a device mapper table", param);
584                 return 0;
585         }
586         major = dm_get_major(param);
587         if (major < 0) {
588                 condlog(2, "%s: not a device mapper table", param);
589                 return 0;
590         }
591         sprintf(dev_path,"dm-%d", minor);
592         alias = dm_mapname(major, minor);
593         if (!alias) {
594                 condlog(2, "%s: mapname not found for %d:%d",
595                         param, major, minor);
596                 return 0;
597         }
598         rc = ev_remove_map(param, alias, minor, vecs);
599         FREE(alias);
600         return rc;
601 }
602
603 int
604 cli_reload(void *v, char **reply, int *len, void *data)
605 {
606         struct vectors * vecs = (struct vectors *)data;
607         char * mapname = get_keyparam(v, MAP);
608         struct multipath *mpp;
609         int minor;
610
611         mapname = convert_dev(mapname, 0);
612         condlog(2, "%s: reload map (operator)", mapname);
613         if (sscanf(mapname, "dm-%d", &minor) == 1)
614                 mpp = find_mp_by_minor(vecs->mpvec, minor);
615         else
616                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
617
618         if (!mpp) {
619                 condlog(0, "%s: invalid map name. cannot reload", mapname);
620                 return 1;
621         }
622
623         return reload_map(vecs, mpp, 0);
624 }
625
626 int resize_map(struct multipath *mpp, unsigned long long size,
627                struct vectors * vecs)
628 {
629         char params[PARAMS_SIZE] = {0};
630         unsigned long long orig_size = mpp->size;
631
632         mpp->size = size;
633         update_mpp_paths(mpp, vecs->pathvec);
634         setup_map(mpp, params, PARAMS_SIZE);
635         mpp->action = ACT_RESIZE;
636         if (domap(mpp, params) <= 0) {
637                 condlog(0, "%s: failed to resize map : %s", mpp->alias,
638                         strerror(errno));
639                 mpp->size = orig_size;
640                 return 1;
641         }
642         return 0;
643 }
644
645 int
646 cli_resize(void *v, char **reply, int *len, void *data)
647 {
648         struct vectors * vecs = (struct vectors *)data;
649         char * mapname = get_keyparam(v, MAP);
650         struct multipath *mpp;
651         int minor;
652         unsigned long long size;
653         struct pathgroup *pgp;
654         struct path *pp;
655
656         mapname = convert_dev(mapname, 0);
657         condlog(2, "%s: resize map (operator)", mapname);
658         if (sscanf(mapname, "dm-%d", &minor) == 1)
659                 mpp = find_mp_by_minor(vecs->mpvec, minor);
660         else
661                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
662
663         if (!mpp) {
664                 condlog(0, "%s: invalid map name. cannot resize", mapname);
665                 return 1;
666         }
667
668         pgp = VECTOR_SLOT(mpp->pg, 0);
669
670         if (!pgp){
671                 condlog(0, "%s: couldn't get path group. cannot resize",
672                         mapname);
673                 return 1;
674         }
675         pp = VECTOR_SLOT(pgp->paths, 0);
676
677         if (!pp){
678                 condlog(0, "%s: couldn't get path. cannot resize", mapname);
679                 return 1;
680         }
681         if (!pp->udev || sysfs_get_size(pp, &size)) {
682                 condlog(0, "%s: couldn't get size for sysfs. cannot resize",
683                         mapname);
684                 return 1;
685         }
686         if (size == mpp->size) {
687                 condlog(0, "%s: map is still the same size (%llu)", mapname,
688                         mpp->size);
689                 return 0;
690         }
691         condlog(3, "%s old size is %llu, new size is %llu", mapname, mpp->size,
692                 size);
693
694         if (resize_map(mpp, size, vecs) != 0)
695                 return 1;
696
697         dm_lib_release();
698         if (setup_multipath(vecs, mpp) != 0)
699                 return 1;
700         sync_map_state(mpp);
701
702         return 0;
703 }
704
705 int
706 cli_force_no_daemon_q(void * v, char ** reply, int * len, void * data)
707 {
708         condlog(2, "force queue_without_daemon (operator)");
709         if (conf->queue_without_daemon == QUE_NO_DAEMON_OFF)
710                 conf->queue_without_daemon = QUE_NO_DAEMON_FORCE;
711         return 0;
712 }
713
714 int
715 cli_restore_no_daemon_q(void * v, char ** reply, int * len, void * data)
716 {
717         condlog(2, "restore queue_without_daemon (operator)");
718         if (conf->queue_without_daemon == QUE_NO_DAEMON_FORCE)
719                 conf->queue_without_daemon = QUE_NO_DAEMON_OFF;
720         return 0;
721 }
722
723 int
724 cli_restore_queueing(void *v, char **reply, int *len, void *data)
725 {
726         struct vectors * vecs = (struct vectors *)data;
727         char * mapname = get_keyparam(v, MAP);
728         struct multipath *mpp;
729         int minor;
730
731         mapname = convert_dev(mapname, 0);
732         condlog(2, "%s: restore map queueing (operator)", mapname);
733         if (sscanf(mapname, "dm-%d", &minor) == 1)
734                 mpp = find_mp_by_minor(vecs->mpvec, minor);
735         else
736                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
737
738         if (!mpp) {
739                 condlog(0, "%s: invalid map name, cannot restore queueing", mapname);
740                 return 1;
741         }
742
743         if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
744                         mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
745                 dm_queue_if_no_path(mpp->alias, 1);
746                 if (mpp->nr_active > 0)
747                         mpp->retry_tick = 0;
748                 else
749                         mpp->retry_tick = mpp->no_path_retry * conf->checkint;
750         }
751         return 0;
752 }
753
754 int
755 cli_restore_all_queueing(void *v, char **reply, int *len, void *data)
756 {
757         struct vectors * vecs = (struct vectors *)data;
758         struct multipath *mpp;
759         int i;
760
761         condlog(2, "restore queueing (operator)");
762         vector_foreach_slot(vecs->mpvec, mpp, i) {
763                 if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
764                     mpp->no_path_retry != NO_PATH_RETRY_FAIL) {
765                         dm_queue_if_no_path(mpp->alias, 1);
766                         if (mpp->nr_active > 0)
767                                 mpp->retry_tick = 0;
768                         else
769                                 mpp->retry_tick = mpp->no_path_retry * conf->checkint;
770                 }
771         }
772         return 0;
773 }
774
775 int
776 cli_disable_queueing(void *v, char **reply, int *len, void *data)
777 {
778         struct vectors * vecs = (struct vectors *)data;
779         char * mapname = get_keyparam(v, MAP);
780         struct multipath *mpp;
781         int minor;
782
783         mapname = convert_dev(mapname, 0);
784         condlog(2, "%s: disable map queueing (operator)", mapname);
785         if (sscanf(mapname, "dm-%d", &minor) == 1)
786                 mpp = find_mp_by_minor(vecs->mpvec, minor);
787         else
788                 mpp = find_mp_by_alias(vecs->mpvec, mapname);
789
790         if (!mpp) {
791                 condlog(0, "%s: invalid map name, cannot disable queueing", mapname);
792                 return 1;
793         }
794
795         mpp->retry_tick = 0;
796         dm_queue_if_no_path(mpp->alias, 0);
797         return 0;
798 }
799
800 int
801 cli_disable_all_queueing(void *v, char **reply, int *len, void *data)
802 {
803         struct vectors * vecs = (struct vectors *)data;
804         struct multipath *mpp;
805         int i;
806
807         condlog(2, "disable queueing (operator)");
808         vector_foreach_slot(vecs->mpvec, mpp, i) {
809                 mpp->retry_tick = 0;
810                 dm_queue_if_no_path(mpp->alias, 0);
811         }
812         return 0;
813 }
814
815 int
816 cli_switch_group(void * v, char ** reply, int * len, void * data)
817 {
818         char * mapname = get_keyparam(v, MAP);
819         int groupnum = atoi(get_keyparam(v, GROUP));
820
821         mapname = convert_dev(mapname, 0);
822         condlog(2, "%s: switch to path group #%i (operator)", mapname, groupnum);
823
824         return dm_switchgroup(mapname, groupnum);
825 }
826
827 int
828 cli_reconfigure(void * v, char ** reply, int * len, void * data)
829 {
830         struct vectors * vecs = (struct vectors *)data;
831
832         condlog(2, "reconfigure (operator)");
833
834         return reconfigure(vecs);
835 }
836
837 int
838 cli_suspend(void * v, char ** reply, int * len, void * data)
839 {
840         struct vectors * vecs = (struct vectors *)data;
841         char * param = get_keyparam(v, MAP);
842         int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param, 0, 0);
843
844         param = convert_dev(param, 0);
845         condlog(2, "%s: suspend (operator)", param);
846
847         if (!r) /* error */
848                 return 1;
849
850         struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
851
852         if (!mpp)
853                 return 1;
854
855         dm_get_info(param, &mpp->dmi);
856         return 0;
857 }
858
859 int
860 cli_resume(void * v, char ** reply, int * len, void * data)
861 {
862         struct vectors * vecs = (struct vectors *)data;
863         char * param = get_keyparam(v, MAP);
864         int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, 0, 0);
865
866         param = convert_dev(param, 0);
867         condlog(2, "%s: resume (operator)", param);
868
869         if (!r) /* error */
870                 return 1;
871
872         struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
873
874         if (!mpp)
875                 return 1;
876
877         dm_get_info(param, &mpp->dmi);
878         return 0;
879 }
880
881 int
882 cli_reinstate(void * v, char ** reply, int * len, void * data)
883 {
884         struct vectors * vecs = (struct vectors *)data;
885         char * param = get_keyparam(v, PATH);
886         struct path * pp;
887
888         param = convert_dev(param, 1);
889         pp = find_path_by_dev(vecs->pathvec, param);
890
891         if (!pp)
892                  pp = find_path_by_devt(vecs->pathvec, param);
893
894         if (!pp || !pp->mpp || !pp->mpp->alias)
895                 return 1;
896
897         condlog(2, "%s: reinstate path %s (operator)",
898                 pp->mpp->alias, pp->dev_t);
899
900         checker_enable(&pp->checker);
901         return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
902 }
903
904 int
905 cli_reassign (void * v, char ** reply, int * len, void * data)
906 {
907         char * param = get_keyparam(v, MAP);
908
909         param = convert_dev(param, 0);
910         condlog(3, "%s: reset devices (operator)", param);
911
912         dm_reassign(param);
913         return 0;
914 }
915
916 int
917 cli_fail(void * v, char ** reply, int * len, void * data)
918 {
919         struct vectors * vecs = (struct vectors *)data;
920         char * param = get_keyparam(v, PATH);
921         struct path * pp;
922         int r;
923
924         param = convert_dev(param, 1);
925         pp = find_path_by_dev(vecs->pathvec, param);
926
927         if (!pp)
928                  pp = find_path_by_devt(vecs->pathvec, param);
929
930         if (!pp || !pp->mpp || !pp->mpp->alias)
931                 return 1;
932
933         condlog(2, "%s: fail path %s (operator)",
934                 pp->mpp->alias, pp->dev_t);
935
936         r = dm_fail_path(pp->mpp->alias, pp->dev_t);
937         /*
938          * Suspend path checking to avoid auto-reinstating the path
939          */
940         if (!r)
941                 checker_disable(&pp->checker);
942         return r;
943 }
944
945 int
946 show_blacklist (char ** r, int * len)
947 {
948         char *c = NULL;
949         char *reply = NULL;
950         unsigned int maxlen = INITIAL_REPLY_LEN;
951         int again = 1;
952
953         reply = MALLOC(maxlen);
954
955         while (again) {
956                 if (!reply)
957                         return 1;
958
959                 c = reply;
960                 c += snprint_blacklist_report(c, maxlen);
961                 again = ((c - reply) == maxlen);
962                 REALLOC_REPLY(reply, again, maxlen);
963         }
964
965         *r = reply;
966         *len = (int)(c - reply + 1);
967
968         return 0;
969 }
970
971 int
972 cli_list_blacklist (void * v, char ** reply, int * len, void * data)
973 {
974         condlog(3, "list blacklist (operator)");
975
976         return show_blacklist(reply, len);
977 }
978
979 int
980 show_devices (char ** r, int * len, struct vectors *vecs)
981 {
982         char *c = NULL;
983         char *reply = NULL;
984         unsigned int maxlen = INITIAL_REPLY_LEN;
985         int again = 1;
986
987         reply = MALLOC(maxlen);
988
989         while (again) {
990                 if (!reply)
991                         return 1;
992
993                 c = reply;
994                 c += snprint_devices(c, maxlen, vecs);
995                 again = ((c - reply) == maxlen);
996                 REALLOC_REPLY(reply, again, maxlen);
997         }
998
999         *r = reply;
1000         *len = (int)(c - reply + 1);
1001
1002         return 0;
1003 }
1004
1005 int
1006 cli_list_devices (void * v, char ** reply, int * len, void * data)
1007 {
1008         struct vectors * vecs = (struct vectors *)data;
1009
1010         condlog(3, "list devices (operator)");
1011
1012         return show_devices(reply, len, vecs);
1013 }
1014
1015 int
1016 cli_quit (void * v, char ** reply, int * len, void * data)
1017 {
1018         return 0;
1019 }
1020
1021 int
1022 cli_shutdown (void * v, char ** reply, int * len, void * data)
1023 {
1024         condlog(3, "shutdown (operator)");
1025         exit_daemon();
1026         return 0;
1027 }
1028
1029 int
1030 cli_getprstatus (void * v, char ** reply, int * len, void * data)
1031 {
1032         struct multipath * mpp;
1033         struct vectors * vecs = (struct vectors *)data;
1034         char * param = get_keyparam(v, MAP);
1035
1036         param = convert_dev(param, 0);
1037         get_path_layout(vecs->pathvec, 0);
1038         mpp = find_mp_by_str(vecs->mpvec, param);
1039
1040         if (!mpp)
1041                 return 1;
1042
1043         condlog(3, "%s: prflag = %u", param, (unsigned int)mpp->prflag);
1044
1045         *reply =(char *)malloc(2);
1046         *len = 2;
1047         memset(*reply,0,2);
1048
1049
1050         sprintf(*reply,"%d",mpp->prflag);
1051         (*reply)[1]='\0';
1052
1053
1054         condlog(3, "%s: reply = %s", param, *reply);
1055
1056         return 0;
1057 }
1058
1059 int
1060 cli_setprstatus(void * v, char ** reply, int * len, void * data)
1061 {
1062         struct multipath * mpp;
1063         struct vectors * vecs = (struct vectors *)data;
1064         char * param = get_keyparam(v, MAP);
1065
1066         param = convert_dev(param, 0);
1067         get_path_layout(vecs->pathvec, 0);
1068         mpp = find_mp_by_str(vecs->mpvec, param);
1069
1070         if (!mpp)
1071                 return 1;
1072
1073         if (!mpp->prflag) {
1074                 mpp->prflag = 1;
1075                 condlog(2, "%s: prflag set", param);
1076         }
1077
1078
1079         return 0;
1080 }
1081
1082 int
1083 cli_unsetprstatus(void * v, char ** reply, int * len, void * data)
1084 {
1085         struct multipath * mpp;
1086         struct vectors * vecs = (struct vectors *)data;
1087         char * param = get_keyparam(v, MAP);
1088
1089         param = convert_dev(param, 0);
1090         get_path_layout(vecs->pathvec, 0);
1091         mpp = find_mp_by_str(vecs->mpvec, param);
1092
1093         if (!mpp)
1094                 return 1;
1095
1096         if (mpp->prflag) {
1097                 mpp->prflag = 0;
1098                 condlog(2, "%s: prflag unset", param);
1099         }
1100
1101         return 0;
1102 }