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