Add -p and -P command line options for controlling plugin selection

This patch adds new -p (enable) and -P (disable) command line options to
select which plugins get loaded and which ones don't during bluetoothd
startup.
diff --git a/src/hcid.h b/src/hcid.h
index 85effdb..040411b 100644
--- a/src/hcid.h
+++ b/src/hcid.h
@@ -80,7 +80,8 @@
 
 void set_pin_length(bdaddr_t *sba, int length);
 
-gboolean plugin_init(GKeyFile *config);
+gboolean plugin_init(GKeyFile *config, const char *enable,
+							const char *disable);
 void plugin_cleanup(void);
 
 void rfkill_init(void);
diff --git a/src/main.c b/src/main.c
index 5460c32..adbb374 100644
--- a/src/main.c
+++ b/src/main.c
@@ -257,6 +257,8 @@
 }
 
 static gchar *option_debug = NULL;
+static gchar *option_plugin = NULL;
+static gchar *option_noplugin = NULL;
 static gboolean option_detach = TRUE;
 static gboolean option_version = FALSE;
 static gboolean option_udev = FALSE;
@@ -344,6 +346,10 @@
 	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
 				G_OPTION_ARG_CALLBACK, parse_debug,
 				"Specify debug options to enable", "DEBUG" },
+	{ "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin,
+				"Specify plugins to load", "NAME,..," },
+	{ "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin,
+				"Specify plugins not to load", "NAME,..." },
 	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
 				G_OPTION_ARG_NONE, &option_detach,
 				"Don't run as daemon in background" },
@@ -456,7 +462,7 @@
 	 * the plugins might wanna expose some paths on the bus. However the
 	 * best order of how to init various subsystems of the Bluetooth
 	 * daemon needs to be re-worked. */
-	plugin_init(config);
+	plugin_init(config, option_plugin, option_noplugin);
 
 	event_loop = g_main_loop_new(NULL, FALSE);
 
diff --git a/src/plugin.c b/src/plugin.c
index a63ce8e..3506553 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -82,41 +82,50 @@
 	return TRUE;
 }
 
-static gboolean is_disabled(const char *name, char **list)
+static gboolean enable_plugin(const char *name, char **conf_disable,
+					char **cli_enable, char **cli_disable)
 {
-	int i;
-
-	if (list == NULL)
-		return FALSE;
-
-	for (i = 0; list[i] != NULL; i++) {
-		char *str;
-		gboolean equal;
-
-		if (g_str_equal(name, list[i]))
-			return TRUE;
-
-		str = g_strdup_printf("%s.so", list[i]);
-
-		equal = g_str_equal(str, name);
-
-		g_free(str);
-
-		if (equal)
-			return TRUE;
+	if (conf_disable) {
+		for (; *conf_disable; conf_disable++)
+			if (g_pattern_match_simple(*conf_disable, name))
+				break;
+		if (*conf_disable) {
+			info("Excluding (conf) %s", name);
+			return FALSE;
+		}
 	}
 
-	return FALSE;
+	if (cli_disable) {
+		for (; *cli_disable; cli_disable++)
+			if (g_pattern_match_simple(*cli_disable, name))
+				break;
+		if (*cli_disable) {
+			info("Excluding (cli) %s", name);
+			return FALSE;
+		}
+	}
+
+	if (cli_enable) {
+		for (; *cli_enable; cli_enable++)
+			if (g_pattern_match_simple(*cli_enable, name))
+				break;
+		if (!*cli_enable) {
+			info("Ignoring (cli) %s", name);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
 }
 
 #include "builtin.h"
 
-gboolean plugin_init(GKeyFile *config)
+gboolean plugin_init(GKeyFile *config, const char *enable, const char *disable)
 {
 	GSList *list;
 	GDir *dir;
 	const gchar *file;
-	gchar **disabled;
+	char **conf_disabled, **cli_disabled, **cli_enabled;
 	unsigned int i;
 
 	/* Make a call to BtIO API so its symbols got resolved before the
@@ -124,33 +133,40 @@
 	bt_io_error_quark();
 
 	if (config)
-		disabled = g_key_file_get_string_list(config, "General",
+		conf_disabled = g_key_file_get_string_list(config, "General",
 							"DisablePlugins",
 							NULL, NULL);
 	else
-		disabled = NULL;
+		conf_disabled = NULL;
+
+	if (enable)
+		cli_enabled = g_strsplit_set(enable, ", ", -1);
+	else
+		cli_enabled = NULL;
+
+	if (disable)
+		cli_disabled = g_strsplit_set(disable, ", ", -1);
+	else
+		cli_disabled = NULL;
 
 	DBG("Loading builtin plugins");
 
 	for (i = 0; __bluetooth_builtin[i]; i++) {
-		if (is_disabled(__bluetooth_builtin[i]->name, disabled))
+		if (!enable_plugin(__bluetooth_builtin[i]->name, conf_disabled,
+						cli_enabled, cli_disabled))
 			continue;
 
 		add_plugin(NULL,  __bluetooth_builtin[i]);
 	}
 
-	if (strlen(PLUGINDIR) == 0) {
-		g_strfreev(disabled);
+	if (strlen(PLUGINDIR) == 0)
 		goto start;
-	}
 
 	DBG("Loading plugins %s", PLUGINDIR);
 
 	dir = g_dir_open(PLUGINDIR, 0, NULL);
-	if (!dir) {
-		g_strfreev(disabled);
+	if (!dir)
 		goto start;
-	}
 
 	while ((file = g_dir_read_name(dir)) != NULL) {
 		struct bluetooth_plugin_desc *desc;
@@ -161,9 +177,6 @@
 				g_str_has_suffix(file, ".so") == FALSE)
 			continue;
 
-		if (is_disabled(file, disabled))
-			continue;
-
 		filename = g_build_filename(PLUGINDIR, file, NULL);
 
 		handle = dlopen(filename, RTLD_NOW);
@@ -183,14 +196,18 @@
 			continue;
 		}
 
+		if (!enable_plugin(desc->name, conf_disabled,
+						cli_enabled, cli_disabled)) {
+			dlclose(handle);
+			continue;
+		}
+
 		if (add_plugin(handle, desc) == FALSE)
 			dlclose(handle);
 	}
 
 	g_dir_close(dir);
 
-	g_strfreev(disabled);
-
 start:
 	for (list = plugins; list; list = list->next) {
 		struct bluetooth_plugin *plugin = list->data;
@@ -203,6 +220,10 @@
 		plugin->active = TRUE;
 	}
 
+	g_strfreev(conf_disabled);
+	g_strfreev(cli_enabled);
+	g_strfreev(cli_disabled);
+
 	return TRUE;
 }