[libmultipath] rename find_mp() to find_mp_by_alias()
[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 #include <sys/file.h>
24 #include <errno.h>
25
26 #include <parser.h>
27 #include <vector.h>
28 #include <memory.h>
29 #include <libdevmapper.h>
30 #include <devmapper.h>
31 #include <checkers.h>
32 #include <path_state.h>
33 #include <blacklist.h>
34 #include <hwtable.h>
35 #include <util.h>
36 #include <defaults.h>
37 #include <structs.h>
38 #include <dmparser.h>
39 #include <cache.h>
40 #include <config.h>
41 #include <propsel.h>
42 #include <discovery.h>
43 #include <debug.h>
44 #include <switchgroup.h>
45 #include <sysfs/libsysfs.h>
46 #include <print.h>
47 #include <alias.h>
48
49 #include "main.h"
50 #include "pgpolicies.h"
51 #include "dict.h"
52
53 /* for column aligned output */
54 struct path_layout pl;
55
56 static char *
57 get_refwwid (vector pathvec)
58 {
59         struct path * pp;
60         char buff[FILE_NAME_SIZE];
61         char * refwwid;
62
63         if (conf->dev_type == DEV_NONE)
64                 return NULL;
65
66         if (conf->dev_type == DEV_DEVNODE) {
67                 basename(conf->dev, buff);
68                 pp = find_path_by_dev(pathvec, buff);
69                 
70                 if (!pp) {
71                         pp = alloc_path();
72
73                         if (!pp)
74                                 return NULL;
75
76                         strncpy(pp->dev, buff, FILE_NAME_SIZE);
77
78                         if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
79                                 return NULL;
80
81                         if (store_path(pathvec, pp)) {
82                                 free_path(pp);
83                                 return NULL;
84                         }
85                 }
86                 refwwid = pp->wwid;
87                 goto out;
88         }
89
90         if (conf->dev_type == DEV_DEVT) {
91                 pp = find_path_by_devt(pathvec, conf->dev);
92                 
93                 if (!pp) {
94                         if (devt2devname(buff, conf->dev))
95                                 return NULL;
96
97                         pp = alloc_path();
98
99                         if (!pp)
100                                 return NULL;
101
102                         strncpy(pp->dev, buff, FILE_NAME_SIZE);
103
104                         if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
105                                 return NULL;
106                         
107                         if (store_path(pathvec, pp)) {
108                                 free_path(pp);
109                                 return NULL;
110                         }
111                 }
112                 refwwid = pp->wwid;
113                 goto out;
114         }
115         if (conf->dev_type == DEV_DEVMAP) {
116                 /*
117                  * may be a binding
118                  */
119                 refwwid = get_user_friendly_wwid(conf->dev,
120                                                  conf->bindings_file);
121
122                 if (refwwid)
123                         return refwwid;
124
125                 /*
126                  * or may be an alias
127                  */
128                 refwwid = get_mpe_wwid(conf->dev);
129
130                 /*
131                  * or directly a wwid
132                  */
133                 if (!refwwid)
134                         refwwid = conf->dev;
135         }
136 out:
137         if (refwwid && strlen(refwwid))
138                 return STRDUP(refwwid);
139
140         return NULL;
141 }
142
143 static void
144 print_path (struct path * pp, char * style)
145 {
146         char line[MAX_LINE_LEN];
147
148         snprint_path(&line[0], MAX_LINE_LEN, style, pp, &pl);
149         printf("%s", line);
150 }
151
152 static void
153 print_map (struct multipath * mpp)
154 {
155         if (mpp->size && mpp->params)
156                 printf("0 %llu %s %s\n",
157                          mpp->size, DEFAULT_TARGET, mpp->params);
158         return;
159 }
160
161 static void
162 print_all_paths (vector pathvec, int banner)
163 {
164         int i;
165         struct path * pp;
166         char line[MAX_LINE_LEN];
167
168         if (!VECTOR_SIZE(pathvec)) {
169                 if (banner)
170                         fprintf(stdout, "===== no paths =====\n");
171                 return;
172         }
173         
174         if (banner)
175                 fprintf(stdout, "===== paths list =====\n");
176
177         get_path_layout(&pl, pathvec);
178         snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG, &pl);
179         fprintf(stdout, "%s", line);
180
181         vector_foreach_slot (pathvec, pp, i)
182                 print_path(pp, PRINT_PATH_LONG);
183 }
184
185 static void
186 print_mp (struct multipath * mpp)
187 {
188         int j, i;
189         struct path * pp = NULL;
190         struct pathgroup * pgp = NULL;
191
192         if (mpp->action == ACT_NOTHING || !conf->verbosity || !mpp->size)
193                 return;
194
195         if (conf->verbosity > 1) {
196                 switch (mpp->action) {
197                 case ACT_RELOAD:
198                         printf("%s: ", ACT_RELOAD_STR);
199                         break;
200
201                 case ACT_CREATE:
202                         printf("%s: ", ACT_CREATE_STR);
203                         break;
204
205                 case ACT_SWITCHPG:
206                         printf("%s: ", ACT_SWITCHPG_STR);
207                         break;
208
209                 default:
210                         break;
211                 }
212         }
213
214         if (mpp->alias)
215                 printf("%s", mpp->alias);
216
217         if (conf->verbosity == 1) {
218                 printf("\n");
219                 return;
220         }
221         if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
222                 printf(" (%s)", mpp->wwid);
223
224         printf("\n");
225
226         if (mpp->size < (1 << 11))
227                 printf("[size=%llu kB]", mpp->size >> 1);
228         else if (mpp->size < (1 << 21))
229                 printf("[size=%llu MB]", mpp->size >> 11);
230         else if (mpp->size < (1 << 31))
231                 printf("[size=%llu GB]", mpp->size >> 21);
232         else
233                 printf("[size=%llu TB]", mpp->size >> 31);
234
235         if (mpp->features)
236                 printf("[features=\"%s\"]", mpp->features);
237
238         if (mpp->hwhandler)
239                 printf("[hwhandler=\"%s\"]", mpp->hwhandler);
240
241         fprintf(stdout, "\n");
242
243         if (!mpp->pg)
244                 return;
245
246         vector_foreach_slot (mpp->pg, pgp, j) {
247                 printf("\\_ ");
248
249                 if (mpp->selector) {
250                         printf("%s ", mpp->selector);
251 #if 0
252                         /* align to path status info */
253                         for (i = pl.hbtl_len + pl.dev_len + pl.dev_t_len + 4;
254                              i > strlen(mpp->selector); i--)
255                                 printf(" ");
256 #endif
257                 }
258                 if (pgp->priority)
259                         printf("[prio=%i]", pgp->priority);
260
261                 switch (pgp->status) {
262                 case PGSTATE_ENABLED:
263                         printf("[enabled]");
264                         break;
265                 case PGSTATE_DISABLED:
266                         printf("[disabled]");
267                         break;
268                 case PGSTATE_ACTIVE:
269                         printf("[active]");
270                         break;
271                 default:
272                         break;
273                 }
274                 printf("\n");
275
276                 vector_foreach_slot (pgp->paths, pp, i)
277                         print_path(pp, PRINT_PATH_INDENT);
278         }
279         printf("\n");
280 }
281
282 static int
283 filter_pathvec (vector pathvec, char * refwwid)
284 {
285         int i;
286         struct path * pp;
287
288         if (!refwwid || !strlen(refwwid))
289                 return 0;
290
291         vector_foreach_slot (pathvec, pp, i) {
292                 if (strncmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
293                         condlog(3, "skip path %s : out of scope", pp->dev);
294                         free_path(pp);
295                         vector_del_slot(pathvec, i);
296                         i--;
297                 }
298         }
299         return 0;
300 }
301
302 /*
303  * Transforms the path group vector into a proper device map string
304  */
305 int
306 assemble_map (struct multipath * mp)
307 {
308         int i, j;
309         int shift, freechar;
310         int minio;
311         char * p;
312         struct pathgroup * pgp;
313         struct path * pp;
314
315         p = mp->params;
316         freechar = sizeof(mp->params);
317         
318         shift = snprintf(p, freechar, "%s %s %i %i",
319                          mp->features, mp->hwhandler,
320                          VECTOR_SIZE(mp->pg), mp->nextpg);
321
322         if (shift >= freechar) {
323                 fprintf(stderr, "mp->params too small\n");
324                 return 1;
325         }
326         p += shift;
327         freechar -= shift;
328         
329         vector_foreach_slot (mp->pg, pgp, i) {
330                 pgp = VECTOR_SLOT(mp->pg, i);
331                 shift = snprintf(p, freechar, " %s %i 1", mp->selector,
332                                  VECTOR_SIZE(pgp->paths));
333                 if (shift >= freechar) {
334                         fprintf(stderr, "mp->params too small\n");
335                         return 1;
336                 }
337                 p += shift;
338                 freechar -= shift;
339
340                 vector_foreach_slot (pgp->paths, pp, j) {
341                         minio = conf->minio;
342                         
343                         if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority)
344                                 minio *= pp->priority;
345
346                         shift = snprintf(p, freechar, " %s %d",
347                                          pp->dev_t, minio);
348                         if (shift >= freechar) {
349                                 fprintf(stderr, "mp->params too small\n");
350                                 return 1;
351                         }
352                         p += shift;
353                         freechar -= shift;
354                 }
355         }
356         if (freechar < 1) {
357                 fprintf(stderr, "mp->params too small\n");
358                 return 1;
359         }
360         snprintf(p, 1, "\n");
361
362         if (conf->verbosity > 2)
363                 print_map(mp);
364
365         return 0;
366 }
367
368 static int
369 setup_map (struct multipath * mpp)
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          * properties selectors
381          */
382         select_pgpolicy(mpp);
383         select_selector(mpp);
384         select_features(mpp);
385         select_hwhandler(mpp);
386         select_rr_weight(mpp);
387         select_no_path_retry(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_by_alias(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                 condlog(3, "set ACT_CREATE: map does not exists");
500                 return;
501         }
502
503         if (!find_mp_by_wwid(curmp, mpp->wwid)) {
504                 condlog(2, "remove: %s (wwid changed)", cmpp->alias);
505                 dm_flush_map(mpp->alias, NULL);
506                 strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
507                 drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
508                 mpp->action = ACT_CREATE;
509                 condlog(3, "set ACT_CREATE: map wwid change");
510                 return;
511         }
512                 
513         if (pathcount(mpp, PATH_UP) == 0) {
514                 mpp->action = ACT_NOTHING;
515                 condlog(3, "set ACT_NOTHING: no usable path");
516                 return;
517         }
518         if (cmpp->size != mpp->size) {
519                 mpp->action = ACT_RELOAD;
520                 condlog(3, "set ACT_RELOAD: size change");
521                 return;
522         }
523         if (!mpp->no_path_retry && /* let features be handled by the daemon */
524             strncmp(cmpp->features, mpp->features, strlen(mpp->features))) {
525                 mpp->action =  ACT_RELOAD;
526                 condlog(3, "set ACT_RELOAD: features change");
527                 return;
528         }
529         if (strncmp(cmpp->hwhandler, mpp->hwhandler,
530                     strlen(mpp->hwhandler))) {
531                 mpp->action = ACT_RELOAD;
532                 condlog(3, "set ACT_RELOAD: hwhandler change");
533                 return;
534         }
535         if (strncmp(cmpp->selector, mpp->selector,
536                     strlen(mpp->selector))) {
537                 mpp->action = ACT_RELOAD;
538                 condlog(3, "set ACT_RELOAD: selector change");
539                 return;
540         }
541         if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
542                 mpp->action = ACT_RELOAD;
543                 condlog(3, "set ACT_RELOAD: number of path group change");
544                 return;
545         }
546         if (pgcmp(mpp, cmpp)) {
547                 mpp->action = ACT_RELOAD;
548                 condlog(3, "set ACT_RELOAD: path group topology change");
549                 return;
550         }
551         if (cmpp->nextpg != mpp->nextpg) {
552                 mpp->action = ACT_SWITCHPG;
553                 condlog(3, "set ACT_SWITCHPG: next path group change");
554                 return;
555         }
556         mpp->action = ACT_NOTHING;
557         condlog(3, "set ACT_NOTHING: map unchanged");
558         return;
559 }
560
561 static int
562 reinstate_paths (struct multipath * mpp)
563 {
564         int i, j;
565         struct pathgroup * pgp;
566         struct path * pp;
567
568         if (!mpp->pg)
569                 return 0;
570
571         vector_foreach_slot (mpp->pg, pgp, i) {
572                 if (!pgp->paths)
573                         continue;
574
575                 vector_foreach_slot (pgp->paths, pp, j) {
576                         if (pp->state != PATH_UP &&
577                             (pgp->status == PGSTATE_DISABLED ||
578                              pgp->status == PGSTATE_ACTIVE))
579                                 continue;
580
581                         if (pp->dmstate == PSTATE_FAILED) {
582                                 if (dm_reinstate(mpp->alias, pp->dev_t))
583                                         condlog(0, "error reinstating %s",
584                                                 pp->dev);
585                         }
586                 }
587         }
588         return 0;
589 }
590
591 int lock_multipath (struct multipath * mpp, int lock)
592 {
593         struct pathgroup * pgp;
594         struct path * pp;
595         int i, j;
596
597         if (!mpp || !mpp->pg)
598                 return 0;
599         
600         vector_foreach_slot (mpp->pg, pgp, i) {
601                 if (!pgp->paths)
602                         continue;
603                 vector_foreach_slot(pgp->paths, pp, j) {
604                         if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
605                             errno == EWOULDBLOCK)
606                                 return 1;
607                         else if (!lock)
608                                 flock(pp->fd, LOCK_UN);
609                 }
610         }
611         return 0;
612 }
613
614 /*
615  * Return value:
616  *  -1: Retry
617  *   0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
618  *   1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
619  *   2: Map is already existing.
620  */
621 static int
622 domap (struct multipath * mpp)
623 {
624         int r = 0;
625
626         /*
627          * last chance to quit before touching the devmaps
628          */
629         if (conf->dry_run)
630                 return 0;
631
632         switch (mpp->action) {
633         case ACT_NOTHING:
634                 return 2;
635
636         case ACT_SWITCHPG:
637                 dm_switchgroup(mpp->alias, mpp->nextpg);
638                 /*
639                  * we may have avoided reinstating paths because there where in
640                  * active or disabled PG. Now that the topology has changed,
641                  * retry.
642                  */
643                 reinstate_paths(mpp);
644                 return 2;
645
646         case ACT_CREATE:
647                 if (lock_multipath(mpp, 1)) {
648                         condlog(3, "%s: in use", mpp->alias);
649                         return -1;
650                 }
651                 dm_shut_log();
652
653                 if (dm_map_present(mpp->alias))
654                         break;
655
656                 r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
657                               mpp->params, mpp->size, mpp->wwid);
658
659                 /*
660                  * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus
661                  * DM_TABLE_LOAD. Failing the second part leaves an
662                  * empty map. Clean it up.
663                  */
664                 if (!r && dm_map_present(mpp->alias)) {
665                         condlog(3, "%s: failed to load map "
666                                    "(a path might be in use)",
667                                    mpp->alias);
668                         dm_flush_map(mpp->alias, NULL);
669                 }
670
671                 lock_multipath(mpp, 0);
672                 dm_restore_log();
673                 break;
674
675         case ACT_RELOAD:
676                 r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
677                               mpp->params, mpp->size, NULL) &&
678                      dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
679                 break;
680
681         default:
682                 break;
683         }
684
685         if (r) {
686                 /*
687                  * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded
688                  */
689                 dm_switchgroup(mpp->alias, mpp->nextpg);
690                 print_mp(mpp);
691         }
692
693         return r;
694 }
695
696 static int
697 deadmap (struct multipath * mpp)
698 {
699         int i, j;
700         struct pathgroup * pgp;
701         struct path * pp;
702
703         if (!mpp->pg)
704                 return 1;
705
706         vector_foreach_slot (mpp->pg, pgp, i) {
707                 if (!pgp->paths)
708                         continue;
709
710                 vector_foreach_slot (pgp->paths, pp, j)
711                         if (strlen(pp->dev))
712                                 return 0; /* alive */
713         }
714         
715         return 1; /* dead */
716 }
717
718 static int
719 coalesce_paths (vector curmp, vector pathvec)
720 {
721         int r = 1;
722         int k, i;
723         char empty_buff[WWID_SIZE];
724         struct multipath * mpp;
725         struct path * pp1;
726         struct path * pp2;
727
728         memset(empty_buff, 0, WWID_SIZE);
729
730         vector_foreach_slot (pathvec, pp1, k) {
731                 /* skip this path for some reason */
732
733                 /* 1. if path has no unique id or wwid blacklisted */
734                 if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
735                     blacklist(conf->blist, pp1->wwid))
736                         continue;
737
738                 /* 2. if path already coalesced */
739                 if (pp1->mpp)
740                         continue;
741
742                 /*
743                  * at this point, we know we really got a new mp
744                  */
745                 mpp = alloc_multipath();
746
747                 if (!mpp)
748                         return 1;
749
750                 mpp->mpe = find_mpe(pp1->wwid);
751                 mpp->hwe = pp1->hwe;
752                 strcpy(mpp->wwid, pp1->wwid);
753                 select_alias(mpp);
754
755                 pp1->mpp = mpp;
756                 mpp->size = pp1->size;
757                 mpp->paths = vector_alloc();
758
759                 if (pp1->priority < 0)
760                         mpp->action = ACT_NOTHING;
761
762                 if (!mpp->paths)
763                         return 1;
764                 
765                 if (store_path(mpp->paths, pp1))
766                         return 1;
767
768                 for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
769                         pp2 = VECTOR_SLOT(pathvec, i);
770
771                         if (strcmp(pp1->wwid, pp2->wwid))
772                                 continue;
773                         
774                         pp2->mpp = mpp;
775
776                         if (pp2->size != mpp->size) {
777                                 /*
778                                  * ouch, avoid feeding that to the DM
779                                  */
780                                 condlog(3, "path size mismatch : discard %s",
781                                      mpp->wwid);
782                                 mpp->action = ACT_NOTHING;
783                         }
784                         if (pp2->priority < 0)
785                                 mpp->action = ACT_NOTHING;
786
787                         if (store_path(mpp->paths, pp2))
788                                 return 1;
789                 }
790                 if (setup_map(mpp))
791                         goto next;
792
793                 if (mpp->action == ACT_UNDEF)
794                         select_action(mpp, curmp);
795
796                 r = domap(mpp);
797
798                 if (r < 0)
799                         return r;
800
801                 if (r && mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
802                         if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
803                                 dm_queue_if_no_path(mpp->alias, 0);
804                         else
805                                 dm_queue_if_no_path(mpp->alias, 1);
806                 }
807
808 next:
809                 drop_multipath(curmp, mpp->wwid, KEEP_PATHS);
810                 free_multipath(mpp, KEEP_PATHS);
811         }
812         /*
813          * Flush maps with only dead paths (ie not in sysfs)
814          * Keep maps with only failed paths
815          */
816         vector_foreach_slot (curmp, mpp, i) {
817                 if (!deadmap(mpp))
818                         continue;
819
820                 if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
821                         condlog(2, "remove: %s (dead) failed!",
822                                 mpp->alias);
823                 else
824                         condlog(2, "remove: %s (dead)", mpp->alias);
825         }
826         return 0;
827 }
828
829 static void
830 usage (char * progname)
831 {
832         fprintf (stderr, VERSION_STRING);
833         fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n",
834                 progname);
835         fprintf (stderr,
836                 "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
837                 "\t\t\t[device]\n" \
838                 "\n" \
839                 "\t-v level\tverbosity level\n" \
840                 "\t   0\t\t\tno output\n" \
841                 "\t   1\t\t\tprint created devmap names only\n" \
842                 "\t   2\t\t\tdefault verbosity\n" \
843                 "\t   3\t\t\tprint debug information\n" \
844                 "\t-b file\t\tbindings file location\n" \
845                 "\t-d\t\tdry run, do not create or update devmaps\n" \
846                 "\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
847                 "\t-ll\t\tshow multipath topology (maximum info)\n" \
848                 "\t-f\t\tflush a multipath device map\n" \
849                 "\t-F\t\tflush all multipath device maps\n" \
850                 "\t-p policy\tforce all maps to specified policy :\n" \
851                 "\t   failover\t\t1 path per priority group\n" \
852                 "\t   multibus\t\tall paths in 1 priority group\n" \
853                 "\t   group_by_serial\t1 priority group per serial\n" \
854                 "\t   group_by_prio\t1 priority group per priority lvl\n" \
855                 "\t   group_by_node_name\t1 priority group per target node\n" \
856                 "\n" \
857                 "\tdevice\t\tlimit scope to the device's multipath\n" \
858                 "\t\t\t(udev-style $DEVNAME reference, eg /dev/sdb\n" \
859                 "\t\t\tor major:minor or a device map name)\n" \
860                 );
861
862         exit(1);
863 }
864
865 static int
866 update_paths (struct multipath * mpp)
867 {
868         int i, j;
869         struct pathgroup * pgp;
870         struct path * pp;
871
872         if (!mpp->pg)
873                 return 0;
874
875         vector_foreach_slot (mpp->pg, pgp, i) {
876                 if (!pgp->paths)
877                         continue;
878
879                 vector_foreach_slot (pgp->paths, pp, j) {
880                         if (!strlen(pp->dev)) {
881                                 if (devt2devname(pp->dev, pp->dev_t)) {
882                                         /*
883                                          * path is not in sysfs anymore
884                                          */
885                                         pp->state = PATH_DOWN;
886                                         continue;
887                                 }
888                                 pathinfo(pp, conf->hwtable,
889                                          DI_SYSFS | DI_CHECKER | \
890                                          DI_SERIAL | DI_PRIO);
891                                 continue;
892                         }
893                         if (pp->state == PATH_UNCHECKED)
894                                 pathinfo(pp, conf->hwtable, DI_CHECKER);
895
896                         if (!pp->priority)
897                                 pathinfo(pp, conf->hwtable, DI_PRIO);
898                 }
899         }
900         return 0;
901 }
902
903 static int
904 get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
905 {
906         int i;
907         struct multipath * mpp;
908
909         if (dm_get_maps(curmp, DEFAULT_TARGET))
910                 return 1;
911
912         vector_foreach_slot (curmp, mpp, i) {
913                 /*
914                  * discard out of scope maps
915                  */
916                 if (mpp->wwid && refwwid &&
917                     strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
918                         condlog(3, "skip map %s: out of scope", mpp->alias);
919                         free_multipath(mpp, KEEP_PATHS);
920                         vector_del_slot(curmp, i);
921                         i--;
922                         continue;
923                 }
924
925                 condlog(3, "params = %s", mpp->params);
926                 condlog(3, "status = %s", mpp->status);
927
928                 disassemble_map(pathvec, mpp->params, mpp);
929
930                 /*
931                  * disassemble_map() can add new paths to pathvec.
932                  * If not in "fast list mode", we need to fetch information
933                  * about them
934                  */
935                 if (conf->list != 1)
936                         update_paths(mpp);
937
938                 if (conf->list > 1)
939                         select_path_group(mpp);
940
941                 disassemble_status(mpp->status, mpp);
942
943                 if (conf->list)
944                         print_mp(mpp);
945
946                 if (!conf->dry_run)
947                         reinstate_paths(mpp);
948         }
949         return 0;
950 }
951
952
953 /*
954  * Return value:
955  *  -1: Retry
956  *   0: Success
957  *   1: Failure
958  */
959 static int
960 configure (void)
961 {
962         vector curmp = NULL;
963         vector pathvec = NULL;
964         int r = 1;
965         int di_flag = 0;
966         char * refwwid = NULL;
967         char * dev = NULL;
968
969         /*
970          * allocate core vectors to store paths and multipaths
971          */
972         curmp = vector_alloc();
973         pathvec = vector_alloc();
974
975         if (!curmp || !pathvec) {
976                 condlog(0, "can not allocate memory");
977                 goto out;
978         }
979
980         /*
981          * if we have a blacklisted device parameter, exit early
982          */
983         if (conf->dev) {
984                 if (!strncmp(conf->dev, "/dev/", 5) &&
985                     strlen(conf->dev) > 5)
986                         dev = conf->dev + 5;
987                 else
988                         dev = conf->dev;
989         }
990         
991         if (dev && blacklist(conf->blist, dev))
992                 goto out;
993         
994         condlog(3, "load path identifiers cache");
995         cache_load(pathvec);
996
997         if (conf->verbosity > 2)
998                 print_all_paths(pathvec, 1);
999
1000         /*
1001          * scope limiting must be translated into a wwid
1002          * failing the translation is fatal (by policy)
1003          */
1004         if (conf->dev) {
1005                 refwwid = get_refwwid(pathvec);
1006
1007                 if (!refwwid) {
1008                         condlog(3, "scope is nul");
1009                         goto out;
1010                 }
1011                 condlog(3, "scope limited to %s", refwwid);
1012         }
1013
1014         /*
1015          * get a path list
1016          */
1017         if (conf->dev)
1018                 di_flag = DI_WWID;
1019
1020         if (conf->list > 1)
1021                 /* extended path info '-ll' */
1022                 di_flag |= DI_SYSFS | DI_CHECKER;
1023         else if (conf->list)
1024                 /* minimum path info '-l' */
1025                 di_flag |= DI_SYSFS;
1026         else
1027                 /* maximum info */
1028                 di_flag = DI_ALL;
1029
1030         if (path_discovery(pathvec, conf, di_flag))
1031                 goto out;
1032
1033         if (conf->verbosity > 2)
1034                 print_all_paths(pathvec, 1);
1035
1036         get_path_layout(&pl, pathvec);
1037
1038         if (get_dm_mpvec(curmp, pathvec, refwwid))
1039                 goto out;
1040
1041         filter_pathvec(pathvec, refwwid);
1042
1043         if (conf->list)
1044                 goto out;
1045
1046         /*
1047          * core logic entry point
1048          */
1049         r = coalesce_paths(curmp, pathvec);
1050
1051 out:
1052         if (refwwid)
1053                 FREE(refwwid);
1054
1055         free_multipathvec(curmp, KEEP_PATHS);
1056         free_pathvec(pathvec, FREE_PATHS);
1057
1058         return r;
1059 }
1060
1061 int
1062 main (int argc, char *argv[])
1063 {
1064         int arg;
1065         extern char *optarg;
1066         extern int optind;
1067         int i, r;
1068
1069         if (getuid() != 0) {
1070                 fprintf(stderr, "need to be root\n");
1071                 exit(1);
1072         }
1073
1074         if (dm_prereq(DEFAULT_TARGET, 1, 0, 3))
1075                 exit(1);
1076
1077         if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
1078                 condlog(0, "multipath tools need sysfs mounted");
1079                 exit(1);
1080         }
1081         if (load_config(DEFAULT_CONFIGFILE))
1082                 exit(1);
1083
1084         while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:b:")) != EOF ) {
1085                 switch(arg) {
1086                 case 1: printf("optarg : %s\n",optarg);
1087                         break;
1088                 case 'v':
1089                         if (sizeof(optarg) > sizeof(char *) ||
1090                             !isdigit(optarg[0]))
1091                                 usage (argv[0]);
1092
1093                         conf->verbosity = atoi(optarg);
1094                         break;
1095                 case 'b':
1096                         conf->bindings_file = optarg;
1097                         break;
1098                 case 'd':
1099                         conf->dry_run = 1;
1100                         break;
1101                 case 'f':
1102                         conf->remove = FLUSH_ONE;
1103                         break;
1104                 case 'F':
1105                         conf->remove = FLUSH_ALL;
1106                         break;
1107                 case 'l':
1108                         conf->list = 1;
1109                         conf->dry_run = 1;
1110
1111                         if (optarg && !strncmp(optarg, "l", 1))
1112                                 conf->list++;
1113
1114                         break;
1115                 case 'M':
1116 #if _DEBUG_
1117                         debug = atoi(optarg);
1118 #endif
1119                         break;
1120                 case 'p':
1121                         conf->pgpolicy_flag = get_pgpolicy_id(optarg);
1122                         if (conf->pgpolicy_flag == -1) {
1123                                 printf("'%s' is not a valid policy\n", optarg);
1124                                 usage(argv[0]);
1125                         }                
1126                         break;
1127                 case ':':
1128                         fprintf(stderr, "Missing option arguement\n");
1129                         usage(argv[0]);        
1130                 case '?':
1131                         fprintf(stderr, "Unknown switch: %s\n", optarg);
1132                         usage(argv[0]);
1133                 default:
1134                         usage(argv[0]);
1135                 }
1136         }        
1137         if (optind < argc) {
1138                 conf->dev = MALLOC(FILE_NAME_SIZE);
1139
1140                 if (!conf->dev)
1141                         goto out;
1142
1143                 strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
1144
1145                 if (filepresent(conf->dev))
1146                         conf->dev_type = DEV_DEVNODE;
1147                 else if (sscanf(conf->dev, "%d:%d", &i, &i) == 2)
1148                         conf->dev_type = DEV_DEVT;
1149                 else
1150                         conf->dev_type = DEV_DEVMAP;
1151
1152         }
1153
1154         if (conf->remove == FLUSH_ONE) {
1155                 if (conf->dev_type == DEV_DEVMAP)
1156                         dm_flush_map(conf->dev, DEFAULT_TARGET);
1157                 else
1158                         condlog(0, "must provide a map name to remove");
1159
1160                 goto out;
1161         }
1162         else if (conf->remove == FLUSH_ALL) {
1163                 dm_flush_maps(DEFAULT_TARGET);
1164                 goto out;
1165         }
1166         while ((r = configure()) < 0)
1167                 condlog(3, "restart multipath configuration process");
1168         
1169 out:
1170         free_config(conf);
1171         dm_lib_release();
1172         dm_lib_exit();
1173 #ifdef _DEBUG_
1174         dbg_free_final(NULL);
1175 #endif
1176         return r;
1177 }