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