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