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