• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <errno.h>
29 #include <dlfcn.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 
33 #include <bluetooth/bluetooth.h>
34 
35 #include <glib.h>
36 
37 #include "plugin.h"
38 #include "log.h"
39 #include "hcid.h"
40 #include "btio.h"
41 
42 static GSList *plugins = NULL;
43 
44 struct bluetooth_plugin {
45 	void *handle;
46 	gboolean active;
47 	struct bluetooth_plugin_desc *desc;
48 };
49 
compare_priority(gconstpointer a,gconstpointer b)50 static gint compare_priority(gconstpointer a, gconstpointer b)
51 {
52 	const struct bluetooth_plugin *plugin1 = a;
53 	const struct bluetooth_plugin *plugin2 = b;
54 
55 	return plugin2->desc->priority - plugin1->desc->priority;
56 }
57 
add_plugin(void * handle,struct bluetooth_plugin_desc * desc)58 static gboolean add_plugin(void *handle, struct bluetooth_plugin_desc *desc)
59 {
60 	struct bluetooth_plugin *plugin;
61 
62 	if (desc->init == NULL)
63 		return FALSE;
64 
65 	if (g_str_equal(desc->version, VERSION) == FALSE) {
66 		error("Version mismatch for %s", desc->name);
67 		return FALSE;
68 	}
69 
70 	DBG("Loading %s plugin", desc->name);
71 
72 	plugin = g_try_new0(struct bluetooth_plugin, 1);
73 	if (plugin == NULL)
74 		return FALSE;
75 
76 	plugin->handle = handle;
77 	plugin->active = FALSE;
78 	plugin->desc = desc;
79 
80 	plugins = g_slist_insert_sorted(plugins, plugin, compare_priority);
81 
82 	return TRUE;
83 }
84 
enable_plugin(const char * name,char ** conf_disable,char ** cli_enable,char ** cli_disable)85 static gboolean enable_plugin(const char *name, char **conf_disable,
86 					char **cli_enable, char **cli_disable)
87 {
88 	if (conf_disable) {
89 		for (; *conf_disable; conf_disable++)
90 			if (g_pattern_match_simple(*conf_disable, name))
91 				break;
92 		if (*conf_disable) {
93 			info("Excluding (conf) %s", name);
94 			return FALSE;
95 		}
96 	}
97 
98 	if (cli_disable) {
99 		for (; *cli_disable; cli_disable++)
100 			if (g_pattern_match_simple(*cli_disable, name))
101 				break;
102 		if (*cli_disable) {
103 			info("Excluding (cli) %s", name);
104 			return FALSE;
105 		}
106 	}
107 
108 	if (cli_enable) {
109 		for (; *cli_enable; cli_enable++)
110 			if (g_pattern_match_simple(*cli_enable, name))
111 				break;
112 		if (!*cli_enable) {
113 			info("Ignoring (cli) %s", name);
114 			return FALSE;
115 		}
116 	}
117 
118 	return TRUE;
119 }
120 
121 #include "builtin.h"
122 
plugin_init(GKeyFile * config,const char * enable,const char * disable)123 gboolean plugin_init(GKeyFile *config, const char *enable, const char *disable)
124 {
125 	GSList *list;
126 	GDir *dir;
127 	const gchar *file;
128 	char **conf_disabled, **cli_disabled, **cli_enabled;
129 	unsigned int i;
130 
131 	/* Make a call to BtIO API so its symbols got resolved before the
132 	 * plugins are loaded. */
133 	bt_io_error_quark();
134 
135 	if (config)
136 		conf_disabled = g_key_file_get_string_list(config, "General",
137 							"DisablePlugins",
138 							NULL, NULL);
139 	else
140 		conf_disabled = NULL;
141 
142 	if (enable)
143 		cli_enabled = g_strsplit_set(enable, ", ", -1);
144 	else
145 		cli_enabled = NULL;
146 
147 	if (disable)
148 		cli_disabled = g_strsplit_set(disable, ", ", -1);
149 	else
150 		cli_disabled = NULL;
151 
152 	DBG("Loading builtin plugins");
153 
154 	for (i = 0; __bluetooth_builtin[i]; i++) {
155 		if (!enable_plugin(__bluetooth_builtin[i]->name, conf_disabled,
156 						cli_enabled, cli_disabled))
157 			continue;
158 
159 		add_plugin(NULL,  __bluetooth_builtin[i]);
160 	}
161 
162 	if (strlen(PLUGINDIR) == 0)
163 		goto start;
164 
165 	DBG("Loading plugins %s", PLUGINDIR);
166 
167 	dir = g_dir_open(PLUGINDIR, 0, NULL);
168 	if (!dir)
169 		goto start;
170 
171 	while ((file = g_dir_read_name(dir)) != NULL) {
172 		struct bluetooth_plugin_desc *desc;
173 		void *handle;
174 		gchar *filename;
175 
176 		if (g_str_has_prefix(file, "lib") == TRUE ||
177 				g_str_has_suffix(file, ".so") == FALSE)
178 			continue;
179 
180 		filename = g_build_filename(PLUGINDIR, file, NULL);
181 
182 		handle = dlopen(filename, RTLD_NOW);
183 		if (handle == NULL) {
184 			error("Can't load plugin %s: %s", filename,
185 								dlerror());
186 			g_free(filename);
187 			continue;
188 		}
189 
190 		g_free(filename);
191 
192 		desc = dlsym(handle, "bluetooth_plugin_desc");
193 		if (desc == NULL) {
194 			error("Can't load plugin description: %s", dlerror());
195 			dlclose(handle);
196 			continue;
197 		}
198 
199 		if (!enable_plugin(desc->name, conf_disabled,
200 						cli_enabled, cli_disabled)) {
201 			dlclose(handle);
202 			continue;
203 		}
204 
205 		if (add_plugin(handle, desc) == FALSE)
206 			dlclose(handle);
207 	}
208 
209 	g_dir_close(dir);
210 
211 start:
212 	for (list = plugins; list; list = list->next) {
213 		struct bluetooth_plugin *plugin = list->data;
214 
215 		if (plugin->desc->init() < 0) {
216 			error("Failed to init %s plugin", plugin->desc->name);
217 			continue;
218 		}
219 
220 		plugin->active = TRUE;
221 	}
222 
223 	g_strfreev(conf_disabled);
224 	g_strfreev(cli_enabled);
225 	g_strfreev(cli_disabled);
226 
227 	return TRUE;
228 }
229 
plugin_cleanup(void)230 void plugin_cleanup(void)
231 {
232 	GSList *list;
233 
234 	DBG("Cleanup plugins");
235 
236 	for (list = plugins; list; list = list->next) {
237 		struct bluetooth_plugin *plugin = list->data;
238 
239 		if (plugin->active == TRUE && plugin->desc->exit)
240 			plugin->desc->exit();
241 
242 		if (plugin->handle != NULL)
243 			dlclose(plugin->handle);
244 
245 		g_free(plugin);
246 	}
247 
248 	g_slist_free(plugins);
249 }
250