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