[multipath] Extension of the "no_path_retry" scope to the multipath
[platform/upstream/multipath-tools.git] / multipath / main.c
1 /*
2  * Soft:        multipath device mapper target autoconfig
3  *
4  * Version:     $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
5  *
6  * Author:      Copyright (C) 2003 Christophe Varoqui
7  *
8  *              This program is distributed in the hope that it will be useful,
9  *              but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *              See the GNU General Public License for more details.
12  *
13  *              This program is free software; you can redistribute it and/or
14  *              modify it under the terms of the GNU General Public License
15  *              as published by the Free Software Foundation; either version
16  *              2 of the License, or (at your option) any later version.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23
24 #include <parser.h>
25 #include <vector.h>
26 #include <memory.h>
27 #include <libdevmapper.h>
28 #include <devmapper.h>
29 #include <checkers.h>
30 #include <path_state.h>
31 #include <blacklist.h>
32 #include <hwtable.h>
33 #include <util.h>
34 #include <defaults.h>
35 #include <structs.h>
36 #include <dmparser.h>
37 #include <cache.h>
38 #include <config.h>
39 #include <propsel.h>
40 #include <discovery.h>
41 #include <debug.h>
42 #include <switchgroup.h>
43 #include <sysfs/libsysfs.h>
44 #include <print.h>
45
46 #include "main.h"
47 #include "pgpolicies.h"
48 #include "dict.h"
49
50 /* for column aligned output */
51 struct path_layout pl;
52
53 static char *
54 get_refwwid (vector pathvec)
55 {
56         struct path * pp;
57         char buff[FILE_NAME_SIZE];
58         char * refwwid;
59
60         if (conf->dev_type == DEV_NONE)
61                 return NULL;
62
63         if (conf->dev_type == DEV_DEVNODE) {
64                 condlog(3, "limited scope = %s", conf->dev);
65                 basename(conf->dev, buff);
66                 pp = find_path_by_dev(pathvec, buff);
67                 
68                 if (!pp) {
69                         pp = alloc_path();
70
71                         if (!pp)
72                                 return NULL;
73
74                         strncpy(pp->dev, buff, FILE_NAME_SIZE);
75
76                         if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
77                                 return NULL;
78
79                         if (store_path(pathvec, pp)) {
80                                 free_path(pp);
81                                 return NULL;
82                         }
83                 }
84
85                 refwwid = MALLOC(WWID_SIZE);
86
87                 if (!refwwid)
88                         return NULL;
89
90                 memcpy(refwwid, pp->wwid, WWID_SIZE);
91                 return refwwid;
92         }
93
94         if (conf->dev_type == DEV_DEVT) {
95                 condlog(3, "limited scope = %s", conf->dev);
96                 pp = find_path_by_devt(pathvec, conf->dev);
97                 
98                 if (!pp) {
99                         if (devt2devname(conf->dev, buff))
100                                 return NULL;
101
102                         pp = alloc_path();
103
104                         if (!pp)
105                                 return NULL;
106
107                         if(safe_sprintf(pp->dev, "%s", buff)) {
108                                 fprintf(stderr, "pp->dev too small\n");
109                                 exit(1);
110                         }
111                         if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
112                                 return NULL;
113                         
114                         if (store_path(pathvec, pp)) {
115                                 free_path(pp);
116                                 return NULL;
117                         }
118                 }
119
120                 refwwid = MALLOC(WWID_SIZE);
121
122                 if (!refwwid)
123                         return NULL;
124                 
125                 memcpy(refwwid, pp->wwid, WWID_SIZE);
126                 return refwwid;
127         }
128         if (conf->dev_type == DEV_DEVMAP) {
129                 condlog(3, "limited scope = %s", conf->dev);
130                 /*
131                  * may be an alias
132                  */
133                 refwwid = get_mpe_wwid(conf->dev);
134
135                 if (refwwid)
136                         return refwwid;
137                 
138                 /*
139                  * or directly a wwid
140                  */
141                 refwwid = MALLOC(WWID_SIZE);
142
143                 if (!refwwid)
144                         return NULL;
145
146                 strncpy(refwwid, conf->dev, WWID_SIZE);
147                 return refwwid;
148         }
149         return NULL;
150 }
151
152 static void
153 print_path (struct path * pp, char * style)
154 {
155         char buff[MAX_LINE_LEN];
156
157         snprint_path(&buff[0], MAX_LINE_LEN, style, pp, &pl);
158         printf("%s", buff);
159 }
160
161 static void
162 print_map (struct multipath * mpp)
163 {
164         if (mpp->size && mpp->params)
165                 printf("0 %llu %s %s\n",
166                          mpp->size, DEFAULT_TARGET, mpp->params);
167         return;
168 }
169
170 static void
171 print_all_paths (vector pathvec)
172 {
173         int i;
174         struct path * pp;
175
176         vector_foreach_slot (pathvec, pp, i)
177                 print_path(pp, PRINT_PATH_LONG);
178 }
179
180 static void
181 print_mp (struct multipath * mpp)
182 {
183         int j, i;
184         struct path * pp = NULL;
185         struct pathgroup * pgp = NULL;
186
187         if (mpp->action == ACT_NOTHING || conf->verbosity == 0)
188                 return;
189
190         if (conf->verbosity > 1) {
191                 switch (mpp->action) {
192                 case ACT_RELOAD:
193                         printf("%s: ", ACT_RELOAD_STR);
194                         break;
195
196                 case ACT_CREATE:
197                         printf("%s: ", ACT_CREATE_STR);
198                         break;
199
200                 case ACT_SWITCHPG:
201                         printf("%s: ", ACT_SWITCHPG_STR);
202                         break;
203
204                 default:
205                         break;
206                 }
207         }
208
209         if (mpp->alias)
210                 printf("%s", mpp->alias);
211
212         if (conf->verbosity == 1) {
213                 printf("\n");
214                 return;
215         }
216         if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
217                 printf(" (%s)", mpp->wwid);
218
219         printf("\n");
220
221         if (mpp->size < (1 << 11))
222                 printf("[size=%llu kB]", mpp->size >> 1);
223         else if (mpp->size < (1 << 21))
224                 printf("[size=%llu MB]", mpp->size >> 11);
225         else if (mpp->size < (1 << 31))
226                 printf("[size=%llu GB]", mpp->size >> 21);
227         else
228                 printf("[size=%llu TB]", mpp->size >> 31);
229
230         if (mpp->features)
231                 printf("[features=\"%s\"]", mpp->features);
232
233         if (mpp->hwhandler)
234                 printf("[hwhandler=\"%s\"]", mpp->hwhandler);
235
236         fprintf(stdout, "\n");
237
238         if (!mpp->pg)
239                 return;
240
241         vector_foreach_slot (mpp->pg, pgp, j) {
242                 printf("\\_ ");
243
244                 if (mpp->selector) {
245                         printf("%s ", mpp->selector);
246 #if 0
247                         /* align to path status info */
248                         for (i = pl.hbtl_len + pl.dev_len + pl.dev_t_len + 4;
249                              i > strlen(mpp->selector); i--)
250                                 printf(" ");
251 #endif
252                 }
253                 if (pgp->priority)
254                         printf("[prio=%i]", pgp->priority);
255
256                 switch (pgp->status) {
257                 case PGSTATE_ENABLED:
258                         printf("[enabled]");
259                         break;
260                 case PGSTATE_DISABLED:
261                         printf("[disabled]");
262                         break;
263                 case PGSTATE_ACTIVE:
264                         printf("[active]");
265                         break;
266                 default:
267                         break;
268                 }
269                 printf("\n");
270
271                 vector_foreach_slot (pgp->paths, pp, i)
272                         print_path(pp, PRINT_PATH_INDENT);
273         }
274         printf("\n");
275 }
276
277 static int
278 filter_pathvec (vector pathvec, char * refwwid)
279 {
280         int i;
281         struct path * pp;
282
283         if (!refwwid || !strlen(refwwid))
284                 return 0;
285
286         vector_foreach_slot (pathvec, pp, i) {
287                 if (memcmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
288                         condlog(3, "skip path %s : out of scope", pp->dev);
289                         free_path(pp);
290                         vector_del_slot(pathvec, i);
291                         i--;
292                 }
293         }
294         return 0;
295 }
296
297 /*
298  * Transforms the path group vector into a proper device map string
299  */
300 int
301 assemble_map (struct multipath * mp)
302 {
303         int i, j;
304         int shift, freechar;
305         int minio;
306         char * p;
307         struct pathgroup * pgp;
308         struct path * pp;
309
310         p = mp->params;
311         freechar = sizeof(mp->params);
312         
313         shift = snprintf(p, freechar, "%s %s %i %i",
314                          mp->features, mp->hwhandler,
315                          VECTOR_SIZE(mp->pg), mp->nextpg);
316
317         if (shift >= freechar) {
318                 fprintf(stderr, "mp->params too small\n");
319                 return 1;
320         }
321         p += shift;
322         freechar -= shift;
323         
324         vector_foreach_slot (mp->pg, pgp, i) {
325                 pgp = VECTOR_SLOT(mp->pg, i);
326                 shift = snprintf(p, freechar, " %s %i 1", mp->selector,
327                                  VECTOR_SIZE(pgp->paths));
328                 if (shift >= freechar) {
329                         fprintf(stderr, "mp->params too small\n");
330                         return 1;
331                 }
332                 p += shift;
333                 freechar -= shift;
334
335                 vector_foreach_slot (pgp->paths, pp, j) {
336                         minio = conf->minio;
337                         
338                         if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority)
339                                 minio *= pp->priority;
340
341                         shift = snprintf(p, freechar, " %s %d",
342                                          pp->dev_t, minio);
343                         if (shift >= freechar) {
344                                 fprintf(stderr, "mp->params too small\n");
345                                 return 1;
346                         }
347                         p += shift;
348                         freechar -= shift;
349                 }
350         }
351         if (freechar < 1) {
352                 fprintf(stderr, "mp->params too small\n");
353                 return 1;
354         }
355         snprintf(p, 1, "\n");
356
357         if (conf->verbosity > 2)
358                 print_map(mp);
359
360         return 0;
361 }
362
363 static int
364 setup_map (struct multipath * mpp)
365 {
366         struct path * pp;
367         int i;
368
369         /*
370          * don't bother if devmap size is unknown
371          */
372         if (mpp->size <= 0) {
373                 condlog(3, "%s devmap size is unknown", mpp->alias);
374                 return 1;
375         }
376
377         /*
378          * don't bother if a constituant path is claimed
379          * (not by the device mapper driver)
380          */
381         vector_foreach_slot (mpp->paths, pp, i) {
382                 if (pp->claimed && pp->dmstate == PSTATE_UNDEF) {
383                         condlog(3, "%s claimed", pp->dev);
384                         return 1;
385                 }
386         }
387
388         /*
389          * properties selectors
390          */
391         select_pgpolicy(mpp);
392         select_selector(mpp);
393         select_features(mpp);
394         select_hwhandler(mpp);
395         select_rr_weight(mpp);
396         select_no_path_retry(mpp);
397
398         /*
399          * apply selected grouping policy to valid paths
400          */
401         switch (mpp->pgpolicy) {
402         case MULTIBUS:
403                 one_group(mpp);
404                 break;
405         case FAILOVER:
406                 one_path_per_group(mpp);
407                 break;
408         case GROUP_BY_SERIAL:
409                 group_by_serial(mpp);
410                 break;
411         case GROUP_BY_PRIO:
412                 group_by_prio(mpp);
413                 break;
414         case GROUP_BY_NODE_NAME:
415                 group_by_node_name(mpp);
416                 break;
417         default:
418                 break;
419         }
420
421         if (mpp->pg == NULL) {
422                 condlog(3, "pgpolicy failed to produce a pg vector");
423                 return 1;
424         }
425
426         /*
427          * ponders each path group and determine highest prio pg
428          * to switch over (default to first)
429          */
430         select_path_group(mpp);
431
432         /*
433          * transform the mp->pg vector of vectors of paths
434          * into a mp->params strings to feed the device-mapper
435          */
436         if (assemble_map(mpp)) {
437                 condlog(3, "problem assembing map");
438                 return 1;
439         }
440         return 0;
441 }
442
443 static int
444 pathcount (struct multipath * mpp, int state)
445 {
446         struct pathgroup *pgp;
447         struct path *pp;
448         int i, j;
449         int count = 0;
450
451         vector_foreach_slot (mpp->pg, pgp, i)
452                 vector_foreach_slot (pgp->paths, pp, j)
453                         if (pp->state == state)
454                                 count++;
455         return count;
456 }
457
458 static void
459 compute_pgid(struct pathgroup * pgp)
460 {
461         struct path * pp;
462         int i;
463
464         vector_foreach_slot (pgp->paths, pp, i)
465                 pgp->id ^= (long)pp;
466 }
467
468 static int
469 pgcmp (struct multipath * mpp, struct multipath * cmpp)
470 {
471         int i, j;
472         struct pathgroup * pgp;
473         struct pathgroup * cpgp;
474         int r = 0;
475
476         vector_foreach_slot (mpp->pg, pgp, i) {
477                 compute_pgid(pgp);
478
479                 vector_foreach_slot (cmpp->pg, cpgp, j) {
480                         if (pgp->id == cpgp->id) {
481                                 r = 0;
482                                 break;
483                         }
484                         r++;
485                 }
486                 if (r)
487                         return r;
488         }
489         return r;
490 }
491
492 static void
493 select_action (struct multipath * mpp, vector curmp)
494 {
495         struct multipath * cmpp;
496
497         cmpp = find_mp(curmp, mpp->alias);
498
499         if (!cmpp) {
500                 cmpp = find_mp_by_wwid(curmp, mpp->wwid);
501
502                 if (cmpp && !conf->dry_run) {
503                         condlog(2, "remove: %s (dup of %s)",
504                                 cmpp->alias, mpp->alias);
505                         dm_flush_map(cmpp->alias, DEFAULT_TARGET);
506                 }
507                 mpp->action = ACT_CREATE;
508                 return;
509         }
510
511         if (!find_mp_by_wwid(curmp, mpp->wwid)) {
512                 dm_flush_map(mpp->alias, NULL);
513                 strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
514                 drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
515                 mpp->action = ACT_CREATE;
516                 return;
517         }
518                 
519         if (pathcount(mpp, PATH_UP) == 0) {
520                 condlog(3, "no good path");
521                 mpp->action = ACT_NOTHING;
522                 return;
523         }
524         if (cmpp->size != mpp->size) {
525                 condlog(3, "size different than current");
526                 mpp->action = ACT_RELOAD;
527                 return;
528         }
529         if (strncmp(cmpp->features, mpp->features,
530                     strlen(mpp->features))) {
531                 condlog(3, "features different than current");
532                 mpp->action =  ACT_RELOAD;
533                 return;
534         }
535         if (strncmp(cmpp->hwhandler, mpp->hwhandler,
536                     strlen(mpp->hwhandler))) {
537                 condlog(3, "hwhandler different than current");
538                 mpp->action = ACT_RELOAD;
539                 return;
540         }
541         if (strncmp(cmpp->selector, mpp->selector,
542                     strlen(mpp->selector))) {
543                 condlog(3, "selector different than current");
544                 mpp->action = ACT_RELOAD;
545                 return;
546         }
547         if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
548                 condlog(3, "different number of PG");
549                 mpp->action = ACT_RELOAD;
550                 return;
551         }
552         if (pgcmp(mpp, cmpp)) {
553                 condlog(3, "different path group topology");
554                 mpp->action = ACT_RELOAD;
555                 return;
556         }
557         if (cmpp->nextpg != mpp->nextpg) {
558                 condlog(3, "nextpg different than current");
559                 mpp->action = ACT_SWITCHPG;
560                 return;
561         }
562         mpp->action = ACT_NOTHING;
563         return;
564 }
565
566 static int
567 reinstate_paths (struct multipath * mpp)
568 {
569         int i, j;
570         struct pathgroup * pgp;
571         struct path * pp;
572
573         if (!mpp->pg)
574                 return 0;
575
576         vector_foreach_slot (mpp->pg, pgp, i) {
577                 if (!pgp->paths)
578                         continue;
579
580                 vector_foreach_slot (pgp->paths, pp, j) {
581                         if (pp->state != PATH_UP &&
582                             (pgp->status == PGSTATE_DISABLED ||
583                              pgp->status == PGSTATE_ACTIVE))
584                                 continue;
585
586                         if (pp->dmstate == PSTATE_FAILED) {
587                                 if (dm_reinstate(mpp->alias, pp->dev_t))
588                                         condlog(0, "error reinstating %s",
589                                                 pp->dev);
590                         }
591                 }
592         }
593         return 0;
594 }
595
596 /*
597  * Return value:
598  *   0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
599  *   1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
600  *   2: Map is already existing.
601  */
602 static int
603 domap (struct multipath * mpp)
604 {
605         int r = 0;
606
607         print_mp(mpp);
608
609         /*
610          * last chance to quit before touching the devmaps
611          */
612         if (conf->dry_run)
613                 return 0;
614
615         switch (mpp->action) {
616         case ACT_NOTHING:
617                 return 2;
618
619         case ACT_SWITCHPG:
620                 dm_switchgroup(mpp->alias, mpp->nextpg);
621                 /*
622                  * we may have avoided reinstating paths because there where in
623                  * active or disabled PG. Now that the topology has changed,
624                  * retry.
625                  */
626                 reinstate_paths(mpp);
627                 return 2;
628
629         case ACT_CREATE:
630                 r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
631                               mpp->params, mpp->size, mpp->wwid);
632                 break;
633
634         case ACT_RELOAD:
635                 r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
636                               mpp->params, mpp->size, NULL) &&
637                      dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
638                 break;
639
640         default:
641                 break;
642         }
643
644         if (r)
645                 /*
646                  * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded
647                  */
648                 dm_switchgroup(mpp->alias, mpp->nextpg);
649
650         return r;
651 }
652
653 static int
654 deadmap (struct multipath * mpp)
655 {
656         int i, j;
657         struct pathgroup * pgp;
658         struct path * pp;
659
660         if (!mpp->pg)
661                 return 1;
662
663         vector_foreach_slot (mpp->pg, pgp, i) {
664                 if (!pgp->paths)
665                         continue;
666
667                 vector_foreach_slot (pgp->paths, pp, j)
668                         if (strlen(pp->dev))
669                                 return 0; /* alive */
670         }
671         
672         return 1; /* dead */
673 }
674
675 static int
676 coalesce_paths (vector curmp, vector pathvec)
677 {
678         int k, i;
679         char empty_buff[WWID_SIZE];
680         struct multipath * mpp;
681         struct path * pp1;
682         struct path * pp2;
683
684         memset(empty_buff, 0, WWID_SIZE);
685
686         vector_foreach_slot (pathvec, pp1, k) {
687                 /* skip this path for some reason */
688
689                 /* 1. if path has no unique id or wwid blacklisted */
690                 if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
691                     blacklist(conf->blist, pp1->wwid))
692                         continue;
693
694                 /* 2. if path already coalesced */
695                 if (pp1->mpp)
696                         continue;
697
698                 /*
699                  * at this point, we know we really got a new mp
700                  */
701                 mpp = alloc_multipath();
702
703                 if (!mpp)
704                         return 1;
705
706                 mpp->mpe = find_mpe(pp1->wwid);
707                 mpp->hwe = pp1->hwe;
708                 select_alias(mpp);
709
710                 pp1->mpp = mpp;
711                 strcpy(mpp->wwid, pp1->wwid);
712                 mpp->size = pp1->size;
713                 mpp->paths = vector_alloc();
714
715                 if (pp1->priority < 0)
716                         mpp->action = ACT_NOTHING;
717
718                 if (!mpp->paths)
719                         return 1;
720                 
721                 if (store_path(mpp->paths, pp1))
722                         return 1;
723
724                 for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
725                         pp2 = VECTOR_SLOT(pathvec, i);
726
727                         if (strcmp(pp1->wwid, pp2->wwid))
728                                 continue;
729                         
730                         pp2->mpp = mpp;
731
732                         if (pp2->size != mpp->size) {
733                                 /*
734                                  * ouch, avoid feeding that to the DM
735                                  */
736                                 condlog(3, "path size mismatch : discard %s",
737                                      mpp->wwid);
738                                 mpp->action = ACT_NOTHING;
739                         }
740                         if (pp2->priority < 0)
741                                 mpp->action = ACT_NOTHING;
742
743                         if (store_path(mpp->paths, pp2))
744                                 return 1;
745                 }
746                 if (setup_map(mpp))
747                         goto next;
748
749                 condlog(3, "action preset to %i", mpp->action);
750
751                 if (mpp->action == ACT_UNDEF)
752                         select_action(mpp, curmp);
753
754                 condlog(3, "action set to %i", mpp->action);
755
756                 if (domap(mpp) && mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
757                         if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
758                                 dm_queue_if_no_path(mpp->alias, 0);
759                         else
760                                 dm_queue_if_no_path(mpp->alias, 1);
761                 }
762
763 next:
764                 drop_multipath(curmp, mpp->wwid, KEEP_PATHS);
765                 free_multipath(mpp, KEEP_PATHS);
766         }
767         /*
768          * Flush maps with only dead paths (ie not in sysfs)
769          * Keep maps with only failed paths
770          */
771         vector_foreach_slot (curmp, mpp, i) {
772                 if (!deadmap(mpp))
773                         continue;
774
775                 if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
776                         condlog(2, "remove: %s (dead) failed!",
777                                 mpp->alias);
778                 else
779                         condlog(2, "remove: %s (dead)", mpp->alias);
780         }
781         return 0;
782 }
783
784 static void
785 usage (char * progname)
786 {
787         fprintf (stderr, VERSION_STRING);
788         fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n",
789                 progname);
790         fprintf (stderr,
791                 "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
792                 "\t\t\t[device]\n" \
793                 "\n" \
794                 "\t-v level\tverbosty level\n" \
795                 "\t   0\t\t\tno output\n" \
796                 "\t   1\t\t\tprint created devmap names only\n" \
797                 "\t   2\t\t\tdefault verbosity\n" \
798                 "\t   3\t\t\tprint debug information\n" \
799                 "\t-d\t\tdry run, do not create or update devmaps\n" \
800                 "\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
801                 "\t-ll\t\tshow multipath topology (maximum info)\n" \
802                 "\t-F\t\tflush a multipath device map\n" \
803                 "\t-F\t\tflush all multipath device maps\n" \
804                 "\t-p policy\tforce all maps to specified policy :\n" \
805                 "\t   failover\t\t1 path per priority group\n" \
806                 "\t   multibus\t\tall paths in 1 priority group\n" \
807                 "\t   group_by_serial\t1 priority group per serial\n" \
808                 "\t   group_by_prio\t1 priority group per priority lvl\n" \
809                 "\t   group_by_node_name\t1 priority group per target node\n" \
810                 "\n" \
811                 "\tdevice\t\tlimit scope to the device's multipath\n" \
812                 "\t\t\t(udev-style $DEVNAME reference, eg /dev/sdb\n" \
813                 "\t\t\tor major:minor or a device map name)\n" \
814                 );
815
816         exit(1);
817 }
818
819 static int
820 update_paths (struct multipath * mpp)
821 {
822         int i, j;
823         struct pathgroup * pgp;
824         struct path * pp;
825
826         if (!mpp->pg)
827                 return 0;
828
829         vector_foreach_slot (mpp->pg, pgp, i) {
830                 if (!pgp->paths)
831                         continue;
832
833                 vector_foreach_slot (pgp->paths, pp, j) {
834                         if (!strlen(pp->dev)) {
835                                 if (devt2devname(pp->dev_t, pp->dev)) {
836                                         /*
837                                          * path is not in sysfs anymore
838                                          */
839                                         pp->state = PATH_DOWN;
840                                         continue;
841                                 }
842                                 pathinfo(pp, conf->hwtable,
843                                          DI_SYSFS | DI_CHECKER | \
844                                          DI_SERIAL | DI_PRIO);
845                                 continue;
846                         }
847                         if (pp->state == PATH_UNCHECKED)
848                                 pathinfo(pp, conf->hwtable, DI_CHECKER);
849
850                         if (!pp->priority)
851                                 pathinfo(pp, conf->hwtable, DI_PRIO);
852                 }
853         }
854         return 0;
855 }
856
857 static int
858 get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
859 {
860         int i;
861         struct multipath * mpp;
862
863         if (dm_get_maps(curmp, DEFAULT_TARGET))
864                 return 1;
865
866         vector_foreach_slot (curmp, mpp, i) {
867                 /*
868                  * discard out of scope maps
869                  */
870                 if (mpp->wwid && refwwid &&
871                     strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
872                         condlog(3, "skip map %s: out of scope", mpp->alias);
873                         free_multipath(mpp, KEEP_PATHS);
874                         vector_del_slot(curmp, i);
875                         i--;
876                         continue;
877                 }
878
879                 condlog(3, "params = %s", mpp->params);
880                 condlog(3, "status = %s", mpp->status);
881
882                 disassemble_map(pathvec, mpp->params, mpp);
883
884                 /*
885                  * disassemble_map() can add new paths to pathvec.
886                  * If not in "fast list mode", we need to fetch information
887                  * about them
888                  */
889                 if (conf->list != 1)
890                         update_paths(mpp);
891
892                 if (conf->list > 1)
893                         select_path_group(mpp);
894
895                 disassemble_status(mpp->status, mpp);
896
897                 if (conf->list)
898                         print_mp(mpp);
899
900                 if (!conf->dry_run)
901                         reinstate_paths(mpp);
902         }
903         return 0;
904 }
905
906 int
907 main (int argc, char *argv[])
908 {
909         vector curmp = NULL;
910         vector pathvec = NULL;
911         int i;
912         int di_flag = 0;
913         int arg;
914         extern char *optarg;
915         extern int optind;
916         char * refwwid = NULL;
917
918         if (getuid() != 0) {
919                 fprintf(stderr, "need to be root\n");
920                 exit(1);
921         }
922
923         if (dm_prereq(DEFAULT_TARGET, 1, 0, 3))
924                 exit(1);
925
926         if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
927                 condlog(0, "multipath tools need sysfs mounted");
928                 exit(1);
929         }
930         if (load_config(DEFAULT_CONFIGFILE))
931                 exit(1);
932
933         while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:")) != EOF ) {
934                 switch(arg) {
935                 case 1: printf("optarg : %s\n",optarg);
936                         break;
937                 case 'v':
938                         if (sizeof(optarg) > sizeof(char *) ||
939                             !isdigit(optarg[0]))
940                                 usage (argv[0]);
941
942                         conf->verbosity = atoi(optarg);
943                         break;
944                 case 'd':
945                         conf->dry_run = 1;
946                         break;
947                 case 'f':
948                         conf->remove = 1;
949                         break;
950                 case 'F':
951                         conf->remove = 2;
952                         break;
953                 case 'l':
954                         conf->list = 1;
955                         conf->dry_run = 1;
956
957                         if (optarg && !strncmp(optarg, "l", 1))
958                                 conf->list++;
959
960                         break;
961                 case 'M':
962 #if _DEBUG_
963                         debug = atoi(optarg);
964 #endif
965                         break;
966                 case 'p':
967                         conf->pgpolicy_flag = get_pgpolicy_id(optarg);
968                         if (conf->pgpolicy_flag == -1) {
969                                 printf("'%s' is not a valid policy\n", optarg);
970                                 usage(argv[0]);
971                         }                
972                         break;
973                 case ':':
974                         fprintf(stderr, "Missing option arguement\n");
975                         usage(argv[0]);        
976                 case '?':
977                         fprintf(stderr, "Unknown switch: %s\n", optarg);
978                         usage(argv[0]);
979                 default:
980                         usage(argv[0]);
981                 }
982         }        
983         if (optind < argc) {
984                 conf->dev = MALLOC(FILE_NAME_SIZE);
985
986                 if (!conf->dev)
987                         goto out;
988
989                 strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
990
991                 if (filepresent(conf->dev))
992                         conf->dev_type = DEV_DEVNODE;
993                 else if (sscanf(conf->dev, "%d:%d", &i, &i) == 2)
994                         conf->dev_type = DEV_DEVT;
995                 else
996                         conf->dev_type = DEV_DEVMAP;
997
998         }
999
1000         if (conf->remove == FLUSH_ONE) {
1001                 if (conf->dev_type == DEV_DEVMAP)
1002                         dm_flush_map(conf->dev, DEFAULT_TARGET);
1003                 else
1004                         condlog(0, "must provide a map name to remove");
1005
1006                 goto out;
1007         }
1008         else if (conf->remove == FLUSH_ALL) {
1009                 dm_flush_maps(DEFAULT_TARGET);
1010                 goto out;
1011         }
1012
1013         /*
1014          * allocate core vectors to store paths and multipaths
1015          */
1016         curmp = vector_alloc();
1017         pathvec = vector_alloc();
1018
1019         if (!curmp || !pathvec) {
1020                 condlog(0, "can not allocate memory");
1021                 goto out;
1022         }
1023
1024         /*
1025          * if we have a blacklisted device parameter, exit early
1026          */
1027         if (conf->dev && blacklist(conf->blist, conf->dev))
1028                 goto out;
1029         
1030         condlog(3, "load path identifiers cache");
1031         cache_load(pathvec);
1032
1033         if (conf->verbosity > 2) {
1034                 fprintf(stdout, "#\n# all paths in cache :\n#\n");
1035                 print_all_paths(pathvec);
1036         }
1037
1038         /*
1039          * get a path list
1040          */
1041         if (conf->dev)
1042                 di_flag = DI_WWID;
1043
1044         if (conf->list > 1)
1045                 /* extended path info '-ll' */
1046                 di_flag |= DI_SYSFS | DI_CHECKER;
1047         else if (conf->list)
1048                 /* minimum path info '-l' */
1049                 di_flag |= DI_SYSFS;
1050         else
1051                 /* maximum info */
1052                 di_flag = DI_ALL;
1053
1054         if (path_discovery(pathvec, conf, di_flag))
1055                 goto out;
1056
1057         if (conf->verbosity > 2) {
1058                 fprintf(stdout, "#\n# all paths :\n#\n");
1059                 print_all_paths(pathvec);
1060         }
1061
1062         /*
1063          * scope limiting must be translated into a wwid
1064          * failing the translation is fatal (by policy)
1065          */
1066         if (conf->dev) {
1067                 refwwid = get_refwwid(pathvec);
1068
1069                 if (!refwwid) {
1070                         condlog(3, "scope is nul");
1071                         goto out;
1072                 }
1073         }
1074
1075         get_path_layout(&pl, pathvec);
1076
1077         if (get_dm_mpvec(curmp, pathvec, refwwid))
1078                 goto out;
1079
1080         filter_pathvec(pathvec, refwwid);
1081
1082         if (conf->list)
1083                 goto out;
1084
1085         /*
1086          * core logic entry point
1087          */
1088         coalesce_paths(curmp, pathvec);
1089
1090 out:
1091         if (refwwid)
1092                 FREE(refwwid);
1093
1094         free_multipathvec(curmp, KEEP_PATHS);
1095         free_pathvec(pathvec, FREE_PATHS);
1096         free_config(conf);
1097         dm_lib_release();
1098         dm_lib_exit();
1099 #ifdef _DEBUG_
1100         dbg_free_final(NULL);
1101 #endif
1102         exit(0);
1103 }