Blame SOURCES/0112-RHBZ-1194917-add-config_dir-option.patch

4728c8
---
4728c8
 libmultipath/config.c      |   56 +++++++++++++++++++++++++++++++-
4728c8
 libmultipath/config.h      |    2 +
4728c8
 libmultipath/defaults.h    |    1 
4728c8
 libmultipath/dict.c        |   69 +++++++++++++++++++++++++++++++++++----
4728c8
 libmultipath/parser.c      |   78 +++++++++++++++++++++++----------------------
4728c8
 libmultipath/parser.h      |    3 -
4728c8
 multipath.conf.annotated   |   10 +++++
4728c8
 multipath.conf.defaults    |    1 
4728c8
 multipath/multipath.conf.5 |    7 ++++
4728c8
 9 files changed, 179 insertions(+), 48 deletions(-)
4728c8
4728c8
Index: multipath-tools-130222/libmultipath/parser.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/parser.c
4728c8
+++ multipath-tools-130222/libmultipath/parser.c
4728c8
@@ -18,6 +18,7 @@
4728c8
  */
4728c8
 
4728c8
 #include <syslog.h>
4728c8
+#include <errno.h>
4728c8
 
4728c8
 #include "parser.h"
4728c8
 #include "memory.h"
4728c8
@@ -453,14 +454,15 @@ set_value(vector strvec)
4728c8
 /* non-recursive configuration stream handler */
4728c8
 static int kw_level = 0;
4728c8
 
4728c8
-int warn_on_duplicates(vector uniques, char *str)
4728c8
+int warn_on_duplicates(vector uniques, char *str, char *file)
4728c8
 {
4728c8
 	char *tmp;
4728c8
 	int i;
4728c8
 
4728c8
 	vector_foreach_slot(uniques, tmp, i) {
4728c8
 		if (!strcmp(str, tmp)) {
4728c8
-			condlog(1, "multipath.conf line %d, duplicate keyword: %s", line_nr, str);
4728c8
+			condlog(1, "%s line %d, duplicate keyword: %s",
4728c8
+				file, line_nr, str);
4728c8
 			return 0;
4728c8
 		}
4728c8
 	}
4728c8
@@ -496,65 +498,70 @@ is_sublevel_keyword(char *str)
4728c8
 }
4728c8
 
4728c8
 int
4728c8
-validate_config_strvec(vector strvec)
4728c8
+validate_config_strvec(vector strvec, char *file)
4728c8
 {
4728c8
 	char *str;
4728c8
 	int i;
4728c8
 
4728c8
 	str = VECTOR_SLOT(strvec, 0);
4728c8
 	if (str == NULL) {
4728c8
-		condlog(0, "can't parse option on line %d of config file",
4728c8
-			line_nr);
4728c8
+		condlog(0, "can't parse option on line %d of %s",
4728c8
+			line_nr, file);
4728c8
 	return -1;
4728c8
 	}
4728c8
 	if (*str == '}') {
4728c8
 		if (VECTOR_SIZE(strvec) > 1)
4728c8
-			condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 1), line_nr);
4728c8
+			condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 1), line_nr, file);
4728c8
 		return 0;
4728c8
 	}
4728c8
 	if (*str == '{') {
4728c8
-		condlog(0, "invalid keyword '%s' on line %d of config file", str, line_nr);
4728c8
+		condlog(0, "invalid keyword '%s' on line %d of %s",
4728c8
+			str, line_nr, file);
4728c8
 		return -1;
4728c8
 	}
4728c8
 	if (is_sublevel_keyword(str)) {
4728c8
 		str = VECTOR_SLOT(strvec, 1);
4728c8
 		if (str == NULL)
4728c8
-			condlog(0, "missing '{' on line %d of config file", line_nr);
4728c8
+			condlog(0, "missing '{' on line %d of %s",
4728c8
+				line_nr, file);
4728c8
 		else if (*str != '{')
4728c8
-			condlog(0, "expecting '{' on line %d of config file. found '%s'", line_nr, str);
4728c8
+			condlog(0, "expecting '{' on line %d of %s. found '%s'",
4728c8
+				line_nr, file, str);
4728c8
 		else if (VECTOR_SIZE(strvec) > 2)
4728c8
-			condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr);
4728c8
+			condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
4728c8
 		return 0;
4728c8
 	}
4728c8
 	str = VECTOR_SLOT(strvec, 1);
4728c8
 	if (str == NULL) {
4728c8
-		condlog(0, "missing value for option '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 0), line_nr);
4728c8
+		condlog(0, "missing value for option '%s' on line %d of %s",
4728c8
+			(char *)VECTOR_SLOT(strvec, 0), line_nr, file);
4728c8
 		return -1;
4728c8
 	}
4728c8
 	if (*str != '"') {
4728c8
 		if (VECTOR_SIZE(strvec) > 2)
4728c8
-			condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr);
4728c8
+			condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
4728c8
 		return 0;
4728c8
 	}
4728c8
 	for (i = 2; i < VECTOR_SIZE(strvec); i++) {
4728c8
 		str = VECTOR_SLOT(strvec, i);
4728c8
 		if (str == NULL) {
4728c8
-			condlog(0, "can't parse value on line %d of config file", line_nr);
4728c8
+			condlog(0, "can't parse value on line %d of %s",
4728c8
+				line_nr, file);
4728c8
 			return -1;
4728c8
 		}
4728c8
 		if (*str == '"') {
4728c8
 			if (VECTOR_SIZE(strvec) > i + 1)
4728c8
-				condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr);
4728c8
+				condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr, file);
4728c8
 			return 0;
4728c8
 		}
4728c8
 	}
4728c8
-	condlog(0, "missing closing quotes on line %d of config file",
4728c8
-		line_nr);
4728c8
+	condlog(0, "missing closing quotes on line %d of %s",
4728c8
+		line_nr, file);
4728c8
 	return 0;
4728c8
 }
4728c8
 
4728c8
-int
4728c8
-process_stream(vector keywords)
4728c8
+static int
4728c8
+process_stream(vector keywords, char *file)
4728c8
 {
4728c8
 	int i;
4728c8
 	int r = 0;
4728c8
@@ -583,7 +590,7 @@ process_stream(vector keywords)
4728c8
 		if (!strvec)
4728c8
 			continue;
4728c8
 
4728c8
-		if (validate_config_strvec(strvec) != 0) {
4728c8
+		if (validate_config_strvec(strvec, file) != 0) {
4728c8
 			free_strvec(strvec);
4728c8
 			continue;
4728c8
 		}
4728c8
@@ -595,8 +602,8 @@ process_stream(vector keywords)
4728c8
 				free_strvec(strvec);
4728c8
 				break;
4728c8
 			}
4728c8
-			condlog(0, "unmatched '%s' at line %d of config file",
4728c8
-				EOB, line_nr);
4728c8
+			condlog(0, "unmatched '%s' at line %d of %s",
4728c8
+				EOB, line_nr, file);
4728c8
 		}
4728c8
 
4728c8
 		for (i = 0; i < VECTOR_SIZE(keywords); i++) {
4728c8
@@ -604,7 +611,7 @@ process_stream(vector keywords)
4728c8
 
4728c8
 			if (!strcmp(keyword->string, str)) {
4728c8
 				if (keyword->unique &&
4728c8
-				    warn_on_duplicates(uniques, str)) {
4728c8
+				    warn_on_duplicates(uniques, str, file)) {
4728c8
 						r = 1;
4728c8
 						free_strvec(strvec);
4728c8
 						goto out;
4728c8
@@ -614,15 +621,15 @@ process_stream(vector keywords)
4728c8
 
4728c8
 				if (keyword->sub) {
4728c8
 					kw_level++;
4728c8
-					r += process_stream(keyword->sub);
4728c8
+					r += process_stream(keyword->sub, file);
4728c8
 					kw_level--;
4728c8
 				}
4728c8
 				break;
4728c8
 			}
4728c8
 		}
4728c8
 		if (i >= VECTOR_SIZE(keywords))
4728c8
-			condlog(1, "multipath.conf +%d, invalid keyword: %s",
4728c8
-				line_nr, str);
4728c8
+			condlog(1, "%s line %d, invalid keyword: %s",
4728c8
+				file, line_nr, str);
4728c8
 
4728c8
 		free_strvec(strvec);
4728c8
 	}
4728c8
@@ -646,27 +653,24 @@ int alloc_keywords(void)
4728c8
 
4728c8
 /* Data initialization */
4728c8
 int
4728c8
-init_data(char *conf_file, void (*init_keywords) (void))
4728c8
+process_file(char *file)
4728c8
 {
4728c8
 	int r;
4728c8
 
4728c8
-	stream = fopen(conf_file, "r");
4728c8
+	if (!keywords) {
4728c8
+		condlog(0, "No keywords alocated");
4728c8
+		return 1;
4728c8
+	}
4728c8
+	stream = fopen(file, "r");
4728c8
 	if (!stream) {
4728c8
-		syslog(LOG_WARNING, "Configuration file open problem");
4728c8
+		condlog(0, "couldn't open configuration file '%s': %s",
4728c8
+			file, strerror(errno));
4728c8
 		return 1;
4728c8
 	}
4728c8
 
4728c8
-	/* Init Keywords structure */
4728c8
-	(*init_keywords) ();
4728c8
-
4728c8
-/* Dump configuration *
4728c8
-  vector_dump(keywords);
4728c8
-  dump_keywords(keywords, 0);
4728c8
-*/
4728c8
-
4728c8
 	/* Stream handling */
4728c8
 	line_nr = 0;
4728c8
-	r = process_stream(keywords);
4728c8
+	r = process_stream(keywords, file);
4728c8
 	fclose(stream);
4728c8
 	//free_keywords(keywords);
4728c8
 
4728c8
Index: multipath-tools-130222/libmultipath/dict.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/dict.c
4728c8
+++ multipath-tools-130222/libmultipath/dict.c
4728c8
@@ -117,6 +117,8 @@ reassign_maps_handler(vector strvec)
4728c8
 static int
4728c8
 multipath_dir_handler(vector strvec)
4728c8
 {
4728c8
+	if (conf->multipath_dir)
4728c8
+		FREE(conf->multipath_dir);
4728c8
 	conf->multipath_dir = set_value(strvec);
4728c8
 
4728c8
 	if (!conf->multipath_dir)
4728c8
@@ -128,6 +130,8 @@ multipath_dir_handler(vector strvec)
4728c8
 static int
4728c8
 def_selector_handler(vector strvec)
4728c8
 {
4728c8
+	if (conf->selector)
4728c8
+		FREE(conf->selector);
4728c8
 	conf->selector = set_value(strvec);
4728c8
 
4728c8
 	if (!conf->selector)
4728c8
@@ -155,6 +159,8 @@ def_pgpolicy_handler(vector strvec)
4728c8
 static int
4728c8
 def_uid_attribute_handler(vector strvec)
4728c8
 {
4728c8
+	if (conf->uid_attribute)
4728c8
+		FREE(conf->uid_attribute);
4728c8
 	conf->uid_attribute = set_value(strvec);
4728c8
 
4728c8
 	if (!conf->uid_attribute)
4728c8
@@ -166,6 +172,8 @@ def_uid_attribute_handler(vector strvec)
4728c8
 static int
4728c8
 def_prio_handler(vector strvec)
4728c8
 {
4728c8
+	if (conf->prio_name)
4728c8
+		FREE(conf->prio_name);
4728c8
 	conf->prio_name = set_value(strvec);
4728c8
 
4728c8
 	if (!conf->prio_name)
4728c8
@@ -177,6 +185,8 @@ def_prio_handler(vector strvec)
4728c8
 static int
4728c8
 def_alias_prefix_handler(vector strvec)
4728c8
 {
4728c8
+	if (conf->alias_prefix)
4728c8
+		FREE(conf->alias_prefix);
4728c8
 	conf->alias_prefix = set_value(strvec);
4728c8
 
4728c8
 	if (!conf->alias_prefix)
4728c8
@@ -188,6 +198,8 @@ def_alias_prefix_handler(vector strvec)
4728c8
 static int
4728c8
 def_prio_args_handler(vector strvec)
4728c8
 {
4728c8
+	if (conf->prio_args)
4728c8
+		FREE(conf->prio_args);
4728c8
 	conf->prio_args = set_value(strvec);
4728c8
 
4728c8
 	if (!conf->prio_args)
4728c8
@@ -199,6 +211,8 @@ def_prio_args_handler(vector strvec)
4728c8
 static int
4728c8
 def_features_handler(vector strvec)
4728c8
 {
4728c8
+	if (conf->features)
4728c8
+		FREE(conf->features);
4728c8
 	conf->features = set_value(strvec);
4728c8
 
4728c8
 	if (!conf->features)
4728c8
@@ -210,6 +224,8 @@ def_features_handler(vector strvec)
4728c8
 static int
4728c8
 def_path_checker_handler(vector strvec)
4728c8
 {
4728c8
+	if (conf->checker_name)
4728c8
+		FREE(conf->checker_name);
4728c8
 	conf->checker_name = set_value(strvec);
4728c8
 
4728c8
 	if (!conf->checker_name)
4728c8
@@ -432,6 +448,23 @@ def_no_path_retry_handler(vector strvec)
4728c8
 	return 0;
4728c8
 }
4728c8
 
4728c8
+
4728c8
+static int
4728c8
+def_config_dir_handler(vector strvec)
4728c8
+{
4728c8
+	/* this is only valid in the main config file */
4728c8
+	if (conf->processed_main_config)
4728c8
+		return 0;
4728c8
+	if (conf->config_dir)
4728c8
+		FREE(conf->config_dir);
4728c8
+	conf->config_dir = set_value(strvec);
4728c8
+
4728c8
+	if (!conf->config_dir)
4728c8
+		return 1;
4728c8
+
4728c8
+	return 0;
4728c8
+}
4728c8
+
4728c8
 static int
4728c8
 def_queue_without_daemon(vector strvec)
4728c8
 {
4728c8
@@ -611,6 +644,8 @@ def_names_handler(vector strvec)
4728c8
 static int
4728c8
 bindings_file_handler(vector strvec)
4728c8
 {
4728c8
+	if (conf->bindings_file)
4728c8
+		FREE(conf->bindings_file);
4728c8
 	conf->bindings_file = set_value(strvec);
4728c8
 
4728c8
 	if (!conf->bindings_file)
4728c8
@@ -622,6 +657,8 @@ bindings_file_handler(vector strvec)
4728c8
 static int
4728c8
 wwids_file_handler(vector strvec)
4728c8
 {
4728c8
+	if (conf->wwids_file)
4728c8
+		FREE(conf->wwids_file);
4728c8
 	conf->wwids_file = set_value(strvec);
4728c8
 
4728c8
 	if (!conf->wwids_file)
4728c8
@@ -770,9 +807,12 @@ def_ignore_new_boot_devs_handler(vector
4728c8
 static int
4728c8
 blacklist_handler(vector strvec)
4728c8
 {
4728c8
-	conf->blist_devnode = vector_alloc();
4728c8
-	conf->blist_wwid = vector_alloc();
4728c8
-	conf->blist_device = vector_alloc();
4728c8
+	if (!conf->blist_devnode)
4728c8
+		conf->blist_devnode = vector_alloc();
4728c8
+	if (!conf->blist_wwid)
4728c8
+		conf->blist_wwid = vector_alloc();
4728c8
+	if (!conf->blist_device)
4728c8
+		conf->blist_device = vector_alloc();
4728c8
 
4728c8
 	if (!conf->blist_devnode || !conf->blist_wwid || !conf->blist_device)
4728c8
 		return 1;
4728c8
@@ -783,9 +823,12 @@ blacklist_handler(vector strvec)
4728c8
 static int
4728c8
 blacklist_exceptions_handler(vector strvec)
4728c8
 {
4728c8
-	conf->elist_devnode = vector_alloc();
4728c8
-	conf->elist_wwid = vector_alloc();
4728c8
-	conf->elist_device = vector_alloc();
4728c8
+	if (!conf->elist_devnode)
4728c8
+		conf->elist_devnode = vector_alloc();
4728c8
+	if (!conf->elist_wwid)
4728c8
+		conf->elist_wwid = vector_alloc();
4728c8
+	if (!conf->elist_device)
4728c8
+		conf->elist_device = vector_alloc();
4728c8
 
4728c8
 	if (!conf->elist_devnode || !conf->elist_wwid || !conf->elist_device)
4728c8
 		return 1;
4728c8
@@ -1480,7 +1523,8 @@ hw_deferred_remove_handler(vector strvec
4728c8
 static int
4728c8
 multipaths_handler(vector strvec)
4728c8
 {
4728c8
-	conf->mptable = vector_alloc();
4728c8
+	if (!conf->mptable)
4728c8
+		conf->mptable = vector_alloc();
4728c8
 
4728c8
 	if (!conf->mptable)
4728c8
 		return 1;
4728c8
@@ -2945,6 +2989,16 @@ snprint_def_ignore_new_boot_devs(char *
4728c8
 		return snprintf(buff, len, "no");
4728c8
 }
4728c8
 
4728c8
+
4728c8
+static int
4728c8
+snprint_def_config_dir (char * buff, int len, void * data)
4728c8
+{
4728c8
+	if (!conf->config_dir)
4728c8
+		return 0;
4728c8
+
4728c8
+	return snprintf(buff, len, "\"%s\"", conf->config_dir);
4728c8
+}
4728c8
+
4728c8
 static int
4728c8
 snprint_ble_simple (char * buff, int len, void * data)
4728c8
 {
4728c8
@@ -3016,6 +3070,7 @@ init_keywords(void)
4728c8
 	install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync);
4728c8
 	install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove);
4728c8
 	install_keyword("ignore_new_boot_devs", &def_ignore_new_boot_devs_handler, &snprint_def_ignore_new_boot_devs);
4728c8
+	install_keyword("config_dir", &def_config_dir_handler, &snprint_def_config_dir);
4728c8
 	__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
4728c8
 	__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
4728c8
 	__deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
4728c8
Index: multipath-tools-130222/libmultipath/parser.h
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/parser.h
4728c8
+++ multipath-tools-130222/libmultipath/parser.h
4728c8
@@ -76,9 +76,8 @@ extern int read_line(char *buf, int size
4728c8
 extern vector read_value_block(void);
4728c8
 extern int alloc_value_block(vector strvec, void (*alloc_func) (vector));
4728c8
 extern void *set_value(vector strvec);
4728c8
-extern int process_stream(vector keywords);
4728c8
 extern int alloc_keywords(void);
4728c8
-extern int init_data(char *conf_file, void (*init_keywords) (void));
4728c8
+extern int process_file(char *conf_file);
4728c8
 extern struct keyword * find_keyword(vector v, char * name);
4728c8
 void set_current_keywords (vector *k);
4728c8
 int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
4728c8
Index: multipath-tools-130222/libmultipath/config.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/config.c
4728c8
+++ multipath-tools-130222/libmultipath/config.c
4728c8
@@ -6,6 +6,9 @@
4728c8
 #include <stdio.h>
4728c8
 #include <string.h>
4728c8
 #include <libudev.h>
4728c8
+#include <dirent.h>
4728c8
+#include <limits.h>
4728c8
+#include <errno.h>
4728c8
 
4728c8
 #include "checkers.h"
4728c8
 #include "memory.h"
4728c8
@@ -556,6 +559,7 @@ free_config (struct config * conf)
4728c8
 
4728c8
 	if (conf->wwids_file)
4728c8
 		FREE(conf->wwids_file);
4728c8
+
4728c8
 	if (conf->prio_name)
4728c8
 		FREE(conf->prio_name);
4728c8
 
4728c8
@@ -567,6 +571,10 @@ free_config (struct config * conf)
4728c8
 
4728c8
 	if (conf->checker_name)
4728c8
 		FREE(conf->checker_name);
4728c8
+
4728c8
+	if (conf->config_dir)
4728c8
+		FREE(conf->config_dir);
4728c8
+
4728c8
 	if (conf->reservation_key)
4728c8
 		FREE(conf->reservation_key);
4728c8
 
4728c8
@@ -584,6 +592,43 @@ free_config (struct config * conf)
4728c8
 	FREE(conf);
4728c8
 }
4728c8
 
4728c8
+/* if multipath fails to process the config directory, it should continue,
4728c8
+ * with just a warning message */
4728c8
+static void
4728c8
+process_config_dir(vector keywords, char *dir)
4728c8
+{
4728c8
+	struct dirent **namelist;
4728c8
+	int i, n;
4728c8
+	char path[LINE_MAX];
4728c8
+	int old_hwtable_size;
4728c8
+
4728c8
+	if (dir[0] != '/') {
4728c8
+		condlog(1, "config_dir '%s' must be a fully qualified path",
4728c8
+			dir);
4728c8
+		return;
4728c8
+	}
4728c8
+	n = scandir(dir, &namelist, NULL, alphasort);
4728c8
+	if (n < 0) {
4728c8
+		if (errno == ENOENT)
4728c8
+			condlog(3, "No configuration dir '%s'", dir);
4728c8
+		else
4728c8
+			condlog(0, "couldn't open configuration dir '%s': %s",
4728c8
+				dir, strerror(errno));
4728c8
+		return;
4728c8
+	}
4728c8
+	for (i = 0; i < n; i++) {
4728c8
+		if (!strstr(namelist[i]->d_name, ".conf"))
4728c8
+			continue;
4728c8
+		old_hwtable_size = VECTOR_SIZE(conf->hwtable);
4728c8
+		snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
4728c8
+		path[LINE_MAX-1] = '\0';
4728c8
+		process_file(path);
4728c8
+		if (VECTOR_SIZE(conf->hwtable) > old_hwtable_size)
4728c8
+			factorize_hwtable(conf->hwtable, old_hwtable_size);
4728c8
+
4728c8
+	}
4728c8
+}
4728c8
+
4728c8
 int
4728c8
 load_config (char * file, struct udev *udev)
4728c8
 {
4728c8
@@ -623,6 +668,7 @@ load_config (char * file, struct udev *u
4728c8
 	conf->hw_strmatch = 0;
4728c8
 	conf->force_sync = 0;
4728c8
 	conf->ignore_new_boot_devs = 0;
4728c8
+	conf->processed_main_config = 0;
4728c8
 
4728c8
 	/*
4728c8
 	 * preload default hwtable
4728c8
@@ -641,11 +687,12 @@ load_config (char * file, struct udev *u
4728c8
 	 */
4728c8
 	set_current_keywords(&conf->keywords);
4728c8
 	alloc_keywords();
4728c8
+	init_keywords();
4728c8
 	if (filepresent(file)) {
4728c8
 		int builtin_hwtable_size;
4728c8
 
4728c8
 		builtin_hwtable_size = VECTOR_SIZE(conf->hwtable);
4728c8
-		if (init_data(file, init_keywords)) {
4728c8
+		if (process_file(file)) {
4728c8
 			condlog(0, "error parsing config file");
4728c8
 			goto out;
4728c8
 		}
4728c8
@@ -658,7 +705,6 @@ load_config (char * file, struct udev *u
4728c8
 		}
4728c8
 
4728c8
 	} else {
4728c8
-		init_keywords();
4728c8
 		condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
4728c8
 		condlog(0, "A default multipath.conf file is located at");
4728c8
 		condlog(0, "/usr/share/doc/device-mapper-multipath-%d.%d.%d/multipath.conf", MULTIPATH_VERSION(VERSION_CODE));
4728c8
@@ -677,6 +723,12 @@ load_config (char * file, struct udev *u
4728c8
 		}
4728c8
 	}
4728c8
 
4728c8
+	conf->processed_main_config = 1;
4728c8
+	if (conf->config_dir == NULL)
4728c8
+		conf->config_dir = set_default(DEFAULT_CONFIG_DIR);
4728c8
+	if (conf->config_dir && conf->config_dir[0] != '\0')
4728c8
+		process_config_dir(conf->keywords, conf->config_dir);
4728c8
+
4728c8
 	/*
4728c8
 	 * fill the voids left in the config file
4728c8
 	 */
4728c8
Index: multipath-tools-130222/libmultipath/config.h
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/config.h
4728c8
+++ multipath-tools-130222/libmultipath/config.h
4728c8
@@ -132,6 +132,7 @@ struct config {
4728c8
 	int force_sync;
4728c8
 	int deferred_remove;
4728c8
 	int ignore_new_boot_devs;
4728c8
+	int processed_main_config;
4728c8
 	unsigned int version[3];
4728c8
 
4728c8
 	char * dev;
4728c8
@@ -147,6 +148,7 @@ struct config {
4728c8
 	char * prio_args;
4728c8
 	char * checker_name;
4728c8
 	char * alias_prefix;
4728c8
+	char * config_dir;
4728c8
 	unsigned char * reservation_key;
4728c8
 
4728c8
 	vector keywords;
4728c8
Index: multipath-tools-130222/libmultipath/defaults.h
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/defaults.h
4728c8
+++ multipath-tools-130222/libmultipath/defaults.h
4728c8
@@ -31,5 +31,6 @@
4728c8
 #define DEFAULT_CONFIGFILE	"/etc/multipath.conf"
4728c8
 #define DEFAULT_BINDINGS_FILE	"/etc/multipath/bindings"
4728c8
 #define DEFAULT_WWIDS_FILE	"/etc/multipath/wwids"
4728c8
+#define DEFAULT_CONFIG_DIR	"/etc/multipath/conf.d"
4728c8
 
4728c8
 char * set_default (char * str);
4728c8
Index: multipath-tools-130222/multipath.conf.annotated
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/multipath.conf.annotated
4728c8
+++ multipath-tools-130222/multipath.conf.annotated
4728c8
@@ -232,6 +232,16 @@
4728c8
 #	# values  : yes|no
4728c8
 #	# default : no
4728c8
 #	force_sync yes
4728c8
+#
4728c8
+#	#
4728c8
+#	# name    : config_dir
4728c8
+#	# scope   : multipath & multipathd
4728c8
+#	# desc    : If not set to an empty string, multipath will search
4728c8
+#	#           this directory alphabetically for files ending in ".conf"
4728c8
+#	#           and it will read configuration information from these
4728c8
+#	#           files, just as if it was in /etc/multipath.conf
4728c8
+#	# values  : "" or a fully qualified pathname
4728c8
+#	# default : "/etc/multipath/conf.d"
4728c8
 #}
4728c8
 #	
4728c8
 ##
4728c8
Index: multipath-tools-130222/multipath.conf.defaults
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/multipath.conf.defaults
4728c8
+++ multipath-tools-130222/multipath.conf.defaults
4728c8
@@ -26,6 +26,7 @@
4728c8
 #	log_checker_err always
4728c8
 #	retain_attached_hw_handler no
4728c8
 #	detect_prio no
4728c8
+#	config_dir "/etc/multipath/conf.d"
4728c8
 #}
4728c8
 #blacklist {
4728c8
 #	devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
4728c8
Index: multipath-tools-130222/multipath/multipath.conf.5
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/multipath/multipath.conf.5
4728c8
+++ multipath-tools-130222/multipath/multipath.conf.5
4728c8
@@ -452,6 +452,13 @@ still in use, it will be freed when the
4728c8
 to the multipath device before the last user closes it, the deferred remove
4728c8
 will be canceled. Default is
4728c8
 .I no
4728c8
+.TP
4728c8
+.B config_dir
4728c8
+If set to anything other than "", multipath will search this directory
4728c8
+alphabetically for file ending in ".conf" and it will read configuration
4728c8
+information from them, just as if it was in /etc/multipath.conf.  config_dir
4728c8
+must either be "" or a fully qualified directory name. Default is
4728c8
+.I "/etc/multipath/conf.d"
4728c8
 .
4728c8
 .SH "blacklist section"
4728c8
 The