libmultipath: rewrite dict.c with function generation macros
[multipath-tools/.git] / libmultipath / config.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  * Copyright (c) 2005 Benjamin Marzinski, Redhat
4  * Copyright (c) 2005 Edward Goggin, EMC
5  */
6 #include <stdio.h>
7 #include <string.h>
8 #include <libudev.h>
9
10 #include "checkers.h"
11 #include "memory.h"
12 #include "util.h"
13 #include "debug.h"
14 #include "parser.h"
15 #include "dict.h"
16 #include "hwtable.h"
17 #include "vector.h"
18 #include "structs.h"
19 #include "config.h"
20 #include "blacklist.h"
21 #include "defaults.h"
22 #include "prio.h"
23 #include "devmapper.h"
24
25 static int
26 hwe_strmatch (struct hwentry *hwe1, struct hwentry *hwe2)
27 {
28         if ((hwe2->vendor && !hwe1->vendor) ||
29             (hwe1->vendor && (!hwe2->vendor ||
30                               strcmp(hwe1->vendor, hwe2->vendor))))
31                 return 1;
32
33         if ((hwe2->product && !hwe1->product) ||
34             (hwe1->product && (!hwe2->product ||
35                               strcmp(hwe1->product, hwe2->product))))
36                 return 1;
37
38         if ((hwe2->revision && !hwe1->revision) ||
39             (hwe1->revision && (!hwe2->revision ||
40                               strcmp(hwe1->revision, hwe2->revision))))
41                 return 1;
42
43         return 0;
44 }
45
46 static struct hwentry *
47 find_hwe_strmatch (vector hwtable, struct hwentry *hwe)
48 {
49         int i;
50         struct hwentry *tmp, *ret = NULL;
51
52         vector_foreach_slot (hwtable, tmp, i) {
53                 if (hwe_strmatch(tmp, hwe))
54                         continue;
55                 ret = tmp;
56                 break;
57         }
58         return ret;
59 }
60
61 static int
62 hwe_regmatch (struct hwentry *hwe1, struct hwentry *hwe2)
63 {
64         regex_t vre, pre, rre;
65         int retval = 1;
66
67         if (hwe1->vendor &&
68             regcomp(&vre, hwe1->vendor, REG_EXTENDED|REG_NOSUB))
69                 goto out;
70
71         if (hwe1->product &&
72             regcomp(&pre, hwe1->product, REG_EXTENDED|REG_NOSUB))
73                 goto out_vre;
74
75         if (hwe1->revision &&
76             regcomp(&rre, hwe1->revision, REG_EXTENDED|REG_NOSUB))
77                 goto out_pre;
78
79         if ((!hwe1->vendor || !hwe2->vendor ||
80              !regexec(&vre, hwe2->vendor, 0, NULL, 0)) &&
81             (!hwe1->product || !hwe2->product ||
82              !regexec(&pre, hwe2->product, 0, NULL, 0)) &&
83             (!hwe1->revision || !hwe2->revision ||
84              !regexec(&rre, hwe2->revision, 0, NULL, 0)))
85                 retval = 0;
86
87         if (hwe1->revision)
88                 regfree(&rre);
89 out_pre:
90         if (hwe1->product)
91                 regfree(&pre);
92 out_vre:
93         if (hwe1->vendor)
94                 regfree(&vre);
95 out:
96         return retval;
97 }
98
99 struct hwentry *
100 find_hwe (vector hwtable, char * vendor, char * product, char * revision)
101 {
102         int i;
103         struct hwentry hwe, *tmp, *ret = NULL;
104
105         hwe.vendor = vendor;
106         hwe.product = product;
107         hwe.revision = revision;
108         /*
109          * Search backwards here.
110          * User modified entries are attached at the end of
111          * the list, so we have to check them first before
112          * continuing to the generic entries
113          */
114         vector_foreach_slot_backwards (hwtable, tmp, i) {
115                 if (hwe_regmatch(tmp, &hwe))
116                         continue;
117                 ret = tmp;
118                 break;
119         }
120         return ret;
121 }
122
123 extern struct mpentry *
124 find_mpe (char * wwid)
125 {
126         int i;
127         struct mpentry * mpe;
128
129         if (!wwid)
130                 return NULL;
131
132         vector_foreach_slot (conf->mptable, mpe, i)
133                 if (mpe->wwid && !strcmp(mpe->wwid, wwid))
134                         return mpe;
135
136         return NULL;
137 }
138
139 extern char *
140 get_mpe_wwid (char * alias)
141 {
142         int i;
143         struct mpentry * mpe;
144
145         if (!alias)
146                 return NULL;
147
148         vector_foreach_slot (conf->mptable, mpe, i)
149                 if (mpe->alias && strcmp(mpe->alias, alias) == 0)
150                         return mpe->wwid;
151
152         return NULL;
153 }
154
155 void
156 free_hwe (struct hwentry * hwe)
157 {
158         if (!hwe)
159                 return;
160
161         if (hwe->vendor)
162                 FREE(hwe->vendor);
163
164         if (hwe->product)
165                 FREE(hwe->product);
166
167         if (hwe->revision)
168                 FREE(hwe->revision);
169
170         if (hwe->getuid)
171                 FREE(hwe->getuid);
172
173         if (hwe->uid_attribute)
174                 FREE(hwe->uid_attribute);
175
176         if (hwe->features)
177                 FREE(hwe->features);
178
179         if (hwe->hwhandler)
180                 FREE(hwe->hwhandler);
181
182         if (hwe->selector)
183                 FREE(hwe->selector);
184
185         if (hwe->checker_name)
186                 FREE(hwe->checker_name);
187
188         if (hwe->prio_name)
189                 FREE(hwe->prio_name);
190
191         if (hwe->prio_args)
192                 FREE(hwe->prio_args);
193
194         if (hwe->alias_prefix)
195                 FREE(hwe->alias_prefix);
196
197         if (hwe->bl_product)
198                 FREE(hwe->bl_product);
199
200         FREE(hwe);
201 }
202
203 void
204 free_hwtable (vector hwtable)
205 {
206         int i;
207         struct hwentry * hwe;
208
209         if (!hwtable)
210                 return;
211
212         vector_foreach_slot (hwtable, hwe, i)
213                 free_hwe(hwe);
214
215         vector_free(hwtable);
216 }
217
218 void
219 free_mpe (struct mpentry * mpe)
220 {
221         if (!mpe)
222                 return;
223
224         if (mpe->wwid)
225                 FREE(mpe->wwid);
226
227         if (mpe->selector)
228                 FREE(mpe->selector);
229
230         if (mpe->getuid)
231                 FREE(mpe->getuid);
232
233         if (mpe->uid_attribute)
234                 FREE(mpe->uid_attribute);
235
236         if (mpe->alias)
237                 FREE(mpe->alias);
238
239         if (mpe->prio_name)
240                 FREE(mpe->prio_name);
241
242         if (mpe->prio_args)
243                 FREE(mpe->prio_args);
244
245         FREE(mpe);
246 }
247
248 void
249 free_mptable (vector mptable)
250 {
251         int i;
252         struct mpentry * mpe;
253
254         if (!mptable)
255                 return;
256
257         vector_foreach_slot (mptable, mpe, i)
258                 free_mpe(mpe);
259
260         vector_free(mptable);
261 }
262
263 struct mpentry *
264 alloc_mpe (void)
265 {
266         struct mpentry * mpe = (struct mpentry *)
267                                 MALLOC(sizeof(struct mpentry));
268
269         return mpe;
270 }
271
272 struct hwentry *
273 alloc_hwe (void)
274 {
275         struct hwentry * hwe = (struct hwentry *)
276                                 MALLOC(sizeof(struct hwentry));
277
278         return hwe;
279 }
280
281 static char *
282 set_param_str(char * str)
283 {
284         char * dst;
285         int len;
286
287         if (!str)
288                 return NULL;
289
290         len = strlen(str);
291
292         if (!len)
293                 return NULL;
294
295         dst = (char *)MALLOC(len + 1);
296
297         if (!dst)
298                 return NULL;
299
300         strcpy(dst, str);
301         return dst;
302 }
303
304 #define merge_str(s) \
305         if (!dst->s && src->s) { \
306                 if (!(dst->s = set_param_str(src->s))) \
307                         return 1; \
308         }
309
310 #define merge_num(s) \
311         if (!dst->s && src->s) \
312                 dst->s = src->s
313
314
315 static int
316 merge_hwe (struct hwentry * dst, struct hwentry * src)
317 {
318         merge_str(vendor);
319         merge_str(product);
320         merge_str(revision);
321         merge_str(getuid);
322         merge_str(uid_attribute);
323         merge_str(features);
324         merge_str(hwhandler);
325         merge_str(selector);
326         merge_str(checker_name);
327         merge_str(prio_name);
328         merge_str(prio_args);
329         merge_str(alias_prefix);
330         merge_str(bl_product);
331         merge_num(pgpolicy);
332         merge_num(pgfailback);
333         merge_num(rr_weight);
334         merge_num(no_path_retry);
335         merge_num(minio);
336         merge_num(minio_rq);
337         merge_num(flush_on_last_del);
338         merge_num(fast_io_fail);
339         merge_num(dev_loss);
340         merge_num(user_friendly_names);
341         merge_num(retain_hwhandler);
342         merge_num(detect_prio);
343
344         /*
345          * Make sure features is consistent with
346          * no_path_retry
347          */
348         if (dst->no_path_retry == NO_PATH_RETRY_FAIL)
349                 remove_feature(&dst->features, "queue_if_no_path");
350         else if (dst->no_path_retry != NO_PATH_RETRY_UNDEF)
351                 add_feature(&dst->features, "queue_if_no_path");
352
353         return 0;
354 }
355
356 int
357 store_hwe (vector hwtable, struct hwentry * dhwe)
358 {
359         struct hwentry * hwe;
360
361         if (find_hwe_strmatch(hwtable, dhwe))
362                 return 0;
363
364         if (!(hwe = alloc_hwe()))
365                 return 1;
366
367         if (!dhwe->vendor || !(hwe->vendor = set_param_str(dhwe->vendor)))
368                 goto out;
369
370         if (!dhwe->product || !(hwe->product = set_param_str(dhwe->product)))
371                 goto out;
372
373         if (dhwe->revision && !(hwe->revision = set_param_str(dhwe->revision)))
374                 goto out;
375
376         if (dhwe->uid_attribute && !(hwe->uid_attribute = set_param_str(dhwe->uid_attribute)))
377                 goto out;
378
379         if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid)))
380                 goto out;
381
382         if (dhwe->features && !(hwe->features = set_param_str(dhwe->features)))
383                 goto out;
384
385         if (dhwe->hwhandler && !(hwe->hwhandler = set_param_str(dhwe->hwhandler)))
386                 goto out;
387
388         if (dhwe->selector && !(hwe->selector = set_param_str(dhwe->selector)))
389                 goto out;
390
391         if (dhwe->checker_name && !(hwe->checker_name = set_param_str(dhwe->checker_name)))
392                 goto out;
393
394         if (dhwe->prio_name && !(hwe->prio_name = set_param_str(dhwe->prio_name)))
395                 goto out;
396
397         if (dhwe->prio_args && !(hwe->prio_args = set_param_str(dhwe->prio_args)))
398                 goto out;
399
400         if (dhwe->alias_prefix && !(hwe->alias_prefix = set_param_str(dhwe->alias_prefix)))
401                 goto out;
402
403         hwe->pgpolicy = dhwe->pgpolicy;
404         hwe->pgfailback = dhwe->pgfailback;
405         hwe->rr_weight = dhwe->rr_weight;
406         hwe->no_path_retry = dhwe->no_path_retry;
407         hwe->minio = dhwe->minio;
408         hwe->minio_rq = dhwe->minio_rq;
409         hwe->flush_on_last_del = dhwe->flush_on_last_del;
410         hwe->fast_io_fail = dhwe->fast_io_fail;
411         hwe->dev_loss = dhwe->dev_loss;
412         hwe->user_friendly_names = dhwe->user_friendly_names;
413         hwe->retain_hwhandler = dhwe->retain_hwhandler;
414         hwe->detect_prio = dhwe->detect_prio;
415
416         if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
417                 goto out;
418
419         if (!vector_alloc_slot(hwtable))
420                 goto out;
421
422         vector_set_slot(hwtable, hwe);
423         return 0;
424 out:
425         free_hwe(hwe);
426         return 1;
427 }
428
429 static void
430 factorize_hwtable (vector hw, int n)
431 {
432         struct hwentry *hwe1, *hwe2;
433         int i, j;
434
435 restart:
436         vector_foreach_slot(hw, hwe1, i) {
437                 if (i == n)
438                         break;
439                 j = n;
440                 vector_foreach_slot_after(hw, hwe2, j) {
441                         if (hwe_regmatch(hwe1, hwe2))
442                                 continue;
443                         /* dup */
444                         merge_hwe(hwe2, hwe1);
445                         if (hwe_strmatch(hwe2, hwe1) == 0) {
446                                 vector_del_slot(hw, i);
447                                 free_hwe(hwe1);
448                                 n -= 1;
449                                 /*
450                                  * Play safe here; we have modified
451                                  * the original vector so the outer
452                                  * vector_foreach_slot() might
453                                  * become confused.
454                                  */
455                                 goto restart;
456                         }
457                 }
458         }
459         return;
460 }
461
462 struct config *
463 alloc_config (void)
464 {
465         return (struct config *)MALLOC(sizeof(struct config));
466 }
467
468 void
469 free_config (struct config * conf)
470 {
471         if (!conf)
472                 return;
473
474         if (conf->dev)
475                 FREE(conf->dev);
476
477         if (conf->multipath_dir)
478                 FREE(conf->multipath_dir);
479
480         if (conf->selector)
481                 FREE(conf->selector);
482
483         if (conf->uid_attribute)
484                 FREE(conf->uid_attribute);
485
486         if (conf->getuid)
487                 FREE(conf->getuid);
488
489         if (conf->features)
490                 FREE(conf->features);
491
492         if (conf->hwhandler)
493                 FREE(conf->hwhandler);
494
495         if (conf->bindings_file)
496                 FREE(conf->bindings_file);
497
498         if (conf->wwids_file)
499                 FREE(conf->wwids_file);
500         if (conf->prio_name)
501                 FREE(conf->prio_name);
502
503         if (conf->alias_prefix)
504                 FREE(conf->alias_prefix);
505
506         if (conf->prio_args)
507                 FREE(conf->prio_args);
508
509         if (conf->checker_name)
510                 FREE(conf->checker_name);
511         if (conf->reservation_key)
512                 FREE(conf->reservation_key);
513
514         free_blacklist(conf->blist_devnode);
515         free_blacklist(conf->blist_wwid);
516         free_blacklist(conf->blist_property);
517         free_blacklist_device(conf->blist_device);
518
519         free_blacklist(conf->elist_devnode);
520         free_blacklist(conf->elist_wwid);
521         free_blacklist(conf->elist_property);
522         free_blacklist_device(conf->elist_device);
523
524         free_mptable(conf->mptable);
525         free_hwtable(conf->hwtable);
526         free_keywords(conf->keywords);
527         FREE(conf);
528 }
529
530 int
531 load_config (char * file, struct udev *udev)
532 {
533         if (!conf)
534                 conf = alloc_config();
535
536         if (!conf || !udev)
537                 return 1;
538
539         /*
540          * internal defaults
541          */
542         if (!conf->verbosity)
543                 conf->verbosity = DEFAULT_VERBOSITY;
544
545         conf->udev = udev;
546         conf->dev_type = DEV_NONE;
547         conf->minio = DEFAULT_MINIO;
548         conf->minio_rq = DEFAULT_MINIO_RQ;
549         get_sys_max_fds(&conf->max_fds);
550         conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE);
551         conf->wwids_file = set_default(DEFAULT_WWIDS_FILE);
552         conf->bindings_read_only = 0;
553         conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
554         conf->features = set_default(DEFAULT_FEATURES);
555         conf->flush_on_last_del = 0;
556         conf->attribute_flags = 0;
557         conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
558         conf->checkint = DEFAULT_CHECKINT;
559         conf->max_checkint = 0;
560         conf->pgfailback = DEFAULT_FAILBACK;
561         conf->fast_io_fail = DEFAULT_FAST_IO_FAIL;
562         conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
563         conf->detect_prio = DEFAULT_DETECT_PRIO;
564         conf->force_sync = 0;
565
566         /*
567          * preload default hwtable
568          */
569         if (conf->hwtable == NULL) {
570                 conf->hwtable = vector_alloc();
571
572                 if (!conf->hwtable)
573                         goto out;
574         }
575         if (setup_default_hwtable(conf->hwtable))
576                 goto out;
577
578         /*
579          * read the config file
580          */
581         set_current_keywords(&conf->keywords);
582         alloc_keywords();
583         if (filepresent(file)) {
584                 int builtin_hwtable_size;
585
586                 builtin_hwtable_size = VECTOR_SIZE(conf->hwtable);
587                 if (init_data(file, init_keywords)) {
588                         condlog(0, "error parsing config file");
589                         goto out;
590                 }
591                 if (VECTOR_SIZE(conf->hwtable) > builtin_hwtable_size) {
592                         /*
593                          * remove duplica in hwtable. config file
594                          * takes precedence over build-in hwtable
595                          */
596                         factorize_hwtable(conf->hwtable, builtin_hwtable_size);
597                 }
598
599         } else {
600                 init_keywords();
601         }
602         if (conf->max_checkint == 0)
603                 conf->max_checkint = MAX_CHECKINT(conf->checkint);
604         /*
605          * fill the voids left in the config file
606          */
607         if (conf->blist_devnode == NULL) {
608                 conf->blist_devnode = vector_alloc();
609
610                 if (!conf->blist_devnode)
611                         goto out;
612         }
613         if (conf->blist_wwid == NULL) {
614                 conf->blist_wwid = vector_alloc();
615
616                 if (!conf->blist_wwid)
617                         goto out;
618         }
619         if (conf->blist_device == NULL) {
620                 conf->blist_device = vector_alloc();
621
622                 if (!conf->blist_device)
623                         goto out;
624         }
625         if (conf->blist_property == NULL) {
626                 conf->blist_property = vector_alloc();
627
628                 if (!conf->blist_property)
629                         goto out;
630         }
631
632         if (conf->elist_devnode == NULL) {
633                 conf->elist_devnode = vector_alloc();
634
635                 if (!conf->elist_devnode)
636                         goto out;
637         }
638         if (conf->elist_wwid == NULL) {
639                 conf->elist_wwid = vector_alloc();
640
641                 if (!conf->elist_wwid)
642                         goto out;
643         }
644
645         if (conf->elist_device == NULL) {
646                 conf->elist_device = vector_alloc();
647
648                 if (!conf->elist_device)
649                         goto out;
650         }
651
652         if (conf->elist_property == NULL) {
653                 conf->elist_property = vector_alloc();
654
655                 if (!conf->elist_property)
656                         goto out;
657         }
658         if (setup_default_blist(conf))
659                 goto out;
660
661         if (conf->mptable == NULL) {
662                 conf->mptable = vector_alloc();
663                 if (!conf->mptable)
664                         goto out;
665         }
666         if (conf->bindings_file == NULL)
667                 conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE);
668
669         if (!conf->multipath_dir || !conf->bindings_file ||
670             !conf->wwids_file)
671                 goto out;
672
673         return 0;
674 out:
675         free_config(conf);
676         return 1;
677 }
678