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