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