Home | History | Annotate | Download | only in src
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel (at) 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 
     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 
     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 
     85 static gboolean is_disabled(const char *name, char **list)
     86 {
     87 	int i;
     88 
     89 	if (list == NULL)
     90 		return FALSE;
     91 
     92 	for (i = 0; list[i] != NULL; i++) {
     93 		char *str;
     94 		gboolean equal;
     95 
     96 		if (g_str_equal(name, list[i]))
     97 			return TRUE;
     98 
     99 		str = g_strdup_printf("%s.so", list[i]);
    100 
    101 		equal = g_str_equal(str, name);
    102 
    103 		g_free(str);
    104 
    105 		if (equal)
    106 			return TRUE;
    107 	}
    108 
    109 	return FALSE;
    110 }
    111 
    112 #include "builtin.h"
    113 
    114 gboolean plugin_init(GKeyFile *config)
    115 {
    116 	GSList *list;
    117 	GDir *dir;
    118 	const gchar *file;
    119 	gchar **disabled;
    120 	unsigned int i;
    121 
    122 	/* Make a call to BtIO API so its symbols got resolved before the
    123 	 * plugins are loaded. */
    124 	bt_io_error_quark();
    125 
    126 	if (config)
    127 		disabled = g_key_file_get_string_list(config, "General",
    128 							"DisablePlugins",
    129 							NULL, NULL);
    130 	else
    131 		disabled = NULL;
    132 
    133 	DBG("Loading builtin plugins");
    134 
    135 	for (i = 0; __bluetooth_builtin[i]; i++) {
    136 		if (is_disabled(__bluetooth_builtin[i]->name, disabled))
    137 			continue;
    138 
    139 		add_plugin(NULL,  __bluetooth_builtin[i]);
    140 	}
    141 
    142 	if (strlen(PLUGINDIR) == 0) {
    143 		g_strfreev(disabled);
    144 		goto start;
    145 	}
    146 
    147 	DBG("Loading plugins %s", PLUGINDIR);
    148 
    149 	dir = g_dir_open(PLUGINDIR, 0, NULL);
    150 	if (!dir) {
    151 		g_strfreev(disabled);
    152 		goto start;
    153 	}
    154 
    155 	while ((file = g_dir_read_name(dir)) != NULL) {
    156 		struct bluetooth_plugin_desc *desc;
    157 		void *handle;
    158 		gchar *filename;
    159 
    160 		if (g_str_has_prefix(file, "lib") == TRUE ||
    161 				g_str_has_suffix(file, ".so") == FALSE)
    162 			continue;
    163 
    164 		if (is_disabled(file, disabled))
    165 			continue;
    166 
    167 		filename = g_build_filename(PLUGINDIR, file, NULL);
    168 
    169 		handle = dlopen(filename, RTLD_NOW);
    170 		if (handle == NULL) {
    171 			error("Can't load plugin %s: %s", filename,
    172 								dlerror());
    173 			g_free(filename);
    174 			continue;
    175 		}
    176 
    177 		g_free(filename);
    178 
    179 		desc = dlsym(handle, "bluetooth_plugin_desc");
    180 		if (desc == NULL) {
    181 			error("Can't load plugin description: %s", dlerror());
    182 			dlclose(handle);
    183 			continue;
    184 		}
    185 
    186 		if (add_plugin(handle, desc) == FALSE)
    187 			dlclose(handle);
    188 	}
    189 
    190 	g_dir_close(dir);
    191 
    192 	g_strfreev(disabled);
    193 
    194 start:
    195 	for (list = plugins; list; list = list->next) {
    196 		struct bluetooth_plugin *plugin = list->data;
    197 
    198 		if (plugin->desc->init() < 0) {
    199 			error("Failed to init %s plugin", plugin->desc->name);
    200 			continue;
    201 		}
    202 
    203 		plugin->active = TRUE;
    204 	}
    205 
    206 	return TRUE;
    207 }
    208 
    209 void plugin_cleanup(void)
    210 {
    211 	GSList *list;
    212 
    213 	DBG("Cleanup plugins");
    214 
    215 	for (list = plugins; list; list = list->next) {
    216 		struct bluetooth_plugin *plugin = list->data;
    217 
    218 		if (plugin->active == TRUE && plugin->desc->exit)
    219 			plugin->desc->exit();
    220 
    221 		if (plugin->handle != NULL)
    222 			dlclose(plugin->handle);
    223 
    224 		g_free(plugin);
    225 	}
    226 
    227 	g_slist_free(plugins);
    228 }
    229