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