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