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