multipath: make 'dev' internal to the multipath program
[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
351         /*
352          * Make sure features is consistent with
353          * no_path_retry
354          */
355         if (dst->no_path_retry == NO_PATH_RETRY_FAIL)
356                 remove_feature(&dst->features, "queue_if_no_path");
357         else if (dst->no_path_retry != NO_PATH_RETRY_UNDEF)
358                 add_feature(&dst->features, "queue_if_no_path");
359
360         return 0;
361 }
362
363 int
364 store_hwe (vector hwtable, struct hwentry * dhwe)
365 {
366         struct hwentry * hwe;
367
368         if (find_hwe_strmatch(hwtable, dhwe))
369                 return 0;
370
371         if (!(hwe = alloc_hwe()))
372                 return 1;
373
374         if (!dhwe->vendor || !(hwe->vendor = set_param_str(dhwe->vendor)))
375                 goto out;
376
377         if (!dhwe->product || !(hwe->product = set_param_str(dhwe->product)))
378                 goto out;
379
380         if (dhwe->revision && !(hwe->revision = set_param_str(dhwe->revision)))
381                 goto out;
382
383         if (dhwe->uid_attribute && !(hwe->uid_attribute = set_param_str(dhwe->uid_attribute)))
384                 goto out;
385
386         if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid)))
387                 goto out;
388
389         if (dhwe->features && !(hwe->features = set_param_str(dhwe->features)))
390                 goto out;
391
392         if (dhwe->hwhandler && !(hwe->hwhandler = set_param_str(dhwe->hwhandler)))
393                 goto out;
394
395         if (dhwe->selector && !(hwe->selector = set_param_str(dhwe->selector)))
396                 goto out;
397
398         if (dhwe->checker_name && !(hwe->checker_name = set_param_str(dhwe->checker_name)))
399                 goto out;
400
401         if (dhwe->prio_name && !(hwe->prio_name = set_param_str(dhwe->prio_name)))
402                 goto out;
403
404         if (dhwe->prio_args && !(hwe->prio_args = set_param_str(dhwe->prio_args)))
405                 goto out;
406
407         if (dhwe->alias_prefix && !(hwe->alias_prefix = set_param_str(dhwe->alias_prefix)))
408                 goto out;
409
410         hwe->pgpolicy = dhwe->pgpolicy;
411         hwe->pgfailback = dhwe->pgfailback;
412         hwe->rr_weight = dhwe->rr_weight;
413         hwe->no_path_retry = dhwe->no_path_retry;
414         hwe->minio = dhwe->minio;
415         hwe->minio_rq = dhwe->minio_rq;
416         hwe->flush_on_last_del = dhwe->flush_on_last_del;
417         hwe->fast_io_fail = dhwe->fast_io_fail;
418         hwe->dev_loss = dhwe->dev_loss;
419         hwe->user_friendly_names = dhwe->user_friendly_names;
420         hwe->retain_hwhandler = dhwe->retain_hwhandler;
421         hwe->detect_prio = dhwe->detect_prio;
422
423         if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
424                 goto out;
425
426         if (!vector_alloc_slot(hwtable))
427                 goto out;
428
429         vector_set_slot(hwtable, hwe);
430         return 0;
431 out:
432         free_hwe(hwe);
433         return 1;
434 }
435
436 static void
437 factorize_hwtable (vector hw, int n)
438 {
439         struct hwentry *hwe1, *hwe2;
440         int i, j;
441
442 restart:
443         vector_foreach_slot(hw, hwe1, i) {
444                 if (i == n)
445                         break;
446                 j = n;
447                 vector_foreach_slot_after(hw, hwe2, j) {
448                         if (hwe_regmatch(hwe1, hwe2))
449                                 continue;
450                         /* dup */
451                         merge_hwe(hwe2, hwe1);
452                         if (hwe_strmatch(hwe2, hwe1) == 0) {
453                                 vector_del_slot(hw, i);
454                                 free_hwe(hwe1);
455                                 n -= 1;
456                                 /*
457                                  * Play safe here; we have modified
458                                  * the original vector so the outer
459                                  * vector_foreach_slot() might
460                                  * become confused.
461                                  */
462                                 goto restart;
463                         }
464                 }
465         }
466         return;
467 }
468
469 struct config *
470 alloc_config (void)
471 {
472         return (struct config *)MALLOC(sizeof(struct config));
473 }
474
475 void
476 free_config (struct config * conf)
477 {
478         if (!conf)
479                 return;
480
481         if (conf->multipath_dir)
482                 FREE(conf->multipath_dir);
483
484         if (conf->selector)
485                 FREE(conf->selector);
486
487         if (conf->uid_attribute)
488                 FREE(conf->uid_attribute);
489
490         if (conf->getuid)
491                 FREE(conf->getuid);
492
493         if (conf->features)
494                 FREE(conf->features);
495
496         if (conf->hwhandler)
497                 FREE(conf->hwhandler);
498
499         if (conf->bindings_file)
500                 FREE(conf->bindings_file);
501
502         if (conf->wwids_file)
503                 FREE(conf->wwids_file);
504
505         if (conf->prio_name)
506                 FREE(conf->prio_name);
507
508         if (conf->alias_prefix)
509                 FREE(conf->alias_prefix);
510         if (conf->partition_delim)
511                 FREE(conf->partition_delim);
512
513         if (conf->prio_args)
514                 FREE(conf->prio_args);
515
516         if (conf->checker_name)
517                 FREE(conf->checker_name);
518
519         if (conf->config_dir)
520                 FREE(conf->config_dir);
521
522         if (conf->reservation_key)
523                 FREE(conf->reservation_key);
524
525         free_blacklist(conf->blist_devnode);
526         free_blacklist(conf->blist_wwid);
527         free_blacklist(conf->blist_property);
528         free_blacklist_device(conf->blist_device);
529
530         free_blacklist(conf->elist_devnode);
531         free_blacklist(conf->elist_wwid);
532         free_blacklist(conf->elist_property);
533         free_blacklist_device(conf->elist_device);
534
535         free_mptable(conf->mptable);
536         free_hwtable(conf->hwtable);
537         free_hwe(conf->overrides);
538         free_keywords(conf->keywords);
539         FREE(conf);
540 }
541
542 /* if multipath fails to process the config directory, it should continue,
543  * with just a warning message */
544 static void
545 process_config_dir(vector keywords, char *dir)
546 {
547         struct dirent **namelist;
548         int i, n;
549         char path[LINE_MAX];
550         int old_hwtable_size;
551
552         if (dir[0] != '/') {
553                 condlog(1, "config_dir '%s' must be a fully qualified path",
554                         dir);
555                 return;
556         }
557         n = scandir(dir, &namelist, NULL, alphasort);
558         if (n < 0) {
559                 if (errno == ENOENT)
560                         condlog(3, "No configuration dir '%s'", dir);
561                 else
562                         condlog(0, "couldn't open configuration dir '%s': %s",
563                                 dir, strerror(errno));
564                 return;
565         }
566         for (i = 0; i < n; i++) {
567                 if (!strstr(namelist[i]->d_name, ".conf"))
568                         continue;
569                 old_hwtable_size = VECTOR_SIZE(conf->hwtable);
570                 snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
571                 path[LINE_MAX-1] = '\0';
572                 process_file(path);
573                 if (VECTOR_SIZE(conf->hwtable) > old_hwtable_size)
574                         factorize_hwtable(conf->hwtable, old_hwtable_size);
575
576         }
577 }
578
579 int
580 load_config (char * file, struct udev *udev)
581 {
582         if (!conf)
583                 conf = alloc_config();
584
585         if (!conf || !udev)
586                 return 1;
587
588         /*
589          * internal defaults
590          */
591         if (!conf->verbosity)
592                 conf->verbosity = DEFAULT_VERBOSITY;
593
594         conf->udev = udev;
595         conf->minio = DEFAULT_MINIO;
596         conf->minio_rq = DEFAULT_MINIO_RQ;
597         get_sys_max_fds(&conf->max_fds);
598         conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE);
599         conf->wwids_file = set_default(DEFAULT_WWIDS_FILE);
600         conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
601         conf->features = set_default(DEFAULT_FEATURES);
602         conf->flush_on_last_del = 0;
603         conf->attribute_flags = 0;
604         conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
605         conf->checkint = DEFAULT_CHECKINT;
606         conf->max_checkint = 0;
607         conf->pgfailback = DEFAULT_FAILBACK;
608         conf->fast_io_fail = DEFAULT_FAST_IO_FAIL;
609         conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
610         conf->detect_prio = DEFAULT_DETECT_PRIO;
611         conf->force_sync = 0;
612         conf->partition_delim = NULL;
613         conf->processed_main_config = 0;
614         conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
615         conf->uxsock_timeout = DEFAULT_REPLY_TIMEOUT;
616         conf->uid_attribute = set_default(DEFAULT_UID_ATTRIBUTE);
617         conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES;
618         conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY;
619         conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
620         conf->deferred_remove = DEFAULT_DEFERRED_REMOVE;
621
622         /*
623          * preload default hwtable
624          */
625         if (conf->hwtable == NULL) {
626                 conf->hwtable = vector_alloc();
627
628                 if (!conf->hwtable)
629                         goto out;
630         }
631         if (setup_default_hwtable(conf->hwtable))
632                 goto out;
633
634         /*
635          * read the config file
636          */
637         set_current_keywords(&conf->keywords);
638         alloc_keywords();
639         init_keywords();
640         if (filepresent(file)) {
641                 int builtin_hwtable_size;
642
643                 builtin_hwtable_size = VECTOR_SIZE(conf->hwtable);
644                 if (process_file(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->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 0;
736 out:
737         free_config(conf);
738         return 1;
739 }
740