Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / obexd / src / plugin.c
1 /*
2  *
3  *  OBEX Server
4  *
5  *  Copyright (C) 2007-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 <glib.h>
34
35 #include "obexd.h"
36 #include "plugin.h"
37 #include "log.h"
38
39 /*
40  * Plugins that are using libraries with threads and their own mainloop
41  * will crash on exit. This is a bug inside these libraries, but there is
42  * nothing much that can be done about it. One bad example is libebook.
43  */
44 #ifdef NEED_THREADS
45 #define PLUGINFLAG (RTLD_NOW | RTLD_NODELETE)
46 #else
47 #define PLUGINFLAG (RTLD_NOW)
48 #endif
49
50 static GSList *plugins = NULL;
51
52 struct obex_plugin {
53         void *handle;
54         struct obex_plugin_desc *desc;
55 };
56
57 static gboolean add_plugin(void *handle, struct obex_plugin_desc *desc)
58 {
59         struct obex_plugin *plugin;
60
61         if (desc->init == NULL)
62                 return FALSE;
63
64         plugin = g_try_new0(struct obex_plugin, 1);
65         if (plugin == NULL)
66                 return FALSE;
67
68         plugin->handle = handle;
69         plugin->desc = desc;
70
71         if (desc->init() < 0) {
72                 g_free(plugin);
73                 return FALSE;
74         }
75
76         plugins = g_slist_append(plugins, plugin);
77         DBG("Plugin %s loaded", desc->name);
78
79         return TRUE;
80 }
81
82 static gboolean check_plugin(struct obex_plugin_desc *desc,
83                                 char **patterns, char **excludes)
84 {
85         if (excludes) {
86                 for (; *excludes; excludes++)
87                         if (g_pattern_match_simple(*excludes, desc->name))
88                                 break;
89                 if (*excludes) {
90                         info("Excluding %s", desc->name);
91                         return FALSE;
92                 }
93         }
94
95         if (patterns) {
96                 for (; *patterns; patterns++)
97                         if (g_pattern_match_simple(*patterns, desc->name))
98                                 break;
99                 if (*patterns == NULL) {
100                         info("Ignoring %s", desc->name);
101                         return FALSE;
102                 }
103         }
104
105         return TRUE;
106 }
107
108
109 #include "builtin.h"
110
111 gboolean plugin_init(const char *pattern, const char *exclude)
112 {
113         char **patterns = NULL;
114         char **excludes = NULL;
115         GDir *dir;
116         const char *file;
117         unsigned int i;
118
119         if (strlen(PLUGINDIR) == 0)
120                 return FALSE;
121
122         if (pattern)
123                 patterns = g_strsplit_set(pattern, ":, ", -1);
124
125         if (exclude)
126                 excludes = g_strsplit_set(exclude, ":, ", -1);
127
128         DBG("Loading builtin plugins");
129
130         for (i = 0; __obex_builtin[i]; i++) {
131                 if (check_plugin(__obex_builtin[i],
132                                         patterns, excludes) == FALSE)
133                         continue;
134
135                 add_plugin(NULL,  __obex_builtin[i]);
136         }
137
138         DBG("Loading plugins %s", PLUGINDIR);
139
140         dir = g_dir_open(PLUGINDIR, 0, NULL);
141         if (!dir)
142                 return FALSE;
143
144         while ((file = g_dir_read_name(dir)) != NULL) {
145                 struct obex_plugin_desc *desc;
146                 void *handle;
147                 char *filename;
148
149                 if (g_str_has_prefix(file, "lib") == TRUE ||
150                                 g_str_has_suffix(file, ".so") == FALSE)
151                         continue;
152
153                 filename = g_build_filename(PLUGINDIR, file, NULL);
154
155                 handle = dlopen(filename, PLUGINFLAG);
156                 if (handle == NULL) {
157                         error("Can't load plugin %s: %s", filename,
158                                                                 dlerror());
159                         g_free(filename);
160                         continue;
161                 }
162
163                 g_free(filename);
164
165                 desc = dlsym(handle, "obex_plugin_desc");
166                 if (desc == NULL) {
167                         error("Can't load plugin description: %s", dlerror());
168                         dlclose(handle);
169                         continue;
170                 }
171
172                 if (check_plugin(desc, patterns, excludes) == FALSE) {
173                         dlclose(handle);
174                         continue;
175                 }
176
177                 if (add_plugin(handle, desc) == FALSE)
178                         dlclose(handle);
179         }
180
181         g_dir_close(dir);
182         g_strfreev(patterns);
183         g_strfreev(excludes);
184
185         return TRUE;
186 }
187
188 void plugin_cleanup(void)
189 {
190         GSList *list;
191
192         DBG("Cleanup plugins");
193
194         for (list = plugins; list; list = list->next) {
195                 struct obex_plugin *plugin = list->data;
196
197                 if (plugin->desc->exit)
198                         plugin->desc->exit();
199
200                 if (plugin->handle != NULL)
201                         dlclose(plugin->handle);
202
203                 g_free(plugin);
204         }
205
206         g_slist_free(plugins);
207 }