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