Fix error
[platform/upstream/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 #include <dirent.h>
10 #include <limits.h>
11 #include <errno.h>
12
13 #include "checkers.h"
14 #include "util.h"
15 #include "debug.h"
16 #include "parser.h"
17 #include "dict.h"
18 #include "hwtable.h"
19 #include "vector.h"
20 #include "structs.h"
21 #include "config.h"
22 #include "blacklist.h"
23 #include "defaults.h"
24 #include "prio.h"
25 #include "devmapper.h"
26 #include "mpath_cmd.h"
27 #include "propsel.h"
28 #include "foreign.h"
29
30 /*
31  * We don't support re-initialization after
32  * libmultipath_exit().
33  */
34 static bool libmultipath_exit_called;
35 static pthread_once_t _init_once = PTHREAD_ONCE_INIT;
36 static pthread_once_t _exit_once = PTHREAD_ONCE_INIT;
37 struct udev *udev;
38
39 static void _udev_init(void)
40 {
41         if (udev)
42                 udev_ref(udev);
43         else
44                 udev = udev_new();
45         if (!udev)
46                 condlog(0, "%s: failed to initialize udev", __func__);
47 }
48
49 static bool _is_libmultipath_initialized(void)
50 {
51         return !libmultipath_exit_called && !!udev;
52 }
53
54 int libmultipath_init(void)
55 {
56         pthread_once(&_init_once, _udev_init);
57         return !_is_libmultipath_initialized();
58 }
59
60 static void _libmultipath_exit(void)
61 {
62         libmultipath_exit_called = true;
63         cleanup_foreign();
64         cleanup_checkers();
65         cleanup_prio();
66         libmp_dm_exit();
67         udev_unref(udev);
68 }
69
70 void libmultipath_exit(void)
71 {
72         pthread_once(&_exit_once, _libmultipath_exit);
73 }
74
75 static struct config __internal_config;
76 struct config *libmp_get_multipath_config(void)
77 {
78         if (!__internal_config.hwtable)
79                 /* not initialized */
80                 return NULL;
81         return &__internal_config;
82 }
83
84 struct config *get_multipath_config(void)
85         __attribute__((alias("libmp_get_multipath_config")));
86
87 void libmp_put_multipath_config(void *conf __attribute__((unused)))
88 {
89         /* empty */
90 }
91
92 void put_multipath_config(void *conf)
93         __attribute__((alias("libmp_put_multipath_config")));
94
95 static int
96 hwe_strmatch (const struct hwentry *hwe1, const struct hwentry *hwe2)
97 {
98         if ((hwe2->vendor && !hwe1->vendor) ||
99             (hwe1->vendor && (!hwe2->vendor ||
100                               strcmp(hwe1->vendor, hwe2->vendor))))
101                 return 1;
102
103         if ((hwe2->product && !hwe1->product) ||
104             (hwe1->product && (!hwe2->product ||
105                               strcmp(hwe1->product, hwe2->product))))
106                 return 1;
107
108         if ((hwe2->revision && !hwe1->revision) ||
109             (hwe1->revision && (!hwe2->revision ||
110                               strcmp(hwe1->revision, hwe2->revision))))
111                 return 1;
112
113         return 0;
114 }
115
116 static struct hwentry *
117 find_hwe_strmatch (const struct _vector *hwtable, const struct hwentry *hwe)
118 {
119         int i;
120         struct hwentry *tmp, *ret = NULL;
121
122         vector_foreach_slot (hwtable, tmp, i) {
123                 if (hwe_strmatch(tmp, hwe))
124                         continue;
125                 ret = tmp;
126                 break;
127         }
128         return ret;
129 }
130
131 static int
132 hwe_regmatch (const struct hwentry *hwe1, const char *vendor,
133               const char *product, const char *revision)
134 {
135         regex_t vre, pre, rre;
136         int retval = 1;
137
138         if (hwe1->vendor &&
139             regcomp(&vre, hwe1->vendor, REG_EXTENDED|REG_NOSUB))
140                 goto out;
141
142         if (hwe1->product &&
143             regcomp(&pre, hwe1->product, REG_EXTENDED|REG_NOSUB))
144                 goto out_vre;
145
146         if (hwe1->revision &&
147             regcomp(&rre, hwe1->revision, REG_EXTENDED|REG_NOSUB))
148                 goto out_pre;
149
150         if ((vendor || product || revision) &&
151             (!hwe1->vendor || !vendor ||
152              !regexec(&vre, vendor, 0, NULL, 0)) &&
153             (!hwe1->product || !product ||
154              !regexec(&pre, product, 0, NULL, 0)) &&
155             (!hwe1->revision || !revision ||
156              !regexec(&rre, revision, 0, NULL, 0)))
157                 retval = 0;
158
159         if (hwe1->revision)
160                 regfree(&rre);
161 out_pre:
162         if (hwe1->product)
163                 regfree(&pre);
164 out_vre:
165         if (hwe1->vendor)
166                 regfree(&vre);
167 out:
168         return retval;
169 }
170
171 static void _log_match(const char *fn, const struct hwentry *h,
172                        const char *vendor, const char *product,
173                        const char *revision)
174 {
175         condlog(4, "%s: found match /%s:%s:%s/ for '%s:%s:%s'", fn,
176                 h->vendor, h->product, h->revision,
177                 vendor, product, revision);
178 }
179 #define log_match(h, v, p, r) _log_match(__func__, (h), (v), (p), (r))
180
181 int
182 find_hwe (const struct _vector *hwtable,
183           const char * vendor, const char * product, const char * revision,
184           vector result)
185 {
186         int i, n = 0;
187         struct hwentry *tmp;
188
189         /*
190          * Search backwards here, and add forward.
191          * User modified entries are attached at the end of
192          * the list, so we have to check them first before
193          * continuing to the generic entries
194          */
195         vector_reset(result);
196         vector_foreach_slot_backwards (hwtable, tmp, i) {
197                 if (hwe_regmatch(tmp, vendor, product, revision))
198                         continue;
199                 if (vector_alloc_slot(result)) {
200                         vector_set_slot(result, tmp);
201                         n++;
202                 }
203                 log_match(tmp, vendor, product, revision);
204         }
205         condlog(n > 1 ? 3 : 4, "%s: found %d hwtable matches for %s:%s:%s",
206                 __func__, n, vendor, product, revision);
207         return n;
208 }
209
210 struct mpentry *find_mpe(vector mptable, char *wwid)
211 {
212         int i;
213         struct mpentry * mpe;
214
215         if (!wwid || !*wwid)
216                 return NULL;
217
218         vector_foreach_slot (mptable, mpe, i)
219                 if (mpe->wwid && !strcmp(mpe->wwid, wwid))
220                         return mpe;
221
222         return NULL;
223 }
224
225 const char *get_mpe_wwid(const struct _vector *mptable, const char *alias)
226 {
227         int i;
228         struct mpentry * mpe;
229
230         if (!alias)
231                 return NULL;
232
233         vector_foreach_slot (mptable, mpe, i)
234                 if (mpe->alias && strcmp(mpe->alias, alias) == 0)
235                         return mpe->wwid;
236
237         return NULL;
238 }
239
240 static void
241 free_pctable (vector pctable)
242 {
243         int i;
244         struct pcentry *pce;
245
246         vector_foreach_slot(pctable, pce, i)
247                 free(pce);
248
249         vector_free(pctable);
250 }
251
252 void
253 free_hwe (struct hwentry * hwe)
254 {
255         if (!hwe)
256                 return;
257
258         if (hwe->vendor)
259                 free(hwe->vendor);
260
261         if (hwe->product)
262                 free(hwe->product);
263
264         if (hwe->revision)
265                 free(hwe->revision);
266
267         if (hwe->uid_attribute)
268                 free(hwe->uid_attribute);
269
270         if (hwe->features)
271                 free(hwe->features);
272
273         if (hwe->hwhandler)
274                 free(hwe->hwhandler);
275
276         if (hwe->selector)
277                 free(hwe->selector);
278
279         if (hwe->checker_name)
280                 free(hwe->checker_name);
281
282         if (hwe->prio_name)
283                 free(hwe->prio_name);
284
285         if (hwe->prio_args)
286                 free(hwe->prio_args);
287
288         if (hwe->alias_prefix)
289                 free(hwe->alias_prefix);
290
291         if (hwe->bl_product)
292                 free(hwe->bl_product);
293
294         if (hwe->pctable)
295                 free_pctable(hwe->pctable);
296
297         free(hwe);
298 }
299
300 void
301 free_hwtable (vector hwtable)
302 {
303         int i;
304         struct hwentry * hwe;
305
306         if (!hwtable)
307                 return;
308
309         vector_foreach_slot (hwtable, hwe, i)
310                 free_hwe(hwe);
311
312         vector_free(hwtable);
313 }
314
315 void
316 free_mpe (struct mpentry * mpe)
317 {
318         if (!mpe)
319                 return;
320
321         if (mpe->wwid)
322                 free(mpe->wwid);
323
324         if (mpe->selector)
325                 free(mpe->selector);
326
327         if (mpe->uid_attribute)
328                 free(mpe->uid_attribute);
329
330         if (mpe->alias)
331                 free(mpe->alias);
332
333         if (mpe->prio_name)
334                 free(mpe->prio_name);
335
336         if (mpe->prio_args)
337                 free(mpe->prio_args);
338
339         free(mpe);
340 }
341
342 void
343 free_mptable (vector mptable)
344 {
345         int i;
346         struct mpentry * mpe;
347
348         if (!mptable)
349                 return;
350
351         vector_foreach_slot (mptable, mpe, i)
352                 free_mpe(mpe);
353
354         vector_free(mptable);
355 }
356
357 struct mpentry *
358 alloc_mpe (void)
359 {
360         struct mpentry * mpe = (struct mpentry *)
361                                 calloc(1, sizeof(struct mpentry));
362
363         return mpe;
364 }
365
366 struct hwentry *
367 alloc_hwe (void)
368 {
369         struct hwentry * hwe = (struct hwentry *)
370                                 calloc(1, sizeof(struct hwentry));
371
372         return hwe;
373 }
374
375 struct pcentry *
376 alloc_pce (void)
377 {
378         struct pcentry *pce = (struct pcentry *)
379                                 calloc(1, sizeof(struct pcentry));
380         pce->type = PCE_INVALID;
381         return pce;
382 }
383
384 static char *
385 set_param_str(const char * str)
386 {
387         char * dst;
388         int len;
389
390         if (!str)
391                 return NULL;
392
393         len = strlen(str);
394
395         if (!len)
396                 return NULL;
397
398         dst = (char *)calloc(1, len + 1);
399
400         if (!dst)
401                 return NULL;
402
403         strcpy(dst, str);
404         return dst;
405 }
406
407 #define merge_str(s) \
408         if (!dst->s && src->s && strlen(src->s)) { \
409                 dst->s = src->s; \
410                 src->s = NULL; \
411         }
412
413 #define merge_num(s) \
414         if (!dst->s && src->s) \
415                 dst->s = src->s
416
417 static void
418 merge_pce(struct pcentry *dst, struct pcentry *src)
419 {
420         merge_num(fast_io_fail);
421         merge_num(dev_loss);
422         merge_num(eh_deadline);
423 }
424
425 static void
426 merge_hwe (struct hwentry * dst, struct hwentry * src)
427 {
428         char id[SCSI_VENDOR_SIZE+PATH_PRODUCT_SIZE];
429         merge_str(vendor);
430         merge_str(product);
431         merge_str(revision);
432         merge_str(uid_attribute);
433         merge_str(features);
434         merge_str(hwhandler);
435         merge_str(selector);
436         merge_str(checker_name);
437         merge_str(prio_name);
438         merge_str(prio_args);
439         merge_str(alias_prefix);
440         merge_str(bl_product);
441         merge_num(pgpolicy);
442         merge_num(pgfailback);
443         merge_num(rr_weight);
444         merge_num(no_path_retry);
445         merge_num(minio);
446         merge_num(minio_rq);
447         merge_num(flush_on_last_del);
448         merge_num(fast_io_fail);
449         merge_num(dev_loss);
450         merge_num(eh_deadline);
451         merge_num(user_friendly_names);
452         merge_num(retain_hwhandler);
453         merge_num(detect_prio);
454         merge_num(detect_checker);
455         merge_num(detect_pgpolicy);
456         merge_num(detect_pgpolicy_use_tpg);
457         merge_num(deferred_remove);
458         merge_num(delay_watch_checks);
459         merge_num(delay_wait_checks);
460         merge_num(skip_kpartx);
461         merge_num(max_sectors_kb);
462         merge_num(ghost_delay);
463         merge_num(all_tg_pt);
464         merge_num(recheck_wwid);
465         merge_num(vpd_vendor_id);
466         merge_num(san_path_err_threshold);
467         merge_num(san_path_err_forget_rate);
468         merge_num(san_path_err_recovery_time);
469         merge_num(marginal_path_err_sample_time);
470         merge_num(marginal_path_err_rate_threshold);
471         merge_num(marginal_path_err_recheck_gap_time);
472         merge_num(marginal_path_double_failed_time);
473
474         snprintf(id, sizeof(id), "%s/%s", dst->vendor, dst->product);
475         reconcile_features_with_options(id, &dst->features,
476                                         &dst->no_path_retry,
477                                         &dst->retain_hwhandler);
478 }
479
480 static void
481 merge_mpe(struct mpentry *dst, struct mpentry *src)
482 {
483         merge_str(alias);
484         merge_str(uid_attribute);
485         merge_str(selector);
486         merge_str(features);
487         merge_str(prio_name);
488         merge_str(prio_args);
489
490         if (dst->prkey_source == PRKEY_SOURCE_NONE &&
491             src->prkey_source != PRKEY_SOURCE_NONE) {
492                 dst->prkey_source = src->prkey_source;
493                 dst->sa_flags = src->sa_flags;
494                 memcpy(&dst->reservation_key, &src->reservation_key,
495                        sizeof(dst->reservation_key));
496         }
497
498         merge_num(pgpolicy);
499         merge_num(pgfailback);
500         merge_num(rr_weight);
501         merge_num(no_path_retry);
502         merge_num(minio);
503         merge_num(minio_rq);
504         merge_num(flush_on_last_del);
505         merge_num(attribute_flags);
506         merge_num(user_friendly_names);
507         merge_num(deferred_remove);
508         merge_num(delay_watch_checks);
509         merge_num(delay_wait_checks);
510         merge_num(san_path_err_threshold);
511         merge_num(san_path_err_forget_rate);
512         merge_num(san_path_err_recovery_time);
513         merge_num(marginal_path_err_sample_time);
514         merge_num(marginal_path_err_rate_threshold);
515         merge_num(marginal_path_err_recheck_gap_time);
516         merge_num(marginal_path_double_failed_time);
517         merge_num(skip_kpartx);
518         merge_num(max_sectors_kb);
519         merge_num(ghost_delay);
520         merge_num(uid);
521         merge_num(gid);
522         merge_num(mode);
523 }
524
525 static int wwid_compar(const void *p1, const void *p2)
526 {
527         const char *wwid1 = (*(struct mpentry * const *)p1)->wwid;
528         const char *wwid2 = (*(struct mpentry * const *)p2)->wwid;
529
530         return strcmp(wwid1, wwid2);
531 }
532
533 void merge_mptable(vector mptable)
534 {
535         struct mpentry *mp1, *mp2;
536         int i, j;
537
538         vector_foreach_slot(mptable, mp1, i) {
539                 /* drop invalid multipath configs */
540                 if (!mp1->wwid) {
541                         condlog(0, "multipaths config section missing wwid");
542                         vector_del_slot(mptable, i--);
543                         free_mpe(mp1);
544                         continue;
545                 }
546         }
547         vector_sort(mptable, wwid_compar);
548         vector_foreach_slot(mptable, mp1, i) {
549                 j = i + 1;
550                 vector_foreach_slot_after(mptable, mp2, j) {
551                         if (strcmp(mp1->wwid, mp2->wwid))
552                                 break;
553                         condlog(1, "%s: duplicate multipath config section for %s",
554                                 __func__, mp1->wwid);
555                         merge_mpe(mp2, mp1);
556                         free_mpe(mp1);
557                         vector_del_slot(mptable, i);
558                         i--;
559                         break;
560                 }
561         }
562 }
563
564 int
565 store_hwe (vector hwtable, struct hwentry * dhwe)
566 {
567         struct hwentry * hwe;
568
569         if (find_hwe_strmatch(hwtable, dhwe))
570                 return 0;
571
572         if (!(hwe = alloc_hwe()))
573                 return 1;
574
575         if (!dhwe->vendor || !(hwe->vendor = set_param_str(dhwe->vendor)))
576                 goto out;
577
578         if (!dhwe->product || !(hwe->product = set_param_str(dhwe->product)))
579                 goto out;
580
581         if (dhwe->revision && !(hwe->revision = set_param_str(dhwe->revision)))
582                 goto out;
583
584         if (dhwe->uid_attribute && !(hwe->uid_attribute = set_param_str(dhwe->uid_attribute)))
585                 goto out;
586
587         if (dhwe->features && !(hwe->features = set_param_str(dhwe->features)))
588                 goto out;
589
590         if (dhwe->hwhandler && !(hwe->hwhandler = set_param_str(dhwe->hwhandler)))
591                 goto out;
592
593         if (dhwe->selector && !(hwe->selector = set_param_str(dhwe->selector)))
594                 goto out;
595
596         if (dhwe->checker_name && !(hwe->checker_name = set_param_str(dhwe->checker_name)))
597                 goto out;
598
599         if (dhwe->prio_name && !(hwe->prio_name = set_param_str(dhwe->prio_name)))
600                 goto out;
601
602         if (dhwe->prio_args && !(hwe->prio_args = set_param_str(dhwe->prio_args)))
603                 goto out;
604
605         if (dhwe->alias_prefix && !(hwe->alias_prefix = set_param_str(dhwe->alias_prefix)))
606                 goto out;
607
608         hwe->pgpolicy = dhwe->pgpolicy;
609         hwe->pgfailback = dhwe->pgfailback;
610         hwe->rr_weight = dhwe->rr_weight;
611         hwe->no_path_retry = dhwe->no_path_retry;
612         hwe->minio = dhwe->minio;
613         hwe->minio_rq = dhwe->minio_rq;
614         hwe->flush_on_last_del = dhwe->flush_on_last_del;
615         hwe->fast_io_fail = dhwe->fast_io_fail;
616         hwe->dev_loss = dhwe->dev_loss;
617         hwe->eh_deadline = dhwe->eh_deadline;
618         hwe->user_friendly_names = dhwe->user_friendly_names;
619         hwe->retain_hwhandler = dhwe->retain_hwhandler;
620         hwe->detect_prio = dhwe->detect_prio;
621         hwe->detect_checker = dhwe->detect_checker;
622         hwe->detect_pgpolicy = dhwe->detect_pgpolicy;
623         hwe->detect_pgpolicy_use_tpg = dhwe->detect_pgpolicy_use_tpg;
624         hwe->ghost_delay = dhwe->ghost_delay;
625         hwe->vpd_vendor_id = dhwe->vpd_vendor_id;
626
627         if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
628                 goto out;
629
630         if (!vector_alloc_slot(hwtable))
631                 goto out;
632
633         vector_set_slot(hwtable, hwe);
634         return 0;
635 out:
636         free_hwe(hwe);
637         return 1;
638 }
639
640 static void
641 validate_pctable(struct hwentry *ovr, int idx, const char *table_desc)
642 {
643         struct pcentry *pce;
644
645         if (!ovr || !ovr->pctable)
646                 return;
647
648         vector_foreach_slot_after(ovr->pctable, pce, idx) {
649                 if (pce->type == PCE_INVALID) {
650                         condlog(0, "protocol section in %s missing type",
651                                 table_desc);
652                         vector_del_slot(ovr->pctable, idx--);
653                         free(pce);
654                 }
655         }
656
657         if (VECTOR_SIZE(ovr->pctable) == 0) {
658                 vector_free(ovr->pctable);
659                 ovr->pctable = NULL;
660         }
661 }
662
663 static void
664 merge_pctable(struct hwentry *ovr)
665 {
666         struct pcentry *pce1, *pce2;
667         int i, j;
668
669         if (!ovr || !ovr->pctable)
670                 return;
671
672         vector_foreach_slot(ovr->pctable, pce1, i) {
673                 j = i + 1;
674                 vector_foreach_slot_after(ovr->pctable, pce2, j) {
675                         if (pce1->type != pce2->type)
676                                 continue;
677                         merge_pce(pce2,pce1);
678                         vector_del_slot(ovr->pctable, i--);
679                         free(pce1);
680                         break;
681                 }
682         }
683 }
684
685 static void
686 factorize_hwtable (vector hw, int n, const char *table_desc)
687 {
688         struct hwentry *hwe1, *hwe2;
689         int i, j;
690
691 restart:
692         vector_foreach_slot(hw, hwe1, i) {
693                 /* drop invalid device configs */
694                 if (i >= n && (!hwe1->vendor || !hwe1->product)) {
695                         condlog(0, "device config in %s missing vendor or product parameter",
696                                 table_desc);
697                         vector_del_slot(hw, i--);
698                         free_hwe(hwe1);
699                         continue;
700                 }
701                 j = n > i + 1 ? n : i + 1;
702                 vector_foreach_slot_after(hw, hwe2, j) {
703                         if (hwe_strmatch(hwe2, hwe1) == 0) {
704                                 condlog(i >= n ? 1 : 3,
705                                         "%s: duplicate device section for %s:%s:%s in %s",
706                                         __func__, hwe1->vendor, hwe1->product,
707                                         hwe1->revision, table_desc);
708                                 vector_del_slot(hw, i);
709                                 merge_hwe(hwe2, hwe1);
710                                 free_hwe(hwe1);
711                                 if (i < n)
712                                         n -= 1;
713                                 /*
714                                  * Play safe here; we have modified
715                                  * the original vector so the outer
716                                  * vector_foreach_slot() might
717                                  * become confused.
718                                  */
719                                 goto restart;
720                         }
721                 }
722         }
723         return;
724 }
725
726 static struct config *alloc_config (void)
727 {
728         return (struct config *)calloc(1, sizeof(struct config));
729 }
730
731 static void _uninit_config(struct config *conf)
732 {
733         void *ptr;
734         int i;
735
736         if (!conf)
737                 conf = &__internal_config;
738
739         if (conf->selector)
740                 free(conf->selector);
741
742         if (conf->uid_attribute)
743                 free(conf->uid_attribute);
744
745         vector_foreach_slot(&conf->uid_attrs, ptr, i)
746                 free(ptr);
747         vector_reset(&conf->uid_attrs);
748
749         if (conf->features)
750                 free(conf->features);
751
752         if (conf->hwhandler)
753                 free(conf->hwhandler);
754
755         if (conf->prio_name)
756                 free(conf->prio_name);
757
758         if (conf->alias_prefix)
759                 free(conf->alias_prefix);
760         if (conf->partition_delim)
761                 free(conf->partition_delim);
762
763         if (conf->prio_args)
764                 free(conf->prio_args);
765
766         if (conf->checker_name)
767                 free(conf->checker_name);
768
769         if (conf->enable_foreign)
770                 free(conf->enable_foreign);
771
772         free_blacklist(conf->blist_devnode);
773         free_blacklist(conf->blist_wwid);
774         free_blacklist(conf->blist_property);
775         free_blacklist(conf->blist_protocol);
776         free_blacklist_device(conf->blist_device);
777
778         free_blacklist(conf->elist_devnode);
779         free_blacklist(conf->elist_wwid);
780         free_blacklist(conf->elist_property);
781         free_blacklist(conf->elist_protocol);
782         free_blacklist_device(conf->elist_device);
783
784         free_mptable(conf->mptable);
785         free_hwtable(conf->hwtable);
786         free_hwe(conf->overrides);
787         free_keywords(conf->keywords);
788
789         memset(conf, 0, sizeof(*conf));
790 }
791
792 void uninit_config(void)
793 {
794         _uninit_config(&__internal_config);
795 }
796
797 void free_config(struct config *conf)
798 {
799         if (!conf)
800                 return;
801         else if (conf == &__internal_config) {
802                 condlog(0, "ERROR: %s called for internal config. Use uninit_config() instead",
803                         __func__);
804                 return;
805         }
806
807         _uninit_config(conf);
808         free(conf);
809 }
810
811 /* if multipath fails to process the config directory, it should continue,
812  * with just a warning message */
813 static void
814 process_config_dir(struct config *conf, char *dir)
815 {
816         struct dirent **namelist;
817         struct scandir_result sr;
818         int i, n;
819         char path[LINE_MAX];
820         int old_hwtable_size;
821         int old_pctable_size = 0;
822
823         if (dir[0] != '/') {
824                 condlog(1, "config_dir '%s' must be a fully qualified path",
825                         dir);
826                 return;
827         }
828         n = scandir(dir, &namelist, NULL, alphasort);
829         if (n < 0) {
830                 if (errno == ENOENT)
831                         condlog(3, "No configuration dir '%s'", dir);
832                 else
833                         condlog(0, "couldn't open configuration dir '%s': %s",
834                                 dir, strerror(errno));
835                 return;
836         } else if (n == 0)
837                 return;
838         sr.di = namelist;
839         sr.n = n;
840         pthread_cleanup_push_cast(free_scandir_result, &sr);
841         for (i = 0; i < n; i++) {
842                 char *ext = strrchr(namelist[i]->d_name, '.');
843
844                 if (!ext || strcmp(ext, ".conf"))
845                         continue;
846
847                 old_hwtable_size = VECTOR_SIZE(conf->hwtable);
848                 old_pctable_size = conf->overrides ?
849                                    VECTOR_SIZE(conf->overrides->pctable) : 0;
850                 snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
851                 path[LINE_MAX-1] = '\0';
852                 process_file(conf, path);
853                 factorize_hwtable(conf->hwtable, old_hwtable_size,
854                                   namelist[i]->d_name);
855                 validate_pctable(conf->overrides, old_pctable_size,
856                                  namelist[i]->d_name);
857         }
858         pthread_cleanup_pop(1);
859 }
860
861 #ifdef USE_SYSTEMD
862 static void set_max_checkint_from_watchdog(struct config *conf)
863 {
864         char *envp = getenv("WATCHDOG_USEC");
865         unsigned long checkint;
866
867         if (envp && sscanf(envp, "%lu", &checkint) == 1) {
868                 /* Value is in microseconds */
869                 checkint /= 1000000;
870                 if (checkint < 1 || checkint > UINT_MAX) {
871                         condlog(1, "invalid value for WatchdogSec: \"%s\"", envp);
872                         return;
873                 }
874                 if (conf->max_checkint == 0 || conf->max_checkint > checkint)
875                         conf->max_checkint = checkint;
876                 condlog(3, "enabling watchdog, interval %ld", checkint);
877                 conf->use_watchdog = true;
878         }
879 }
880 #endif
881
882 static int _init_config (const char *file, struct config *conf);
883
884 int init_config(const char *file)
885 {
886         return _init_config(file, &__internal_config);
887 }
888
889 struct config *load_config(const char *file)
890 {
891         struct config *conf = alloc_config();
892
893         if (conf && !_init_config(file, conf))
894                 return conf;
895
896         free(conf);
897         return NULL;
898 }
899
900 int _init_config (const char *file, struct config *conf)
901 {
902
903         if (!conf)
904                 conf = &__internal_config;
905
906         /*
907          * Processing the config file will overwrite conf->verbosity if set
908          * When we return, we'll copy the config value back
909          */
910         conf->verbosity = libmp_verbosity;
911
912         /*
913          * internal defaults
914          */
915         get_sys_max_fds(&conf->max_fds);
916         conf->attribute_flags = 0;
917         conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
918         conf->checkint = CHECKINT_UNDEF;
919         conf->use_watchdog = false;
920         conf->max_checkint = 0;
921         conf->force_sync = DEFAULT_FORCE_SYNC;
922         conf->partition_delim = (default_partition_delim != NULL ?
923                                  strdup(default_partition_delim) : NULL);
924         conf->processed_main_config = 0;
925         conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
926         conf->uxsock_timeout = DEFAULT_REPLY_TIMEOUT;
927         conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES;
928         conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY;
929         conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
930         conf->remove_retries = 0;
931         conf->ghost_delay = DEFAULT_GHOST_DELAY;
932         conf->all_tg_pt = DEFAULT_ALL_TG_PT;
933         conf->recheck_wwid = DEFAULT_RECHECK_WWID;
934         /*
935          * preload default hwtable
936          */
937         conf->hwtable = vector_alloc();
938         if (!conf->hwtable)
939                         goto out;
940         if (setup_default_hwtable(conf->hwtable))
941                 goto out;
942
943 #ifdef CHECK_BUILTIN_HWTABLE
944         factorize_hwtable(conf->hwtable, 0, "builtin");
945 #endif
946         /*
947          * read the config file
948          */
949         conf->keywords = vector_alloc();
950         init_keywords(conf->keywords);
951         if (filepresent(file)) {
952                 int builtin_hwtable_size;
953
954                 builtin_hwtable_size = VECTOR_SIZE(conf->hwtable);
955                 if (process_file(conf, file)) {
956                         condlog(0, "error parsing config file");
957                         goto out;
958                 }
959                 factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
960                 validate_pctable(conf->overrides, 0, file);
961         }
962
963         conf->processed_main_config = 1;
964         process_config_dir(conf, CONFIG_DIR);
965
966         /*
967          * fill the voids left in the config file
968          */
969 #ifdef USE_SYSTEMD
970         set_max_checkint_from_watchdog(conf);
971 #endif
972         if (conf->max_checkint == 0) {
973                 if (conf->checkint == CHECKINT_UNDEF)
974                         conf->checkint = DEFAULT_CHECKINT;
975                 conf->max_checkint = (conf->checkint < UINT_MAX / 4 ?
976                                       conf->checkint * 4 : UINT_MAX);
977         } else if (conf->checkint == CHECKINT_UNDEF)
978                 conf->checkint = (conf->max_checkint >= 4 ?
979                                   conf->max_checkint / 4 : 1);
980         else if (conf->checkint > conf->max_checkint)
981                 conf->checkint = conf->max_checkint;
982         condlog(3, "polling interval: %d, max: %d",
983                 conf->checkint, conf->max_checkint);
984
985         if (conf->blist_devnode == NULL) {
986                 conf->blist_devnode = vector_alloc();
987
988                 if (!conf->blist_devnode)
989                         goto out;
990         }
991         if (conf->blist_wwid == NULL) {
992                 conf->blist_wwid = vector_alloc();
993
994                 if (!conf->blist_wwid)
995                         goto out;
996         }
997         if (conf->blist_device == NULL) {
998                 conf->blist_device = vector_alloc();
999
1000                 if (!conf->blist_device)
1001                         goto out;
1002         }
1003         if (conf->blist_property == NULL) {
1004                 conf->blist_property = vector_alloc();
1005
1006                 if (!conf->blist_property)
1007                         goto out;
1008         }
1009         if (conf->blist_protocol == NULL) {
1010                 conf->blist_protocol = vector_alloc();
1011
1012                 if (!conf->blist_protocol)
1013                         goto out;
1014         }
1015
1016         if (conf->elist_devnode == NULL) {
1017                 conf->elist_devnode = vector_alloc();
1018
1019                 if (!conf->elist_devnode)
1020                         goto out;
1021         }
1022         if (conf->elist_wwid == NULL) {
1023                 conf->elist_wwid = vector_alloc();
1024
1025                 if (!conf->elist_wwid)
1026                         goto out;
1027         }
1028
1029         if (conf->elist_device == NULL) {
1030                 conf->elist_device = vector_alloc();
1031
1032                 if (!conf->elist_device)
1033                         goto out;
1034         }
1035
1036         if (conf->elist_property == NULL) {
1037                 conf->elist_property = vector_alloc();
1038
1039                 if (!conf->elist_property)
1040                         goto out;
1041         }
1042         if (conf->elist_protocol == NULL) {
1043                 conf->elist_protocol = vector_alloc();
1044
1045                 if (!conf->elist_protocol)
1046                         goto out;
1047         }
1048
1049         if (setup_default_blist(conf))
1050                 goto out;
1051
1052         if (conf->mptable == NULL) {
1053                 conf->mptable = vector_alloc();
1054                 if (!conf->mptable)
1055                         goto out;
1056         }
1057
1058         merge_pctable(conf->overrides);
1059         merge_mptable(conf->mptable);
1060         merge_blacklist(conf->blist_devnode);
1061         merge_blacklist(conf->blist_property);
1062         merge_blacklist(conf->blist_wwid);
1063         merge_blacklist_device(conf->blist_device);
1064         merge_blacklist(conf->elist_devnode);
1065         merge_blacklist(conf->elist_property);
1066         merge_blacklist(conf->elist_wwid);
1067         merge_blacklist_device(conf->elist_device);
1068
1069         libmp_verbosity = conf->verbosity;
1070         return 0;
1071 out:
1072         _uninit_config(conf);
1073         return 1;
1074 }
1075
1076 const char *get_uid_attribute_by_attrs(const struct config *conf,
1077                                        const char *path_dev)
1078 {
1079         const struct _vector *uid_attrs = &conf->uid_attrs;
1080         int j;
1081         char *att, *col;
1082
1083         vector_foreach_slot(uid_attrs, att, j) {
1084                 col = strrchr(att, ':');
1085                 if (!col)
1086                         continue;
1087                 if (!strncmp(path_dev, att, col - att))
1088                         return col + 1;
1089         }
1090         return NULL;
1091 }
1092
1093 int parse_uid_attrs(char *uid_attrs, struct config *conf)
1094 {
1095         vector attrs  = &conf->uid_attrs;
1096         char *uid_attr_record, *tmp;
1097         int  ret = 0, count;
1098
1099         if (!uid_attrs)
1100                 return 1;
1101
1102         count = get_word(uid_attrs, &uid_attr_record);
1103         while (uid_attr_record) {
1104                 tmp = strchr(uid_attr_record, ':');
1105                 if (!tmp) {
1106                         condlog(2, "invalid record in uid_attrs: %s",
1107                                 uid_attr_record);
1108                         free(uid_attr_record);
1109                         ret = 1;
1110                 } else if (!vector_alloc_slot(attrs)) {
1111                         free(uid_attr_record);
1112                         ret = 1;
1113                 } else
1114                         vector_set_slot(attrs, uid_attr_record);
1115                 if (!count)
1116                         break;
1117                 uid_attrs += count;
1118                 count = get_word(uid_attrs, &uid_attr_record);
1119         }
1120         return ret;
1121 }