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