2 libmultipath/config.c | 56 +++++++++++++++++++++++++++++++-
3 libmultipath/config.h | 2 +
4 libmultipath/defaults.h | 1
5 libmultipath/dict.c | 69 +++++++++++++++++++++++++++++++++++----
6 libmultipath/parser.c | 78 +++++++++++++++++++++++----------------------
7 libmultipath/parser.h | 3 -
8 multipath.conf.annotated | 10 +++++
9 multipath.conf.defaults | 1
10 multipath/multipath.conf.5 | 7 ++++
11 9 files changed, 179 insertions(+), 48 deletions(-)
13 Index: multipath-tools-130222/libmultipath/parser.c
14 ===================================================================
15 --- multipath-tools-130222.orig/libmultipath/parser.c
16 +++ multipath-tools-130222/libmultipath/parser.c
25 @@ -453,14 +454,15 @@ set_value(vector strvec)
26 /* non-recursive configuration stream handler */
27 static int kw_level = 0;
29 -int warn_on_duplicates(vector uniques, char *str)
30 +int warn_on_duplicates(vector uniques, char *str, char *file)
35 vector_foreach_slot(uniques, tmp, i) {
36 if (!strcmp(str, tmp)) {
37 - condlog(1, "multipath.conf line %d, duplicate keyword: %s", line_nr, str);
38 + condlog(1, "%s line %d, duplicate keyword: %s",
39 + file, line_nr, str);
43 @@ -496,65 +498,70 @@ is_sublevel_keyword(char *str)
47 -validate_config_strvec(vector strvec)
48 +validate_config_strvec(vector strvec, char *file)
53 str = VECTOR_SLOT(strvec, 0);
55 - condlog(0, "can't parse option on line %d of config file",
57 + condlog(0, "can't parse option on line %d of %s",
62 if (VECTOR_SIZE(strvec) > 1)
63 - condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 1), line_nr);
64 + condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 1), line_nr, file);
68 - condlog(0, "invalid keyword '%s' on line %d of config file", str, line_nr);
69 + condlog(0, "invalid keyword '%s' on line %d of %s",
70 + str, line_nr, file);
73 if (is_sublevel_keyword(str)) {
74 str = VECTOR_SLOT(strvec, 1);
76 - condlog(0, "missing '{' on line %d of config file", line_nr);
77 + condlog(0, "missing '{' on line %d of %s",
80 - condlog(0, "expecting '{' on line %d of config file. found '%s'", line_nr, str);
81 + condlog(0, "expecting '{' on line %d of %s. found '%s'",
82 + line_nr, file, str);
83 else if (VECTOR_SIZE(strvec) > 2)
84 - condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr);
85 + condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
88 str = VECTOR_SLOT(strvec, 1);
90 - condlog(0, "missing value for option '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 0), line_nr);
91 + condlog(0, "missing value for option '%s' on line %d of %s",
92 + (char *)VECTOR_SLOT(strvec, 0), line_nr, file);
96 if (VECTOR_SIZE(strvec) > 2)
97 - condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr);
98 + condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
101 for (i = 2; i < VECTOR_SIZE(strvec); i++) {
102 str = VECTOR_SLOT(strvec, i);
104 - condlog(0, "can't parse value on line %d of config file", line_nr);
105 + condlog(0, "can't parse value on line %d of %s",
110 if (VECTOR_SIZE(strvec) > i + 1)
111 - condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr);
112 + condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr, file);
116 - condlog(0, "missing closing quotes on line %d of config file",
118 + condlog(0, "missing closing quotes on line %d of %s",
124 -process_stream(vector keywords)
126 +process_stream(vector keywords, char *file)
130 @@ -583,7 +590,7 @@ process_stream(vector keywords)
134 - if (validate_config_strvec(strvec) != 0) {
135 + if (validate_config_strvec(strvec, file) != 0) {
139 @@ -595,8 +602,8 @@ process_stream(vector keywords)
143 - condlog(0, "unmatched '%s' at line %d of config file",
145 + condlog(0, "unmatched '%s' at line %d of %s",
146 + EOB, line_nr, file);
149 for (i = 0; i < VECTOR_SIZE(keywords); i++) {
150 @@ -604,7 +611,7 @@ process_stream(vector keywords)
152 if (!strcmp(keyword->string, str)) {
153 if (keyword->unique &&
154 - warn_on_duplicates(uniques, str)) {
155 + warn_on_duplicates(uniques, str, file)) {
159 @@ -614,15 +621,15 @@ process_stream(vector keywords)
163 - r += process_stream(keyword->sub);
164 + r += process_stream(keyword->sub, file);
170 if (i >= VECTOR_SIZE(keywords))
171 - condlog(1, "multipath.conf +%d, invalid keyword: %s",
173 + condlog(1, "%s line %d, invalid keyword: %s",
174 + file, line_nr, str);
178 @@ -646,27 +653,24 @@ int alloc_keywords(void)
180 /* Data initialization */
182 -init_data(char *conf_file, void (*init_keywords) (void))
183 +process_file(char *file)
187 - stream = fopen(conf_file, "r");
189 + condlog(0, "No keywords alocated");
192 + stream = fopen(file, "r");
194 - syslog(LOG_WARNING, "Configuration file open problem");
195 + condlog(0, "couldn't open configuration file '%s': %s",
196 + file, strerror(errno));
200 - /* Init Keywords structure */
201 - (*init_keywords) ();
203 -/* Dump configuration *
204 - vector_dump(keywords);
205 - dump_keywords(keywords, 0);
208 /* Stream handling */
210 - r = process_stream(keywords);
211 + r = process_stream(keywords, file);
213 //free_keywords(keywords);
215 Index: multipath-tools-130222/libmultipath/dict.c
216 ===================================================================
217 --- multipath-tools-130222.orig/libmultipath/dict.c
218 +++ multipath-tools-130222/libmultipath/dict.c
219 @@ -117,6 +117,8 @@ reassign_maps_handler(vector strvec)
221 multipath_dir_handler(vector strvec)
223 + if (conf->multipath_dir)
224 + FREE(conf->multipath_dir);
225 conf->multipath_dir = set_value(strvec);
227 if (!conf->multipath_dir)
228 @@ -128,6 +130,8 @@ multipath_dir_handler(vector strvec)
230 def_selector_handler(vector strvec)
232 + if (conf->selector)
233 + FREE(conf->selector);
234 conf->selector = set_value(strvec);
237 @@ -155,6 +159,8 @@ def_pgpolicy_handler(vector strvec)
239 def_uid_attribute_handler(vector strvec)
241 + if (conf->uid_attribute)
242 + FREE(conf->uid_attribute);
243 conf->uid_attribute = set_value(strvec);
245 if (!conf->uid_attribute)
246 @@ -166,6 +172,8 @@ def_uid_attribute_handler(vector strvec)
248 def_prio_handler(vector strvec)
250 + if (conf->prio_name)
251 + FREE(conf->prio_name);
252 conf->prio_name = set_value(strvec);
254 if (!conf->prio_name)
255 @@ -177,6 +185,8 @@ def_prio_handler(vector strvec)
257 def_alias_prefix_handler(vector strvec)
259 + if (conf->alias_prefix)
260 + FREE(conf->alias_prefix);
261 conf->alias_prefix = set_value(strvec);
263 if (!conf->alias_prefix)
264 @@ -188,6 +198,8 @@ def_alias_prefix_handler(vector strvec)
266 def_prio_args_handler(vector strvec)
268 + if (conf->prio_args)
269 + FREE(conf->prio_args);
270 conf->prio_args = set_value(strvec);
272 if (!conf->prio_args)
273 @@ -199,6 +211,8 @@ def_prio_args_handler(vector strvec)
275 def_features_handler(vector strvec)
277 + if (conf->features)
278 + FREE(conf->features);
279 conf->features = set_value(strvec);
282 @@ -210,6 +224,8 @@ def_features_handler(vector strvec)
284 def_path_checker_handler(vector strvec)
286 + if (conf->checker_name)
287 + FREE(conf->checker_name);
288 conf->checker_name = set_value(strvec);
290 if (!conf->checker_name)
291 @@ -432,6 +448,23 @@ def_no_path_retry_handler(vector strvec)
297 +def_config_dir_handler(vector strvec)
299 + /* this is only valid in the main config file */
300 + if (conf->processed_main_config)
302 + if (conf->config_dir)
303 + FREE(conf->config_dir);
304 + conf->config_dir = set_value(strvec);
306 + if (!conf->config_dir)
313 def_queue_without_daemon(vector strvec)
315 @@ -611,6 +644,8 @@ def_names_handler(vector strvec)
317 bindings_file_handler(vector strvec)
319 + if (conf->bindings_file)
320 + FREE(conf->bindings_file);
321 conf->bindings_file = set_value(strvec);
323 if (!conf->bindings_file)
324 @@ -622,6 +657,8 @@ bindings_file_handler(vector strvec)
326 wwids_file_handler(vector strvec)
328 + if (conf->wwids_file)
329 + FREE(conf->wwids_file);
330 conf->wwids_file = set_value(strvec);
332 if (!conf->wwids_file)
333 @@ -770,9 +807,12 @@ def_ignore_new_boot_devs_handler(vector
335 blacklist_handler(vector strvec)
337 - conf->blist_devnode = vector_alloc();
338 - conf->blist_wwid = vector_alloc();
339 - conf->blist_device = vector_alloc();
340 + if (!conf->blist_devnode)
341 + conf->blist_devnode = vector_alloc();
342 + if (!conf->blist_wwid)
343 + conf->blist_wwid = vector_alloc();
344 + if (!conf->blist_device)
345 + conf->blist_device = vector_alloc();
347 if (!conf->blist_devnode || !conf->blist_wwid || !conf->blist_device)
349 @@ -783,9 +823,12 @@ blacklist_handler(vector strvec)
351 blacklist_exceptions_handler(vector strvec)
353 - conf->elist_devnode = vector_alloc();
354 - conf->elist_wwid = vector_alloc();
355 - conf->elist_device = vector_alloc();
356 + if (!conf->elist_devnode)
357 + conf->elist_devnode = vector_alloc();
358 + if (!conf->elist_wwid)
359 + conf->elist_wwid = vector_alloc();
360 + if (!conf->elist_device)
361 + conf->elist_device = vector_alloc();
363 if (!conf->elist_devnode || !conf->elist_wwid || !conf->elist_device)
365 @@ -1480,7 +1523,8 @@ hw_deferred_remove_handler(vector strvec
367 multipaths_handler(vector strvec)
369 - conf->mptable = vector_alloc();
370 + if (!conf->mptable)
371 + conf->mptable = vector_alloc();
375 @@ -2945,6 +2989,16 @@ snprint_def_ignore_new_boot_devs(char *
376 return snprintf(buff, len, "no");
381 +snprint_def_config_dir (char * buff, int len, void * data)
383 + if (!conf->config_dir)
386 + return snprintf(buff, len, "\"%s\"", conf->config_dir);
390 snprint_ble_simple (char * buff, int len, void * data)
392 @@ -3016,6 +3070,7 @@ init_keywords(void)
393 install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync);
394 install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove);
395 install_keyword("ignore_new_boot_devs", &def_ignore_new_boot_devs_handler, &snprint_def_ignore_new_boot_devs);
396 + install_keyword("config_dir", &def_config_dir_handler, &snprint_def_config_dir);
397 __deprecated install_keyword("default_selector", &def_selector_handler, NULL);
398 __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
399 __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
400 Index: multipath-tools-130222/libmultipath/parser.h
401 ===================================================================
402 --- multipath-tools-130222.orig/libmultipath/parser.h
403 +++ multipath-tools-130222/libmultipath/parser.h
404 @@ -76,9 +76,8 @@ extern int read_line(char *buf, int size
405 extern vector read_value_block(void);
406 extern int alloc_value_block(vector strvec, void (*alloc_func) (vector));
407 extern void *set_value(vector strvec);
408 -extern int process_stream(vector keywords);
409 extern int alloc_keywords(void);
410 -extern int init_data(char *conf_file, void (*init_keywords) (void));
411 +extern int process_file(char *conf_file);
412 extern struct keyword * find_keyword(vector v, char * name);
413 void set_current_keywords (vector *k);
414 int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
415 Index: multipath-tools-130222/libmultipath/config.c
416 ===================================================================
417 --- multipath-tools-130222.orig/libmultipath/config.c
418 +++ multipath-tools-130222/libmultipath/config.c
427 #include "checkers.h"
429 @@ -556,6 +559,7 @@ free_config (struct config * conf)
431 if (conf->wwids_file)
432 FREE(conf->wwids_file);
435 FREE(conf->prio_name);
437 @@ -567,6 +571,10 @@ free_config (struct config * conf)
439 if (conf->checker_name)
440 FREE(conf->checker_name);
442 + if (conf->config_dir)
443 + FREE(conf->config_dir);
445 if (conf->reservation_key)
446 FREE(conf->reservation_key);
448 @@ -584,6 +592,43 @@ free_config (struct config * conf)
452 +/* if multipath fails to process the config directory, it should continue,
453 + * with just a warning message */
455 +process_config_dir(vector keywords, char *dir)
457 + struct dirent **namelist;
459 + char path[LINE_MAX];
460 + int old_hwtable_size;
462 + if (dir[0] != '/') {
463 + condlog(1, "config_dir '%s' must be a fully qualified path",
467 + n = scandir(dir, &namelist, NULL, alphasort);
469 + if (errno == ENOENT)
470 + condlog(3, "No configuration dir '%s'", dir);
472 + condlog(0, "couldn't open configuration dir '%s': %s",
473 + dir, strerror(errno));
476 + for (i = 0; i < n; i++) {
477 + if (!strstr(namelist[i]->d_name, ".conf"))
479 + old_hwtable_size = VECTOR_SIZE(conf->hwtable);
480 + snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
481 + path[LINE_MAX-1] = '\0';
482 + process_file(path);
483 + if (VECTOR_SIZE(conf->hwtable) > old_hwtable_size)
484 + factorize_hwtable(conf->hwtable, old_hwtable_size);
490 load_config (char * file, struct udev *udev)
492 @@ -623,6 +668,7 @@ load_config (char * file, struct udev *u
493 conf->hw_strmatch = 0;
494 conf->force_sync = 0;
495 conf->ignore_new_boot_devs = 0;
496 + conf->processed_main_config = 0;
499 * preload default hwtable
500 @@ -641,11 +687,12 @@ load_config (char * file, struct udev *u
502 set_current_keywords(&conf->keywords);
505 if (filepresent(file)) {
506 int builtin_hwtable_size;
508 builtin_hwtable_size = VECTOR_SIZE(conf->hwtable);
509 - if (init_data(file, init_keywords)) {
510 + if (process_file(file)) {
511 condlog(0, "error parsing config file");
514 @@ -658,7 +705,6 @@ load_config (char * file, struct udev *u
519 condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
520 condlog(0, "A default multipath.conf file is located at");
521 condlog(0, "/usr/share/doc/device-mapper-multipath-%d.%d.%d/multipath.conf", MULTIPATH_VERSION(VERSION_CODE));
522 @@ -677,6 +723,12 @@ load_config (char * file, struct udev *u
526 + conf->processed_main_config = 1;
527 + if (conf->config_dir == NULL)
528 + conf->config_dir = set_default(DEFAULT_CONFIG_DIR);
529 + if (conf->config_dir && conf->config_dir[0] != '\0')
530 + process_config_dir(conf->keywords, conf->config_dir);
533 * fill the voids left in the config file
535 Index: multipath-tools-130222/libmultipath/config.h
536 ===================================================================
537 --- multipath-tools-130222.orig/libmultipath/config.h
538 +++ multipath-tools-130222/libmultipath/config.h
539 @@ -132,6 +132,7 @@ struct config {
542 int ignore_new_boot_devs;
543 + int processed_main_config;
544 unsigned int version[3];
547 @@ -147,6 +148,7 @@ struct config {
552 unsigned char * reservation_key;
555 Index: multipath-tools-130222/libmultipath/defaults.h
556 ===================================================================
557 --- multipath-tools-130222.orig/libmultipath/defaults.h
558 +++ multipath-tools-130222/libmultipath/defaults.h
560 #define DEFAULT_CONFIGFILE "/etc/multipath.conf"
561 #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings"
562 #define DEFAULT_WWIDS_FILE "/etc/multipath/wwids"
563 +#define DEFAULT_CONFIG_DIR "/etc/multipath/conf.d"
565 char * set_default (char * str);
566 Index: multipath-tools-130222/multipath.conf.annotated
567 ===================================================================
568 --- multipath-tools-130222.orig/multipath.conf.annotated
569 +++ multipath-tools-130222/multipath.conf.annotated
576 +# # name : config_dir
577 +# # scope : multipath & multipathd
578 +# # desc : If not set to an empty string, multipath will search
579 +# # this directory alphabetically for files ending in ".conf"
580 +# # and it will read configuration information from these
581 +# # files, just as if it was in /etc/multipath.conf
582 +# # values : "" or a fully qualified pathname
583 +# # default : "/etc/multipath/conf.d"
587 Index: multipath-tools-130222/multipath.conf.defaults
588 ===================================================================
589 --- multipath-tools-130222.orig/multipath.conf.defaults
590 +++ multipath-tools-130222/multipath.conf.defaults
592 # log_checker_err always
593 # retain_attached_hw_handler no
595 +# config_dir "/etc/multipath/conf.d"
598 # devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
599 Index: multipath-tools-130222/multipath/multipath.conf.5
600 ===================================================================
601 --- multipath-tools-130222.orig/multipath/multipath.conf.5
602 +++ multipath-tools-130222/multipath/multipath.conf.5
603 @@ -430,6 +430,13 @@ still in use, it will be freed when the
604 to the multipath device before the last user closes it, the deferred remove
605 will be canceled. Default is
609 +If set to anything other than "", multipath will search this directory
610 +alphabetically for file ending in ".conf" and it will read configuration
611 +information from them, just as if it was in /etc/multipath.conf. config_dir
612 +must either be "" or a fully qualified directory name. Default is
613 +.I "/etc/multipath/conf.d"
615 .SH "blacklist section"