dmparser: use 'is_daemon' as argument for disassemble_map()
[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 = *dst;
23         int len;
24
25         len = strlen(*dst) + strlen(word) + space;
26         *dst = REALLOC(*dst, len + 1);
27
28         if (!*dst) {
29                 free(p);
30                 return 1;
31         }
32
33         p = *dst;
34
35         while (*p != '\0')
36                 p++;
37
38         while (space) {
39                 *p = ' ';
40                 p++;
41                 space--;
42         }
43         strncpy(p, word, strlen(word) + 1);
44
45         return 0;
46 }
47
48 /*
49  * Transforms the path group vector into a proper device map string
50  */
51 int
52 assemble_map (struct multipath * mp, char * params, int len)
53 {
54         int i, j;
55         int shift, freechar;
56         int minio;
57         int nr_priority_groups, initial_pg_nr;
58         char * p, * f;
59         char no_path_retry[] = "queue_if_no_path";
60         char retain_hwhandler[] = "retain_attached_hw_handler";
61         struct pathgroup * pgp;
62         struct path * pp;
63
64         minio = mp->minio;
65         p = params;
66         freechar = len;
67
68         nr_priority_groups = VECTOR_SIZE(mp->pg);
69         initial_pg_nr = (nr_priority_groups ? mp->bestpg : 0);
70
71         f = STRDUP(mp->features);
72
73         /*
74          * We have to set 'queue_if_no_path' here even
75          * to avoid path failures during map reload.
76          */
77         if (mp->no_path_retry == NO_PATH_RETRY_UNDEF ||
78             mp->no_path_retry == NO_PATH_RETRY_FAIL) {
79                 /* remove queue_if_no_path settings */
80                 condlog(3, "%s: remove queue_if_no_path from '%s'",
81                         mp->alias, mp->features);
82                 remove_feature(&f, no_path_retry);
83         } else {
84                 add_feature(&f, no_path_retry);
85         }
86         if (mp->retain_hwhandler == RETAIN_HWHANDLER_ON)
87                 add_feature(&f, retain_hwhandler);
88
89         shift = snprintf(p, freechar, "%s %s %i %i",
90                          f, mp->hwhandler,
91                          nr_priority_groups, initial_pg_nr);
92
93         FREE(f);
94
95         if (shift >= freechar) {
96                 condlog(0, "%s: params too small", mp->alias);
97                 return 1;
98         }
99         p += shift;
100         freechar -= shift;
101
102         vector_foreach_slot (mp->pg, pgp, i) {
103                 pgp = VECTOR_SLOT(mp->pg, i);
104                 shift = snprintf(p, freechar, " %s %i 1", mp->selector,
105                                  VECTOR_SIZE(pgp->paths));
106                 if (shift >= freechar) {
107                         condlog(0, "%s: params too small", mp->alias);
108                         return 1;
109                 }
110                 p += shift;
111                 freechar -= shift;
112
113                 vector_foreach_slot (pgp->paths, pp, j) {
114                         int tmp_minio = minio;
115
116                         if (mp->rr_weight == RR_WEIGHT_PRIO
117                             && pp->priority > 0)
118                                 tmp_minio = minio * pp->priority;
119                         if (!strlen(pp->dev_t) ) {
120                                 condlog(0, "dev_t not set for '%s'", pp->dev);
121                                 return 1;
122                         }
123                         shift = snprintf(p, freechar, " %s %d",
124                                          pp->dev_t, tmp_minio);
125                         if (shift >= freechar) {
126                                 condlog(0, "%s: params too small", mp->alias);
127                                 return 1;
128                         }
129                         p += shift;
130                         freechar -= shift;
131                 }
132         }
133         if (freechar < 1) {
134                 condlog(0, "%s: params too small", mp->alias);
135                 return 1;
136         }
137         snprintf(p, 1, "\n");
138
139         condlog(3, "%s: assembled map [%s]", mp->alias, params);
140         return 0;
141 }
142
143 extern int
144 disassemble_map (vector pathvec, char * params, struct multipath * mpp,
145                  int is_daemon)
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 - 1);
348                                 strncpy(pp->dev, devname, FILE_NAME_SIZE - 1);
349                                 if (strlen(mpp->wwid)) {
350                                         strncpy(pp->wwid, mpp->wwid,
351                                                 WWID_SIZE - 1);
352                                 }
353                                 /* Only call this in multipath client mode */
354                                 if (!is_daemon && store_path(pathvec, pp))
355                                         goto out1;
356                         } else {
357                                 if (!strlen(pp->wwid) &&
358                                     strlen(mpp->wwid))
359                                         strncpy(pp->wwid, mpp->wwid,
360                                                 WWID_SIZE - 1);
361                         }
362                         FREE(word);
363
364                         if (store_path(pgp->paths, pp))
365                                 goto out;
366
367                         /*
368                          * Update wwid for multipaths which are not setup
369                          * in the get_dm_mpvec() code path
370                          */
371                         if (!strlen(mpp->wwid))
372                                 strncpy(mpp->wwid, pp->wwid,
373                                         WWID_SIZE - 1);
374
375                         /*
376                          * Update wwid for paths which may not have been
377                          * active at the time the getuid callout was run
378                          */
379                         else if (!strlen(pp->wwid))
380                                 strncpy(pp->wwid, mpp->wwid,
381                                         WWID_SIZE - 1);
382
383                         pgp->id ^= (long)pp;
384                         pp->pgindex = i + 1;
385
386                         for (k = 0; k < num_paths_args; k++)
387                                 if (k == 0) {
388                                         if (!strncmp(mpp->selector,
389                                                      "round-robin", 11)) {
390                                                 p += get_word(p, &word);
391                                                 def_minio = atoi(word);
392
393                                                 if (mpp->rr_weight == RR_WEIGHT_PRIO
394                                                     && pp->priority > 0)
395                                                         def_minio /= pp->priority;
396
397                                                 FREE(word);
398                                         } else {
399                                                 p += get_word(p, NULL);
400                                                 def_minio = 0;
401                                         }
402
403                                         if (def_minio != mpp->minio)
404                                                 mpp->minio = def_minio;
405                                 }
406                                 else
407                                         p += get_word(p, NULL);
408
409                 }
410         }
411         return 0;
412 out1:
413         FREE(word);
414 out:
415         free_pgvec(mpp->pg, KEEP_PATHS);
416         mpp->pg = NULL;
417         return 1;
418 }
419
420 extern int
421 disassemble_status (char * params, struct multipath * mpp)
422 {
423         char * word;
424         char * p;
425         int i, j, k;
426         int num_feature_args;
427         int num_hwhandler_args;
428         int num_pg;
429         int num_pg_args;
430         int num_paths;
431         int def_minio = 0;
432         struct path * pp;
433         struct pathgroup * pgp;
434
435         p = params;
436
437         condlog(3, "%s: disassemble status [%s]", mpp->alias, params);
438
439         /*
440          * features
441          */
442         p += get_word(p, &word);
443
444         if (!word)
445                 return 1;
446
447         num_feature_args = atoi(word);
448         FREE(word);
449
450         for (i = 0; i < num_feature_args; i++) {
451                 if (i == 1) {
452                         p += get_word(p, &word);
453
454                         if (!word)
455                                 return 1;
456
457                         mpp->queuedio = atoi(word);
458                         FREE(word);
459                         continue;
460                 }
461                 /* unknown */
462                 p += get_word(p, NULL);
463         }
464         /*
465          * hwhandler
466          */
467         p += get_word(p, &word);
468
469         if (!word)
470                 return 1;
471
472         num_hwhandler_args = atoi(word);
473         FREE(word);
474
475         for (i = 0; i < num_hwhandler_args; i++)
476                 p += get_word(p, NULL);
477
478         /*
479          * nb of path groups
480          */
481         p += get_word(p, &word);
482
483         if (!word)
484                 return 1;
485
486         num_pg = atoi(word);
487         FREE(word);
488
489         if (num_pg == 0)
490                 return 0;
491
492         /*
493          * next pg to try
494          */
495         p += get_word(p, NULL);
496
497         if (VECTOR_SIZE(mpp->pg) < num_pg)
498                 return 1;
499
500         for (i = 0; i < num_pg; i++) {
501                 pgp = VECTOR_SLOT(mpp->pg, i);
502                 /*
503                  * PG status
504                  */
505                 p += get_word(p, &word);
506
507                 if (!word)
508                         return 1;
509
510                 switch (*word) {
511                 case 'D':
512                         pgp->status = PGSTATE_DISABLED;
513                         break;
514                 case 'A':
515                         pgp->status = PGSTATE_ACTIVE;
516                         break;
517                 case 'E':
518                         pgp->status = PGSTATE_ENABLED;
519                         break;
520                 default:
521                         pgp->status = PGSTATE_UNDEF;
522                         break;
523                 }
524                 FREE(word);
525
526                 /*
527                  * PG Status (discarded, would be '0' anyway)
528                  */
529                 p += get_word(p, NULL);
530
531                 p += get_word(p, &word);
532
533                 if (!word)
534                         return 1;
535
536                 num_paths = atoi(word);
537                 FREE(word);
538
539                 p += get_word(p, &word);
540
541                 if (!word)
542                         return 1;
543
544                 num_pg_args = atoi(word);
545                 FREE(word);
546
547                 if (VECTOR_SIZE(pgp->paths) < num_paths)
548                         return 1;
549
550                 for (j = 0; j < num_paths; j++) {
551                         pp = VECTOR_SLOT(pgp->paths, j);
552                         /*
553                          * path
554                          */
555                         p += get_word(p, NULL);
556
557                         /*
558                          * path status
559                          */
560                         p += get_word(p, &word);
561
562                         if (!word)
563                                 return 1;
564
565                         switch (*word) {
566                         case 'F':
567                                 pp->dmstate = PSTATE_FAILED;
568                                 break;
569                         case 'A':
570                                 pp->dmstate = PSTATE_ACTIVE;
571                                 break;
572                         default:
573                                 break;
574                         }
575                         FREE(word);
576                         /*
577                          * fail count
578                          */
579                         p += get_word(p, &word);
580
581                         if (!word)
582                                 return 1;
583
584                         pp->failcount = atoi(word);
585                         FREE(word);
586
587                         /*
588                          * selector args
589                          */
590                         for (k = 0; k < num_pg_args; k++) {
591                                 if (!strncmp(mpp->selector,
592                                              "least-pending", 13)) {
593                                         p += get_word(p, &word);
594                                         if (sscanf(word,"%d:*d",
595                                                    &def_minio) == 1 &&
596                                             def_minio != mpp->minio)
597                                                         mpp->minio = def_minio;
598                                 } else
599                                         p += get_word(p, NULL);
600                         }
601                 }
602         }
603         return 0;
604 }