dmparser: Use find_path_by_dev()
[multipath-tools/.git] / libmultipath / dmparser.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  * Copyright (c) 2005 Stefan Bader, IBM
4  * Copyright (c) 2005 Edward Goggin, EMC
5  */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include "checkers.h"
11 #include "vector.h"
12 #include "memory.h"
13 #include "structs.h"
14 #include "util.h"
15 #include "debug.h"
16 #include "config.h"
17
18 #define WORD_SIZE 64
19
20 static int
21 merge_words (char ** dst, char * word, int space)
22 {
23         char * p = *dst;
24         int len;
25
26         len = strlen(*dst) + strlen(word) + space;
27         *dst = REALLOC(*dst, len + 1);
28
29         if (!*dst) {
30                 free(p);
31                 return 1;
32         }
33
34         p = *dst;
35
36         while (*p != '\0')
37                 p++;
38
39         while (space) {
40                 *p = ' ';
41                 p++;
42                 space--;
43         }
44         strncpy(p, word, strlen(word) + 1);
45
46         return 0;
47 }
48
49 /*
50  * Transforms the path group vector into a proper device map string
51  */
52 int
53 assemble_map (struct multipath * mp, char * params, int len)
54 {
55         int i, j;
56         int shift, freechar;
57         int minio;
58         int nr_priority_groups, initial_pg_nr;
59         char * p, * f;
60         char no_path_retry[] = "queue_if_no_path";
61         char retain_hwhandler[] = "retain_attached_hw_handler";
62         struct pathgroup * pgp;
63         struct path * pp;
64
65         minio = mp->minio;
66         p = params;
67         freechar = len;
68
69         nr_priority_groups = VECTOR_SIZE(mp->pg);
70         initial_pg_nr = (nr_priority_groups ? mp->bestpg : 0);
71
72         f = STRDUP(mp->features);
73
74         /*
75          * We have to set 'queue_if_no_path' here even
76          * to avoid path failures during map reload.
77          */
78         if (mp->no_path_retry == NO_PATH_RETRY_UNDEF ||
79             mp->no_path_retry == NO_PATH_RETRY_FAIL) {
80                 /* remove queue_if_no_path settings */
81                 condlog(3, "%s: remove queue_if_no_path from '%s'",
82                         mp->alias, mp->features);
83                 remove_feature(&f, no_path_retry);
84         } else {
85                 add_feature(&f, no_path_retry);
86         }
87         if (mp->retain_hwhandler == RETAIN_HWHANDLER_ON)
88                 add_feature(&f, retain_hwhandler);
89
90         shift = snprintf(p, freechar, "%s %s %i %i",
91                          f, mp->hwhandler,
92                          nr_priority_groups, initial_pg_nr);
93
94         FREE(f);
95
96         if (shift >= freechar) {
97                 condlog(0, "%s: params too small", mp->alias);
98                 return 1;
99         }
100         p += shift;
101         freechar -= shift;
102
103         vector_foreach_slot (mp->pg, pgp, i) {
104                 pgp = VECTOR_SLOT(mp->pg, i);
105                 shift = snprintf(p, freechar, " %s %i 1", mp->selector,
106                                  VECTOR_SIZE(pgp->paths));
107                 if (shift >= freechar) {
108                         condlog(0, "%s: params too small", mp->alias);
109                         return 1;
110                 }
111                 p += shift;
112                 freechar -= shift;
113
114                 vector_foreach_slot (pgp->paths, pp, j) {
115                         int tmp_minio = minio;
116
117                         if (mp->rr_weight == RR_WEIGHT_PRIO
118                             && pp->priority > 0)
119                                 tmp_minio = minio * pp->priority;
120                         if (!strlen(pp->dev_t) ) {
121                                 condlog(0, "dev_t not set for '%s'", pp->dev);
122                                 return 1;
123                         }
124                         shift = snprintf(p, freechar, " %s %d",
125                                          pp->dev_t, tmp_minio);
126                         if (shift >= freechar) {
127                                 condlog(0, "%s: params too small", mp->alias);
128                                 return 1;
129                         }
130                         p += shift;
131                         freechar -= shift;
132                 }
133         }
134         if (freechar < 1) {
135                 condlog(0, "%s: params too small", mp->alias);
136                 return 1;
137         }
138         snprintf(p, 1, "\n");
139
140         condlog(3, "%s: assembled map [%s]", mp->alias, params);
141         return 0;
142 }
143
144 extern int
145 disassemble_map (vector pathvec, char * params, struct multipath * mpp)
146 {
147         char * word;
148         char * p;
149         int i, j, k;
150         int num_features = 0;
151         int num_hwhandler = 0;
152         int num_pg = 0;
153         int num_pg_args = 0;
154         int num_paths = 0;
155         int num_paths_args = 0;
156         int def_minio = 0;
157         int no_path_retry = NO_PATH_RETRY_UNDEF;
158         struct path * pp;
159         struct pathgroup * pgp;
160
161         p = params;
162
163         condlog(3, "%s: disassemble map [%s]", mpp->alias, params);
164
165         /*
166          * features
167          */
168         p += get_word(p, &mpp->features);
169
170         if (!mpp->features)
171                 return 1;
172
173         num_features = atoi(mpp->features);
174         no_path_retry = mpp->no_path_retry;
175         mpp->no_path_retry = NO_PATH_RETRY_UNDEF;
176
177         for (i = 0; i < num_features; i++) {
178                 p += get_word(p, &word);
179
180                 if (!word)
181                         return 1;
182
183                 if (merge_words(&mpp->features, word, 1)) {
184                         FREE(word);
185                         return 1;
186                 }
187                 if ((mpp->no_path_retry == NO_PATH_RETRY_UNDEF) ||
188                         (mpp->no_path_retry == NO_PATH_RETRY_FAIL) ||
189                         (mpp->no_path_retry == NO_PATH_RETRY_QUEUE))
190                         setup_feature(mpp, word);
191
192                 FREE(word);
193         }
194
195         /*
196          * Reset no_path_retry.
197          * - if not set from features
198          * - if queue_if_no_path is set from features but
199          *   no_path_retry > 0 is selected.
200          */
201         if ((mpp->no_path_retry == NO_PATH_RETRY_UNDEF ||
202              mpp->no_path_retry == NO_PATH_RETRY_QUEUE) &&
203             mpp->no_path_retry != no_path_retry)
204                 mpp->no_path_retry = no_path_retry;
205
206         /*
207          * hwhandler
208          */
209         p += get_word(p, &mpp->hwhandler);
210
211         if (!mpp->hwhandler)
212                 return 1;
213
214         num_hwhandler = atoi(mpp->hwhandler);
215
216         for (i = 0; i < num_hwhandler; i++) {
217                 p += get_word(p, &word);
218
219                 if (!word)
220                         return 1;
221
222                 if (merge_words(&mpp->hwhandler, word, 1)) {
223                         FREE(word);
224                         return 1;
225                 }
226                 FREE(word);
227         }
228
229         /*
230          * nb of path groups
231          */
232         p += get_word(p, &word);
233
234         if (!word)
235                 return 1;
236
237         num_pg = atoi(word);
238         FREE(word);
239
240         if (num_pg > 0) {
241                 if (!mpp->pg) {
242                         mpp->pg = vector_alloc();
243                         if (!mpp->pg)
244                                 return 1;
245                 }
246         } else {
247                 free_pgvec(mpp->pg, KEEP_PATHS);
248                 mpp->pg = NULL;
249         }
250
251         /*
252          * first pg to try
253          */
254         p += get_word(p, &word);
255
256         if (!word)
257                 goto out;
258
259         mpp->nextpg = atoi(word);
260         FREE(word);
261
262         for (i = 0; i < num_pg; i++) {
263                 /*
264                  * selector
265                  */
266
267                 if (!mpp->selector) {
268                         p += get_word(p, &mpp->selector);
269
270                         if (!mpp->selector)
271                                 goto out;
272
273                         /*
274                          * selector args
275                          */
276                         p += get_word(p, &word);
277
278                         if (!word)
279                                 goto out;
280
281                         num_pg_args = atoi(word);
282
283                         if (merge_words(&mpp->selector, word, 1)) {
284                                 goto out1;
285                         }
286                         FREE(word);
287                 } else {
288                         p += get_word(p, NULL);
289                         p += get_word(p, NULL);
290                 }
291
292                 for (j = 0; j < num_pg_args; j++)
293                         p += get_word(p, NULL);
294
295                 /*
296                  * paths
297                  */
298                 pgp = alloc_pathgroup();
299
300                 if (!pgp)
301                         goto out;
302
303                 if (store_pathgroup(mpp->pg, pgp))
304                         goto out;
305
306                 p += get_word(p, &word);
307
308                 if (!word)
309                         goto out;
310
311                 num_paths = atoi(word);
312                 FREE(word);
313
314                 p += get_word(p, &word);
315
316                 if (!word)
317                         goto out;
318
319                 num_paths_args = atoi(word);
320                 FREE(word);
321
322                 for (j = 0; j < num_paths; j++) {
323                         char devname[FILE_NAME_SIZE];
324
325                         pp = NULL;
326                         p += get_word(p, &word);
327
328                         if (!word)
329                                 goto out;
330
331                         if (devt2devname(devname, FILE_NAME_SIZE, word)) {
332                                 condlog(2, "%s: cannot find block device",
333                                         word);
334                                 FREE(word);
335                                 continue;
336                         }
337
338                         if (pathvec)
339                                 pp = find_path_by_dev(pathvec, devname);
340
341                         if (!pp) {
342                                 pp = alloc_path();
343
344                                 if (!pp)
345                                         goto out1;
346
347                                 strncpy(pp->dev_t, word, BLK_DEV_SIZE);
348                                 strncpy(pp->dev, devname, FILE_NAME_SIZE);
349                                 if (strlen(mpp->wwid)) {
350                                         strncpy(pp->wwid, mpp->wwid, WWID_SIZE);
351                                 }
352                                 /* Only call this in multipath client mode */
353                                 if (!conf->daemon && store_path(pathvec, pp))
354                                         goto out1;
355                         } else {
356                                 if (!strlen(pp->wwid) &&
357                                     strlen(mpp->wwid))
358                                         strncpy(pp->wwid, mpp->wwid, WWID_SIZE);
359                         }
360                         FREE(word);
361
362                         if (store_path(pgp->paths, pp))
363                                 goto out;
364
365                         /*
366                          * Update wwid for multipaths which are not setup
367                          * in the get_dm_mpvec() code path
368                          */
369                         if (!strlen(mpp->wwid))
370                                 strncpy(mpp->wwid, pp->wwid, WWID_SIZE);
371
372                         /*
373                          * Update wwid for paths which may not have been
374                          * active at the time the getuid callout was run
375                          */
376                         else if (!strlen(pp->wwid))
377                                 strncpy(pp->wwid, mpp->wwid, WWID_SIZE);
378
379                         pgp->id ^= (long)pp;
380                         pp->pgindex = i + 1;
381
382                         for (k = 0; k < num_paths_args; k++)
383                                 if (k == 0) {
384                                         if (!strncmp(mpp->selector,
385                                                      "round-robin", 11)) {
386                                                 p += get_word(p, &word);
387                                                 def_minio = atoi(word);
388
389                                                 if (mpp->rr_weight == RR_WEIGHT_PRIO
390                                                     && pp->priority > 0)
391                                                         def_minio /= pp->priority;
392
393                                                 FREE(word);
394                                         } else {
395                                                 p += get_word(p, NULL);
396                                                 def_minio = 0;
397                                         }
398
399                                         if (def_minio != mpp->minio)
400                                                 mpp->minio = def_minio;
401                                 }
402                                 else
403                                         p += get_word(p, NULL);
404
405                 }
406         }
407         return 0;
408 out1:
409         FREE(word);
410 out:
411         free_pgvec(mpp->pg, KEEP_PATHS);
412         mpp->pg = NULL;
413         return 1;
414 }
415
416 extern int
417 disassemble_status (char * params, struct multipath * mpp)
418 {
419         char * word;
420         char * p;
421         int i, j, k;
422         int num_feature_args;
423         int num_hwhandler_args;
424         int num_pg;
425         int num_pg_args;
426         int num_paths;
427         int def_minio = 0;
428         struct path * pp;
429         struct pathgroup * pgp;
430
431         p = params;
432
433         condlog(3, "%s: disassemble status [%s]", mpp->alias, params);
434
435         /*
436          * features
437          */
438         p += get_word(p, &word);
439
440         if (!word)
441                 return 1;
442
443         num_feature_args = atoi(word);
444         FREE(word);
445
446         for (i = 0; i < num_feature_args; i++) {
447                 if (i == 1) {
448                         p += get_word(p, &word);
449
450                         if (!word)
451                                 return 1;
452
453                         mpp->queuedio = atoi(word);
454                         FREE(word);
455                         continue;
456                 }
457                 /* unknown */
458                 p += get_word(p, NULL);
459         }
460         /*
461          * hwhandler
462          */
463         p += get_word(p, &word);
464
465         if (!word)
466                 return 1;
467
468         num_hwhandler_args = atoi(word);
469         FREE(word);
470
471         for (i = 0; i < num_hwhandler_args; i++)
472                 p += get_word(p, NULL);
473
474         /*
475          * nb of path groups
476          */
477         p += get_word(p, &word);
478
479         if (!word)
480                 return 1;
481
482         num_pg = atoi(word);
483         FREE(word);
484
485         if (num_pg == 0)
486                 return 0;
487
488         /*
489          * next pg to try
490          */
491         p += get_word(p, NULL);
492
493         if (VECTOR_SIZE(mpp->pg) < num_pg)
494                 return 1;
495
496         for (i = 0; i < num_pg; i++) {
497                 pgp = VECTOR_SLOT(mpp->pg, i);
498                 /*
499                  * PG status
500                  */
501                 p += get_word(p, &word);
502
503                 if (!word)
504                         return 1;
505
506                 switch (*word) {
507                 case 'D':
508                         pgp->status = PGSTATE_DISABLED;
509                         break;
510                 case 'A':
511                         pgp->status = PGSTATE_ACTIVE;
512                         break;
513                 case 'E':
514                         pgp->status = PGSTATE_ENABLED;
515                         break;
516                 default:
517                         pgp->status = PGSTATE_UNDEF;
518                         break;
519                 }
520                 FREE(word);
521
522                 /*
523                  * PG Status (discarded, would be '0' anyway)
524                  */
525                 p += get_word(p, NULL);
526
527                 p += get_word(p, &word);
528
529                 if (!word)
530                         return 1;
531
532                 num_paths = atoi(word);
533                 FREE(word);
534
535                 p += get_word(p, &word);
536
537                 if (!word)
538                         return 1;
539
540                 num_pg_args = atoi(word);
541                 FREE(word);
542
543                 if (VECTOR_SIZE(pgp->paths) < num_paths)
544                         return 1;
545
546                 for (j = 0; j < num_paths; j++) {
547                         pp = VECTOR_SLOT(pgp->paths, j);
548                         /*
549                          * path
550                          */
551                         p += get_word(p, NULL);
552
553                         /*
554                          * path status
555                          */
556                         p += get_word(p, &word);
557
558                         if (!word)
559                                 return 1;
560
561                         switch (*word) {
562                         case 'F':
563                                 pp->dmstate = PSTATE_FAILED;
564                                 break;
565                         case 'A':
566                                 pp->dmstate = PSTATE_ACTIVE;
567                                 break;
568                         default:
569                                 break;
570                         }
571                         FREE(word);
572                         /*
573                          * fail count
574                          */
575                         p += get_word(p, &word);
576
577                         if (!word)
578                                 return 1;
579
580                         pp->failcount = atoi(word);
581                         FREE(word);
582
583                         /*
584                          * selector args
585                          */
586                         for (k = 0; k < num_pg_args; k++) {
587                                 if (!strncmp(mpp->selector,
588                                              "least-pending", 13)) {
589                                         p += get_word(p, &word);
590                                         if (sscanf(word,"%d:*d",
591                                                    &def_minio) == 1 &&
592                                             def_minio != mpp->minio)
593                                                         mpp->minio = def_minio;
594                                 } else
595                                         p += get_word(p, NULL);
596                         }
597                 }
598         }
599         return 0;
600 }