74c9215506ddd171e58b518682c850a3e75c4f1c
[platform/upstream/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 #include <assert.h>
10
11 #include "checkers.h"
12 #include "vector.h"
13 #include "structs.h"
14 #include "util.h"
15 #include "debug.h"
16 #include "dmparser.h"
17 #include "strbuf.h"
18
19 #define WORD_SIZE 64
20
21 static int
22 merge_words(char **dst, const char *word)
23 {
24         char * p = *dst;
25         int len, dstlen;
26
27         dstlen = strlen(*dst);
28         len = dstlen + strlen(word) + 2;
29         *dst = realloc(*dst, len);
30
31         if (!*dst) {
32                 free(p);
33                 return 1;
34         }
35
36         p = *dst + dstlen;
37         *p = ' ';
38         ++p;
39         strncpy(p, word, len - dstlen - 1);
40
41         return 0;
42 }
43
44 /*
45  * Transforms the path group vector into a proper device map string
46  */
47 int assemble_map(struct multipath *mp, char **params)
48 {
49         static const char no_path_retry[] = "queue_if_no_path";
50         static const char retain_hwhandler[] = "retain_attached_hw_handler";
51         int i, j;
52         int minio;
53         int nr_priority_groups, initial_pg_nr;
54         STRBUF_ON_STACK(buff);
55         struct pathgroup * pgp;
56         struct path * pp;
57
58         minio = mp->minio;
59
60         nr_priority_groups = VECTOR_SIZE(mp->pg);
61         initial_pg_nr = (nr_priority_groups ? mp->bestpg : 0);
62
63         if (mp->no_path_retry != NO_PATH_RETRY_UNDEF  &&
64             mp->no_path_retry != NO_PATH_RETRY_FAIL) {
65                 add_feature(&mp->features, no_path_retry);
66         }
67         if (mp->retain_hwhandler == RETAIN_HWHANDLER_ON &&
68             get_linux_version_code() < KERNEL_VERSION(4, 3, 0))
69                 add_feature(&mp->features, retain_hwhandler);
70
71         if (print_strbuf(&buff, "%s %s %i %i", mp->features, mp->hwhandler,
72                          nr_priority_groups, initial_pg_nr) < 0)
73                 goto err;
74
75         vector_foreach_slot (mp->pg, pgp, i) {
76                 pgp = VECTOR_SLOT(mp->pg, i);
77                 if (print_strbuf(&buff, " %s %i 1", mp->selector,
78                                  VECTOR_SIZE(pgp->paths)) < 0)
79                         goto err;
80
81                 vector_foreach_slot (pgp->paths, pp, j) {
82                         int tmp_minio = minio;
83
84                         if (mp->rr_weight == RR_WEIGHT_PRIO
85                             && pp->priority > 0)
86                                 tmp_minio = minio * pp->priority;
87                         if (!strlen(pp->dev_t) ) {
88                                 condlog(0, "dev_t not set for '%s'", pp->dev);
89                                 goto err;
90                         }
91                         if (print_strbuf(&buff, " %s %d", pp->dev_t, tmp_minio) < 0)
92                                 goto err;
93                 }
94         }
95
96         *params = steal_strbuf_str(&buff);
97         condlog(4, "%s: assembled map [%s]", mp->alias, *params);
98         return 0;
99
100 err:
101         return 1;
102 }
103
104 /*
105  * Caution callers: If this function encounters yet unkown path devices, it
106  * adds them uninitialized to the mpp.
107  * Call update_pathvec_from_dm() after this function to make sure
108  * all data structures are in a sane state.
109  */
110 int disassemble_map(const struct _vector *pathvec,
111                     const char *params, struct multipath *mpp)
112 {
113         char * word;
114         const 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         assert(pathvec != NULL);
127         p = params;
128
129         condlog(4, "%s: disassemble map [%s]", mpp->alias, params);
130
131         /*
132          * features
133          */
134         p += get_word(p, &mpp->features);
135
136         if (!mpp->features)
137                 return 1;
138
139         num_features = atoi(mpp->features);
140
141         for (i = 0; i < num_features; i++) {
142                 p += get_word(p, &word);
143
144                 if (!word)
145                         return 1;
146
147                 if (merge_words(&mpp->features, word)) {
148                         free(word);
149                         return 1;
150                 }
151
152                 free(word);
153         }
154
155         /*
156          * hwhandler
157          */
158         p += get_word(p, &mpp->hwhandler);
159
160         if (!mpp->hwhandler)
161                 return 1;
162
163         num_hwhandler = atoi(mpp->hwhandler);
164
165         for (i = 0; i < num_hwhandler; i++) {
166                 p += get_word(p, &word);
167
168                 if (!word)
169                         return 1;
170
171                 if (merge_words(&mpp->hwhandler, word)) {
172                         free(word);
173                         return 1;
174                 }
175                 free(word);
176         }
177
178         /*
179          * nb of path groups
180          */
181         p += get_word(p, &word);
182
183         if (!word)
184                 return 1;
185
186         num_pg = atoi(word);
187         free(word);
188
189         if (num_pg > 0) {
190                 if (!mpp->pg) {
191                         mpp->pg = vector_alloc();
192                         if (!mpp->pg)
193                                 return 1;
194                 }
195         } else {
196                 free_pgvec(mpp->pg, KEEP_PATHS);
197                 mpp->pg = NULL;
198         }
199
200         /*
201          * first pg to try
202          */
203         p += get_word(p, &word);
204
205         if (!word)
206                 goto out;
207
208         mpp->nextpg = atoi(word);
209         free(word);
210
211         for (i = 0; i < num_pg; i++) {
212                 /*
213                  * selector
214                  */
215
216                 if (!mpp->selector) {
217                         p += get_word(p, &mpp->selector);
218
219                         if (!mpp->selector)
220                                 goto out;
221
222                         /*
223                          * selector args
224                          */
225                         p += get_word(p, &word);
226
227                         if (!word)
228                                 goto out;
229
230                         num_pg_args = atoi(word);
231
232                         if (merge_words(&mpp->selector, word))
233                                 goto out1;
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 (add_pathgroup(mpp, pgp)) {
252                         free_pathgroup(pgp, KEEP_PATHS);
253                         goto out;
254                 }
255
256                 p += get_word(p, &word);
257
258                 if (!word)
259                         goto out;
260
261                 num_paths = atoi(word);
262                 free(word);
263
264                 p += get_word(p, &word);
265
266                 if (!word)
267                         goto out;
268
269                 num_paths_args = atoi(word);
270                 free(word);
271
272                 for (j = 0; j < num_paths; j++) {
273                         pp = NULL;
274                         p += get_word(p, &word);
275
276                         if (!word)
277                                 goto out;
278
279                         pp = find_path_by_devt(pathvec, word);
280
281                         if (!pp) {
282                                 pp = alloc_path();
283
284                                 if (!pp)
285                                         goto out1;
286
287                                 strlcpy(pp->dev_t, word, BLK_DEV_SIZE);
288
289                                 if (store_path(pgp->paths, pp)) {
290                                         free_path(pp);
291                                         goto out1;
292                                 }
293                         } else if (store_path(pgp->paths, pp))
294                                 goto out1;
295
296                         free(word);
297
298                         pgp->id ^= (long)pp;
299                         pp->pgindex = i + 1;
300
301                         for (k = 0; k < num_paths_args; k++)
302                                 if (k == 0) {
303                                         p += get_word(p, &word);
304                                         def_minio = atoi(word);
305                                         free(word);
306
307                                         if (!strncmp(mpp->selector,
308                                                      "round-robin", 11)) {
309
310                                                 if (mpp->rr_weight == RR_WEIGHT_PRIO
311                                                     && pp->priority > 0)
312                                                         def_minio /= pp->priority;
313
314                                         }
315
316                                         if (def_minio != mpp->minio)
317                                                 mpp->minio = def_minio;
318                                 }
319                                 else
320                                         p += get_word(p, NULL);
321
322                 }
323         }
324         return 0;
325 out1:
326         free(word);
327 out:
328         free_pgvec(mpp->pg, KEEP_PATHS);
329         mpp->pg = NULL;
330         return 1;
331 }
332
333 int disassemble_status(const char *params, struct multipath *mpp)
334 {
335         char *word;
336         const char *p;
337         int i, j, k;
338         int num_feature_args;
339         int num_hwhandler_args;
340         int num_pg;
341         int num_pg_args;
342         int num_paths;
343         int def_minio = 0;
344         struct path * pp;
345         struct pathgroup * pgp;
346
347         p = params;
348
349         condlog(4, "%s: disassemble status [%s]", mpp->alias, params);
350
351         /*
352          * features
353          */
354         p += get_word(p, &word);
355
356         if (!word)
357                 return 1;
358
359         num_feature_args = atoi(word);
360         free(word);
361
362         for (i = 0; i < num_feature_args; i++) {
363                 if (i == 1) {
364                         p += get_word(p, &word);
365
366                         if (!word)
367                                 return 1;
368
369                         mpp->queuedio = atoi(word);
370                         free(word);
371                         continue;
372                 }
373                 /* unknown */
374                 p += get_word(p, NULL);
375         }
376         /*
377          * hwhandler
378          */
379         p += get_word(p, &word);
380
381         if (!word)
382                 return 1;
383
384         num_hwhandler_args = atoi(word);
385         free(word);
386
387         for (i = 0; i < num_hwhandler_args; i++)
388                 p += get_word(p, NULL);
389
390         /*
391          * nb of path groups
392          */
393         p += get_word(p, &word);
394
395         if (!word)
396                 return 1;
397
398         num_pg = atoi(word);
399         free(word);
400
401         if (num_pg == 0)
402                 return 0;
403
404         /*
405          * next pg to try
406          */
407         p += get_word(p, NULL);
408
409         if (VECTOR_SIZE(mpp->pg) < num_pg)
410                 return 1;
411
412         for (i = 0; i < num_pg; i++) {
413                 pgp = VECTOR_SLOT(mpp->pg, i);
414                 /*
415                  * PG status
416                  */
417                 p += get_word(p, &word);
418
419                 if (!word)
420                         return 1;
421
422                 switch (*word) {
423                 case 'D':
424                         pgp->status = PGSTATE_DISABLED;
425                         break;
426                 case 'A':
427                         pgp->status = PGSTATE_ACTIVE;
428                         break;
429                 case 'E':
430                         pgp->status = PGSTATE_ENABLED;
431                         break;
432                 default:
433                         pgp->status = PGSTATE_UNDEF;
434                         break;
435                 }
436                 free(word);
437
438                 /*
439                  * PG Status (discarded, would be '0' anyway)
440                  */
441                 p += get_word(p, NULL);
442
443                 p += get_word(p, &word);
444
445                 if (!word)
446                         return 1;
447
448                 num_paths = atoi(word);
449                 free(word);
450
451                 p += get_word(p, &word);
452
453                 if (!word)
454                         return 1;
455
456                 num_pg_args = atoi(word);
457                 free(word);
458
459                 if (VECTOR_SIZE(pgp->paths) < num_paths)
460                         return 1;
461
462                 for (j = 0; j < num_paths; j++) {
463                         pp = VECTOR_SLOT(pgp->paths, j);
464                         /*
465                          * path
466                          */
467                         p += get_word(p, NULL);
468
469                         /*
470                          * path status
471                          */
472                         p += get_word(p, &word);
473
474                         if (!word)
475                                 return 1;
476
477                         switch (*word) {
478                         case 'F':
479                                 pp->dmstate = PSTATE_FAILED;
480                                 break;
481                         case 'A':
482                                 pp->dmstate = PSTATE_ACTIVE;
483                                 break;
484                         default:
485                                 break;
486                         }
487                         free(word);
488                         /*
489                          * fail count
490                          */
491                         p += get_word(p, &word);
492
493                         if (!word)
494                                 return 1;
495
496                         pp->failcount = atoi(word);
497                         free(word);
498
499                         /*
500                          * selector args
501                          */
502                         for (k = 0; k < num_pg_args; k++) {
503                                 if (!strncmp(mpp->selector,
504                                              "least-pending", 13)) {
505                                         p += get_word(p, &word);
506                                         if (sscanf(word,"%d:*d",
507                                                    &def_minio) == 1 &&
508                                             def_minio != mpp->minio)
509                                                         mpp->minio = def_minio;
510                                         free(word);
511                                 } else
512                                         p += get_word(p, NULL);
513                         }
514                 }
515         }
516         return 0;
517 }