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