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

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