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