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