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