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