57f96fba338cf801710bf26e79e961c5633c03d0
[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 "memory.h"
15 #include "util.h"
16 #include "debug.h"
17 #include "parser.h"
18 #include "dict.h"
19 #include "hwtable.h"
20 #include "vector.h"
21 #include "structs.h"
22 #include "config.h"
23 #include "blacklist.h"
24 #include "defaults.h"
25 #include "prio.h"
26 #include "devmapper.h"
27 #include "mpath_cmd.h"
28 #include "propsel.h"
29
30 static int
31 hwe_strmatch (const struct hwentry *hwe1, const struct hwentry *hwe2)
32 {
33         if ((hwe2->vendor && !hwe1->vendor) ||
34             (hwe1->vendor && (!hwe2->vendor ||
35                               strcmp(hwe1->vendor, hwe2->vendor))))
36                 return 1;
37
38         if ((hwe2->product && !hwe1->product) ||
39             (hwe1->product && (!hwe2->product ||
40                               strcmp(hwe1->product, hwe2->product))))
41                 return 1;
42
43         if ((hwe2->revision && !hwe1->revision) ||
44             (hwe1->revision && (!hwe2->revision ||
45                               strcmp(hwe1->revision, hwe2->revision))))
46                 return 1;
47
48         return 0;
49 }
50
51 static struct hwentry *
52 find_hwe_strmatch (const struct _vector *hwtable, const struct hwentry *hwe)
53 {
54         int i;
55         struct hwentry *tmp, *ret = NULL;
56
57         vector_foreach_slot (hwtable, tmp, i) {
58                 if (hwe_strmatch(tmp, hwe))
59                         continue;
60                 ret = tmp;
61                 break;
62         }
63         return ret;
64 }
65
66 static int
67 hwe_regmatch (const struct hwentry *hwe1, const char *vendor,
68               const char *product, const char *revision)
69 {
70         regex_t vre, pre, rre;
71         int retval = 1;
72
73         if (hwe1->vendor &&
74             regcomp(&vre, hwe1->vendor, REG_EXTENDED|REG_NOSUB))
75                 goto out;
76
77         if (hwe1->product &&
78             regcomp(&pre, hwe1->product, REG_EXTENDED|REG_NOSUB))
79                 goto out_vre;
80
81         if (hwe1->revision &&
82             regcomp(&rre, hwe1->revision, REG_EXTENDED|REG_NOSUB))
83                 goto out_pre;
84
85         if ((vendor || product || revision) &&
86             (!hwe1->vendor || !vendor ||
87              !regexec(&vre, vendor, 0, NULL, 0)) &&
88             (!hwe1->product || !product ||
89              !regexec(&pre, product, 0, NULL, 0)) &&
90             (!hwe1->revision || !revision ||
91              !regexec(&rre, revision, 0, NULL, 0)))
92                 retval = 0;
93
94         if (hwe1->revision)
95                 regfree(&rre);
96 out_pre:
97         if (hwe1->product)
98                 regfree(&pre);
99 out_vre:
100         if (hwe1->vendor)
101                 regfree(&vre);
102 out:
103         return retval;
104 }
105
106 static void _log_match(const char *fn, const struct hwentry *h,
107                        const char *vendor, const char *product,
108                        const char *revision)
109 {
110         condlog(4, "%s: found match /%s:%s:%s/ for '%s:%s:%s'", fn,
111                 h->vendor, h->product, h->revision,
112                 vendor, product, revision);
113 }
114 #define log_match(h, v, p, r) _log_match(__func__, (h), (v), (p), (r))
115
116 int
117 find_hwe (const struct _vector *hwtable,
118           const char * vendor, const char * product, const char * revision,
119           vector result)
120 {
121         int i, n = 0;
122         struct hwentry *tmp;
123
124         /*
125          * Search backwards here, and add forward.
126          * User modified entries are attached at the end of
127          * the list, so we have to check them first before
128          * continuing to the generic entries
129          */
130         vector_reset(result);
131         vector_foreach_slot_backwards (hwtable, tmp, i) {
132                 if (hwe_regmatch(tmp, vendor, product, revision))
133                         continue;
134                 if (vector_alloc_slot(result) != NULL) {
135                         vector_set_slot(result, tmp);
136                         n++;
137                 }
138                 log_match(tmp, vendor, product, revision);
139         }
140         condlog(n > 1 ? 3 : 4, "%s: found %d hwtable matches for %s:%s:%s",
141                 __func__, n, vendor, product, revision);
142         return n;
143 }
144
145 struct mpentry *find_mpe(vector mptable, char *wwid)
146 {
147         int i;
148         struct mpentry * mpe;
149
150         if (!wwid)
151                 return NULL;
152
153         vector_foreach_slot (mptable, mpe, i)
154                 if (mpe->wwid && !strcmp(mpe->wwid, wwid))
155                         return mpe;
156
157         return NULL;
158 }
159
160 char *get_mpe_wwid(vector mptable, char *alias)
161 {
162         int i;
163         struct mpentry * mpe;
164
165         if (!alias)
166                 return NULL;
167
168         vector_foreach_slot (mptable, mpe, i)
169                 if (mpe->alias && strcmp(mpe->alias, alias) == 0)
170                         return mpe->wwid;
171
172         return NULL;
173 }
174
175 void
176 free_hwe (struct hwentry * hwe)
177 {
178         if (!hwe)
179                 return;
180
181         if (hwe->vendor)
182                 FREE(hwe->vendor);
183
184         if (hwe->product)
185                 FREE(hwe->product);
186
187         if (hwe->revision)
188                 FREE(hwe->revision);
189
190         if (hwe->getuid)
191                 FREE(hwe->getuid);
192
193         if (hwe->uid_attribute)
194                 FREE(hwe->uid_attribute);
195
196         if (hwe->features)
197                 FREE(hwe->features);
198
199         if (hwe->hwhandler)
200                 FREE(hwe->hwhandler);
201
202         if (hwe->selector)
203                 FREE(hwe->selector);
204
205         if (hwe->checker_name)
206                 FREE(hwe->checker_name);
207
208         if (hwe->prio_name)
209                 FREE(hwe->prio_name);
210
211         if (hwe->prio_args)
212                 FREE(hwe->prio_args);
213
214         if (hwe->alias_prefix)
215                 FREE(hwe->alias_prefix);
216
217         if (hwe->bl_product)
218                 FREE(hwe->bl_product);
219
220         FREE(hwe);
221 }
222
223 void
224 free_hwtable (vector hwtable)
225 {
226         int i;
227         struct hwentry * hwe;
228
229         if (!hwtable)
230                 return;
231
232         vector_foreach_slot (hwtable, hwe, i)
233                 free_hwe(hwe);
234
235         vector_free(hwtable);
236 }
237
238 void
239 free_mpe (struct mpentry * mpe)
240 {
241         if (!mpe)
242                 return;
243
244         if (mpe->wwid)
245                 FREE(mpe->wwid);
246
247         if (mpe->selector)
248                 FREE(mpe->selector);
249
250         if (mpe->getuid)
251                 FREE(mpe->getuid);
252
253         if (mpe->uid_attribute)
254                 FREE(mpe->uid_attribute);
255
256         if (mpe->alias)
257                 FREE(mpe->alias);
258
259         if (mpe->prio_name)
260                 FREE(mpe->prio_name);
261
262         if (mpe->prio_args)
263                 FREE(mpe->prio_args);
264
265         FREE(mpe);
266 }
267
268 void
269 free_mptable (vector mptable)
270 {
271         int i;
272         struct mpentry * mpe;
273
274         if (!mptable)
275                 return;
276
277         vector_foreach_slot (mptable, mpe, i)
278                 free_mpe(mpe);
279
280         vector_free(mptable);
281 }
282
283 struct mpentry *
284 alloc_mpe (void)
285 {
286         struct mpentry * mpe = (struct mpentry *)
287                                 MALLOC(sizeof(struct mpentry));
288
289         return mpe;
290 }
291
292 struct hwentry *
293 alloc_hwe (void)
294 {
295         struct hwentry * hwe = (struct hwentry *)
296                                 MALLOC(sizeof(struct hwentry));
297
298         return hwe;
299 }
300
301 static char *
302 set_param_str(const char * str)
303 {
304         char * dst;
305         int len;
306
307         if (!str)
308                 return NULL;
309
310         len = strlen(str);
311
312         if (!len)
313                 return NULL;
314
315         dst = (char *)MALLOC(len + 1);
316
317         if (!dst)
318                 return NULL;
319
320         strcpy(dst, str);
321         return dst;
322 }
323
324 #define merge_str(s) \
325         if (!dst->s && src->s) { \
326                 if (!(dst->s = set_param_str(src->s))) \
327                         return 1; \
328         }
329
330 #define merge_num(s) \
331         if (!dst->s && src->s) \
332                 dst->s = src->s
333
334
335 static int
336 merge_hwe (struct hwentry * dst, struct hwentry * src)
337 {
338         char id[SCSI_VENDOR_SIZE+PATH_PRODUCT_SIZE];
339         merge_str(vendor);
340         merge_str(product);
341         merge_str(revision);
342         merge_str(getuid);
343         merge_str(uid_attribute);
344         merge_str(features);
345         merge_str(hwhandler);
346         merge_str(selector);
347         merge_str(checker_name);
348         merge_str(prio_name);
349         merge_str(prio_args);
350         merge_str(alias_prefix);
351         merge_str(bl_product);
352         merge_num(pgpolicy);
353         merge_num(pgfailback);
354         merge_num(rr_weight);
355         merge_num(no_path_retry);
356         merge_num(minio);
357         merge_num(minio_rq);
358         merge_num(flush_on_last_del);
359         merge_num(fast_io_fail);
360         merge_num(dev_loss);
361         merge_num(user_friendly_names);
362         merge_num(retain_hwhandler);
363         merge_num(detect_prio);
364         merge_num(detect_checker);
365         merge_num(deferred_remove);
366         merge_num(delay_watch_checks);
367         merge_num(delay_wait_checks);
368         merge_num(skip_kpartx);
369         merge_num(max_sectors_kb);
370         merge_num(ghost_delay);
371         merge_num(all_tg_pt);
372         merge_num(vpd_vendor_id);
373         merge_num(san_path_err_threshold);
374         merge_num(san_path_err_forget_rate);
375         merge_num(san_path_err_recovery_time);
376         merge_num(marginal_path_err_sample_time);
377         merge_num(marginal_path_err_rate_threshold);
378         merge_num(marginal_path_err_recheck_gap_time);
379         merge_num(marginal_path_double_failed_time);
380
381         snprintf(id, sizeof(id), "%s/%s", dst->vendor, dst->product);
382         reconcile_features_with_options(id, &dst->features,
383                                         &dst->no_path_retry,
384                                         &dst->retain_hwhandler);
385         return 0;
386 }
387
388 static int
389 merge_mpe(struct mpentry *dst, struct mpentry *src)
390 {
391         if (!dst || !src)
392                 return 1;
393
394         merge_str(alias);
395         merge_str(uid_attribute);
396         merge_str(getuid);
397         merge_str(selector);
398         merge_str(features);
399         merge_str(prio_name);
400         merge_str(prio_args);
401
402         if (dst->prkey_source == PRKEY_SOURCE_NONE &&
403             src->prkey_source != PRKEY_SOURCE_NONE) {
404                 dst->prkey_source = src->prkey_source;
405                 dst->sa_flags = src->sa_flags;
406                 memcpy(&dst->reservation_key, &src->reservation_key,
407                        sizeof(dst->reservation_key));
408         }
409
410         merge_num(pgpolicy);
411         merge_num(pgfailback);
412         merge_num(rr_weight);
413         merge_num(no_path_retry);
414         merge_num(minio);
415         merge_num(minio_rq);
416         merge_num(flush_on_last_del);
417         merge_num(attribute_flags);
418         merge_num(user_friendly_names);
419         merge_num(deferred_remove);
420         merge_num(delay_watch_checks);
421         merge_num(delay_wait_checks);
422         merge_num(san_path_err_threshold);
423         merge_num(san_path_err_forget_rate);
424         merge_num(san_path_err_recovery_time);
425         merge_num(marginal_path_err_sample_time);
426         merge_num(marginal_path_err_rate_threshold);
427         merge_num(marginal_path_err_recheck_gap_time);
428         merge_num(marginal_path_double_failed_time);
429         merge_num(skip_kpartx);
430         merge_num(max_sectors_kb);
431         merge_num(ghost_delay);
432         merge_num(uid);
433         merge_num(gid);
434         merge_num(mode);
435
436         return 0;
437 }
438
439 void merge_mptable(vector mptable)
440 {
441         struct mpentry *mp1, *mp2;
442         int i, j;
443
444         vector_foreach_slot(mptable, mp1, i) {
445                 j = i + 1;
446                 vector_foreach_slot_after(mptable, mp2, j) {
447                         if (strcmp(mp1->wwid, mp2->wwid))
448                                 continue;
449                         condlog(1, "%s: duplicate multipath config section for %s",
450                                 __func__, mp1->wwid);
451                         merge_mpe(mp2, mp1);
452                         free_mpe(mp1);
453                         vector_del_slot(mptable, i);
454                         i--;
455                         break;
456                 }
457         }
458 }
459
460 int
461 store_hwe (vector hwtable, struct hwentry * dhwe)
462 {
463         struct hwentry * hwe;
464
465         if (find_hwe_strmatch(hwtable, dhwe))
466                 return 0;
467
468         if (!(hwe = alloc_hwe()))
469                 return 1;
470
471         if (!dhwe->vendor || !(hwe->vendor = set_param_str(dhwe->vendor)))
472                 goto out;
473
474         if (!dhwe->product || !(hwe->product = set_param_str(dhwe->product)))
475                 goto out;
476
477         if (dhwe->revision && !(hwe->revision = set_param_str(dhwe->revision)))
478                 goto out;
479
480         if (dhwe->uid_attribute && !(hwe->uid_attribute = set_param_str(dhwe->uid_attribute)))
481                 goto out;
482
483         if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid)))
484                 goto out;
485
486         if (dhwe->features && !(hwe->features = set_param_str(dhwe->features)))
487                 goto out;
488
489         if (dhwe->hwhandler && !(hwe->hwhandler = set_param_str(dhwe->hwhandler)))
490                 goto out;
491
492         if (dhwe->selector && !(hwe->selector = set_param_str(dhwe->selector)))
493                 goto out;
494
495         if (dhwe->checker_name && !(hwe->checker_name = set_param_str(dhwe->checker_name)))
496                 goto out;
497
498         if (dhwe->prio_name && !(hwe->prio_name = set_param_str(dhwe->prio_name)))
499                 goto out;
500
501         if (dhwe->prio_args && !(hwe->prio_args = set_param_str(dhwe->prio_args)))
502                 goto out;
503
504         if (dhwe->alias_prefix && !(hwe->alias_prefix = set_param_str(dhwe->alias_prefix)))
505                 goto out;
506
507         hwe->pgpolicy = dhwe->pgpolicy;
508         hwe->pgfailback = dhwe->pgfailback;
509         hwe->rr_weight = dhwe->rr_weight;
510         hwe->no_path_retry = dhwe->no_path_retry;
511         hwe->minio = dhwe->minio;
512         hwe->minio_rq = dhwe->minio_rq;
513         hwe->flush_on_last_del = dhwe->flush_on_last_del;
514         hwe->fast_io_fail = dhwe->fast_io_fail;
515         hwe->dev_loss = dhwe->dev_loss;
516         hwe->user_friendly_names = dhwe->user_friendly_names;
517         hwe->retain_hwhandler = dhwe->retain_hwhandler;
518         hwe->detect_prio = dhwe->detect_prio;
519         hwe->detect_checker = dhwe->detect_checker;
520         hwe->ghost_delay = dhwe->ghost_delay;
521         hwe->vpd_vendor_id = dhwe->vpd_vendor_id;
522
523         if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
524                 goto out;
525
526         if (!vector_alloc_slot(hwtable))
527                 goto out;
528
529         vector_set_slot(hwtable, hwe);
530         return 0;
531 out:
532         free_hwe(hwe);
533         return 1;
534 }
535
536 static void
537 factorize_hwtable (vector hw, int n, const char *table_desc)
538 {
539         struct hwentry *hwe1, *hwe2;
540         int i, j;
541
542 restart:
543         vector_foreach_slot(hw, hwe1, i) {
544                 /* drop invalid device configs */
545                 if (i >= n && (!hwe1->vendor || !hwe1->product)) {
546                         condlog(0, "device config in %s missing vendor or product parameter",
547                                 table_desc);
548                         vector_del_slot(hw, i--);
549                         free_hwe(hwe1);
550                         continue;
551                 }
552                 j = n > i + 1 ? n : i + 1;
553                 vector_foreach_slot_after(hw, hwe2, j) {
554                         if (hwe_strmatch(hwe2, hwe1) == 0) {
555                                 condlog(i >= n ? 1 : 3,
556                                         "%s: duplicate device section for %s:%s:%s in %s",
557                                         __func__, hwe1->vendor, hwe1->product,
558                                         hwe1->revision, table_desc);
559                                 vector_del_slot(hw, i);
560                                 merge_hwe(hwe2, hwe1);
561                                 free_hwe(hwe1);
562                                 if (i < n)
563                                         n -= 1;
564                                 /*
565                                  * Play safe here; we have modified
566                                  * the original vector so the outer
567                                  * vector_foreach_slot() might
568                                  * become confused.
569                                  */
570                                 goto restart;
571                         }
572                 }
573         }
574         return;
575 }
576
577 struct config *
578 alloc_config (void)
579 {
580         return (struct config *)MALLOC(sizeof(struct config));
581 }
582
583 void
584 free_config (struct config * conf)
585 {
586         if (!conf)
587                 return;
588
589         if (conf->multipath_dir)
590                 FREE(conf->multipath_dir);
591
592         if (conf->selector)
593                 FREE(conf->selector);
594
595         if (conf->uid_attribute)
596                 FREE(conf->uid_attribute);
597
598         vector_reset(&conf->uid_attrs);
599
600         if (conf->getuid)
601                 FREE(conf->getuid);
602
603         if (conf->features)
604                 FREE(conf->features);
605
606         if (conf->hwhandler)
607                 FREE(conf->hwhandler);
608
609         if (conf->bindings_file)
610                 FREE(conf->bindings_file);
611
612         if (conf->wwids_file)
613                 FREE(conf->wwids_file);
614
615         if (conf->prkeys_file)
616                 FREE(conf->prkeys_file);
617
618         if (conf->prio_name)
619                 FREE(conf->prio_name);
620
621         if (conf->alias_prefix)
622                 FREE(conf->alias_prefix);
623         if (conf->partition_delim)
624                 FREE(conf->partition_delim);
625
626         if (conf->prio_args)
627                 FREE(conf->prio_args);
628
629         if (conf->checker_name)
630                 FREE(conf->checker_name);
631
632         if (conf->config_dir)
633                 FREE(conf->config_dir);
634
635         free_blacklist(conf->blist_devnode);
636         free_blacklist(conf->blist_wwid);
637         free_blacklist(conf->blist_property);
638         free_blacklist(conf->blist_protocol);
639         free_blacklist_device(conf->blist_device);
640
641         free_blacklist(conf->elist_devnode);
642         free_blacklist(conf->elist_wwid);
643         free_blacklist(conf->elist_property);
644         free_blacklist(conf->elist_protocol);
645         free_blacklist_device(conf->elist_device);
646
647         free_mptable(conf->mptable);
648         free_hwtable(conf->hwtable);
649         free_hwe(conf->overrides);
650         free_keywords(conf->keywords);
651         FREE(conf);
652 }
653
654 /* if multipath fails to process the config directory, it should continue,
655  * with just a warning message */
656 static void
657 process_config_dir(struct config *conf, char *dir)
658 {
659         struct dirent **namelist;
660         struct scandir_result sr;
661         int i, n;
662         char path[LINE_MAX];
663         int old_hwtable_size;
664
665         if (dir[0] != '/') {
666                 condlog(1, "config_dir '%s' must be a fully qualified path",
667                         dir);
668                 return;
669         }
670         n = scandir(dir, &namelist, NULL, alphasort);
671         if (n < 0) {
672                 if (errno == ENOENT)
673                         condlog(3, "No configuration dir '%s'", dir);
674                 else
675                         condlog(0, "couldn't open configuration dir '%s': %s",
676                                 dir, strerror(errno));
677                 return;
678         } else if (n == 0)
679                 return;
680         sr.di = namelist;
681         sr.n = n;
682         pthread_cleanup_push_cast(free_scandir_result, &sr);
683         for (i = 0; i < n; i++) {
684                 if (!strstr(namelist[i]->d_name, ".conf"))
685                         continue;
686                 old_hwtable_size = VECTOR_SIZE(conf->hwtable);
687                 snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
688                 path[LINE_MAX-1] = '\0';
689                 process_file(conf, path);
690                 factorize_hwtable(conf->hwtable, old_hwtable_size,
691                                   namelist[i]->d_name);
692         }
693         pthread_cleanup_pop(1);
694 }
695
696 struct config *
697 load_config (char * file)
698 {
699         struct config *conf = alloc_config();
700
701         if (!conf)
702                 return NULL;
703
704         /*
705          * internal defaults
706          */
707         conf->verbosity = DEFAULT_VERBOSITY;
708
709         get_sys_max_fds(&conf->max_fds);
710         conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE);
711         conf->wwids_file = set_default(DEFAULT_WWIDS_FILE);
712         conf->prkeys_file = set_default(DEFAULT_PRKEYS_FILE);
713         conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
714         conf->attribute_flags = 0;
715         conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
716         conf->checkint = DEFAULT_CHECKINT;
717         conf->max_checkint = 0;
718         conf->force_sync = DEFAULT_FORCE_SYNC;
719         conf->partition_delim = (default_partition_delim != NULL ?
720                                  strdup(default_partition_delim) : NULL);
721         conf->processed_main_config = 0;
722         conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
723         conf->uxsock_timeout = DEFAULT_REPLY_TIMEOUT;
724         conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES;
725         conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY;
726         conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
727         conf->remove_retries = 0;
728         conf->ghost_delay = DEFAULT_GHOST_DELAY;
729         conf->all_tg_pt = DEFAULT_ALL_TG_PT;
730         /*
731          * preload default hwtable
732          */
733         conf->hwtable = vector_alloc();
734         if (!conf->hwtable)
735                         goto out;
736         if (setup_default_hwtable(conf->hwtable))
737                 goto out;
738
739 #ifdef CHECK_BUILTIN_HWTABLE
740         factorize_hwtable(conf->hwtable, 0, "builtin");
741 #endif
742         /*
743          * read the config file
744          */
745         conf->keywords = vector_alloc();
746         init_keywords(conf->keywords);
747         if (filepresent(file)) {
748                 int builtin_hwtable_size;
749
750                 builtin_hwtable_size = VECTOR_SIZE(conf->hwtable);
751                 if (process_file(conf, file)) {
752                         condlog(0, "error parsing config file");
753                         goto out;
754                 }
755                 factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
756         }
757
758         conf->processed_main_config = 1;
759         if (conf->config_dir == NULL)
760                 conf->config_dir = set_default(DEFAULT_CONFIG_DIR);
761         if (conf->config_dir && conf->config_dir[0] != '\0')
762                 process_config_dir(conf, conf->config_dir);
763
764         /*
765          * fill the voids left in the config file
766          */
767         if (conf->max_checkint == 0)
768                 conf->max_checkint = MAX_CHECKINT(conf->checkint);
769         if (conf->blist_devnode == NULL) {
770                 conf->blist_devnode = vector_alloc();
771
772                 if (!conf->blist_devnode)
773                         goto out;
774         }
775         if (conf->blist_wwid == NULL) {
776                 conf->blist_wwid = vector_alloc();
777
778                 if (!conf->blist_wwid)
779                         goto out;
780         }
781         if (conf->blist_device == NULL) {
782                 conf->blist_device = vector_alloc();
783
784                 if (!conf->blist_device)
785                         goto out;
786         }
787         if (conf->blist_property == NULL) {
788                 conf->blist_property = vector_alloc();
789
790                 if (!conf->blist_property)
791                         goto out;
792         }
793         if (conf->blist_protocol == NULL) {
794                 conf->blist_protocol = vector_alloc();
795
796                 if (!conf->blist_protocol)
797                         goto out;
798         }
799
800         if (conf->elist_devnode == NULL) {
801                 conf->elist_devnode = vector_alloc();
802
803                 if (!conf->elist_devnode)
804                         goto out;
805         }
806         if (conf->elist_wwid == NULL) {
807                 conf->elist_wwid = vector_alloc();
808
809                 if (!conf->elist_wwid)
810                         goto out;
811         }
812
813         if (conf->elist_device == NULL) {
814                 conf->elist_device = vector_alloc();
815
816                 if (!conf->elist_device)
817                         goto out;
818         }
819
820         if (conf->elist_property == NULL) {
821                 conf->elist_property = vector_alloc();
822
823                 if (!conf->elist_property)
824                         goto out;
825         }
826         if (conf->elist_protocol == NULL) {
827                 conf->elist_protocol = vector_alloc();
828
829                 if (!conf->elist_protocol)
830                         goto out;
831         }
832
833         if (setup_default_blist(conf))
834                 goto out;
835
836         if (conf->mptable == NULL) {
837                 conf->mptable = vector_alloc();
838                 if (!conf->mptable)
839                         goto out;
840         }
841
842         merge_mptable(conf->mptable);
843         merge_blacklist(conf->blist_devnode);
844         merge_blacklist(conf->blist_property);
845         merge_blacklist(conf->blist_wwid);
846         merge_blacklist_device(conf->blist_device);
847         merge_blacklist(conf->elist_devnode);
848         merge_blacklist(conf->elist_property);
849         merge_blacklist(conf->elist_wwid);
850         merge_blacklist_device(conf->elist_device);
851
852         if (conf->bindings_file == NULL)
853                 conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE);
854
855         if (!conf->multipath_dir || !conf->bindings_file ||
856             !conf->wwids_file || !conf->prkeys_file)
857                 goto out;
858
859         return conf;
860 out:
861         free_config(conf);
862         return NULL;
863 }
864
865 char *get_uid_attribute_by_attrs(struct config *conf,
866                                  const char *path_dev)
867 {
868         vector uid_attrs = &conf->uid_attrs;
869         int j;
870         char *att, *col;
871
872         vector_foreach_slot(uid_attrs, att, j) {
873                 col = strrchr(att, ':');
874                 if (!col)
875                         continue;
876                 if (!strncmp(path_dev, att, col - att))
877                         return col + 1;
878         }
879         return NULL;
880 }
881
882 int parse_uid_attrs(char *uid_attrs, struct config *conf)
883 {
884         vector attrs  = &conf->uid_attrs;
885         char *uid_attr_record, *tmp;
886         int  ret = 0, count;
887
888         if (!uid_attrs)
889                 return 1;
890
891         count = get_word(uid_attrs, &uid_attr_record);
892         while (uid_attr_record) {
893                 tmp = strchr(uid_attr_record, ':');
894                 if (!tmp) {
895                         condlog(2, "invalid record in uid_attrs: %s",
896                                 uid_attr_record);
897                         free(uid_attr_record);
898                         ret = 1;
899                 } else if (!vector_alloc_slot(attrs)) {
900                         free(uid_attr_record);
901                         ret = 1;
902                 } else
903                         vector_set_slot(attrs, uid_attr_record);
904                 if (!count)
905                         break;
906                 uid_attrs += count;
907                 count = get_word(uid_attrs, &uid_attr_record);
908         }
909         return ret;
910 }