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