]> git.proxmox.com Git - mirror_qemu.git/blame - util/module.c
util/uri: Remove the uri_string_escape() function
[mirror_qemu.git] / util / module.c
CommitLineData
0bfe3ca5
AL
1/*
2 * QEMU Module Infrastructure
3 *
4 * Copyright IBM, Corp. 2009
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
11 *
6b620ca3
PB
12 * Contributions after 2012-01-13 are licensed under the terms of the
13 * GNU GPL, version 2 or (at your option) any later version.
0bfe3ca5
AL
14 */
15
aafd7584 16#include "qemu/osdep.h"
aa0d1f44 17#ifdef CONFIG_MODULES
e26110cf 18#include <gmodule.h>
aa0d1f44 19#endif
1de7afc9
PB
20#include "qemu/queue.h"
21#include "qemu/module.h"
1b934064 22#include "qemu/cutils.h"
5111edaf 23#include "qemu/config-file.h"
c551fb0b 24#include "qapi/error.h"
bd83c861
CE
25#ifdef CONFIG_MODULE_UPGRADES
26#include "qemu-version.h"
27#endif
819b8b13 28#include "trace.h"
0bfe3ca5
AL
29
30typedef struct ModuleEntry
31{
0bfe3ca5 32 void (*init)(void);
72cf2d4f 33 QTAILQ_ENTRY(ModuleEntry) node;
e26110cf 34 module_init_type type;
0bfe3ca5
AL
35} ModuleEntry;
36
72cf2d4f 37typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
0bfe3ca5 38
f7897430 39static ModuleTypeList init_type_list[MODULE_INIT_MAX];
46a07579 40static bool modules_init_done[MODULE_INIT_MAX];
0bfe3ca5 41
e26110cf
FZ
42static ModuleTypeList dso_init_list;
43
44static void init_lists(void)
0bfe3ca5 45{
f7897430
AL
46 static int inited;
47 int i;
0bfe3ca5 48
f7897430
AL
49 if (inited) {
50 return;
0bfe3ca5
AL
51 }
52
f7897430 53 for (i = 0; i < MODULE_INIT_MAX; i++) {
72cf2d4f 54 QTAILQ_INIT(&init_type_list[i]);
f7897430 55 }
0bfe3ca5 56
e26110cf
FZ
57 QTAILQ_INIT(&dso_init_list);
58
f7897430
AL
59 inited = 1;
60}
0bfe3ca5 61
0bfe3ca5 62
f7897430
AL
63static ModuleTypeList *find_type(module_init_type type)
64{
e26110cf 65 init_lists();
f7897430 66
9be38598 67 return &init_type_list[type];
0bfe3ca5
AL
68}
69
70void register_module_init(void (*fn)(void), module_init_type type)
71{
72 ModuleEntry *e;
73 ModuleTypeList *l;
74
7267c094 75 e = g_malloc0(sizeof(*e));
0bfe3ca5 76 e->init = fn;
e26110cf 77 e->type = type;
0bfe3ca5 78
f7897430 79 l = find_type(type);
0bfe3ca5 80
72cf2d4f 81 QTAILQ_INSERT_TAIL(l, e, node);
0bfe3ca5
AL
82}
83
e26110cf
FZ
84void register_dso_module_init(void (*fn)(void), module_init_type type)
85{
86 ModuleEntry *e;
87
88 init_lists();
89
90 e = g_malloc0(sizeof(*e));
91 e->init = fn;
92 e->type = type;
93
94 QTAILQ_INSERT_TAIL(&dso_init_list, e, node);
95}
96
0bfe3ca5
AL
97void module_call_init(module_init_type type)
98{
99 ModuleTypeList *l;
100 ModuleEntry *e;
101
46a07579
AB
102 if (modules_init_done[type]) {
103 return;
104 }
105
f7897430 106 l = find_type(type);
0bfe3ca5 107
72cf2d4f 108 QTAILQ_FOREACH(e, l, node) {
0bfe3ca5
AL
109 e->init();
110 }
46a07579
AB
111
112 modules_init_done[type] = true;
0bfe3ca5 113}
e26110cf
FZ
114
115#ifdef CONFIG_MODULES
5ebbfecc
GH
116
117static const QemuModinfo module_info_stub[] = { {
118 /* end of list */
119} };
120static const QemuModinfo *module_info = module_info_stub;
d7795d3c 121static const char *module_arch;
5ebbfecc
GH
122
123void module_init_info(const QemuModinfo *info)
124{
125 module_info = info;
126}
127
d7795d3c
GH
128void module_allow_arch(const char *arch)
129{
130 module_arch = arch;
131}
132
133static bool module_check_arch(const QemuModinfo *modinfo)
134{
135 if (modinfo->arch) {
136 if (!module_arch) {
137 /* no arch set -> ignore all */
138 return false;
139 }
140 if (strcmp(module_arch, modinfo->arch) != 0) {
141 /* mismatch */
142 return false;
143 }
144 }
145 return true;
146}
147
c551fb0b
CF
148/*
149 * module_load_dso: attempt to load an existing dso file
150 *
151 * fname: full pathname of the file to load
152 * export_symbols: if true, add the symbols to the global name space
153 * errp: error to set.
154 *
155 * Return value: true on success, false on error, and errp will be set.
156 */
157static bool module_load_dso(const char *fname, bool export_symbols,
158 Error **errp)
e26110cf
FZ
159{
160 GModule *g_module;
161 void (*sym)(void);
e26110cf 162 ModuleEntry *e, *next;
c551fb0b 163 int flags;
e26110cf
FZ
164
165 assert(QTAILQ_EMPTY(&dso_init_list));
166
546323bd 167 flags = 0;
6f13fa7a
GH
168 if (!export_symbols) {
169 flags |= G_MODULE_BIND_LOCAL;
170 }
171 g_module = g_module_open(fname, flags);
e26110cf 172 if (!g_module) {
c551fb0b
CF
173 error_setg(errp, "failed to open module: %s", g_module_error());
174 return false;
e26110cf
FZ
175 }
176 if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
c551fb0b
CF
177 error_setg(errp, "failed to initialize module: %s", fname);
178 /*
179 * Print some info if this is a QEMU module (but from different build),
180 * this will make debugging user problems easier.
181 */
e26110cf 182 if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
c551fb0b
CF
183 error_append_hint(errp,
184 "Only modules from the same build can be loaded.\n");
e26110cf
FZ
185 }
186 g_module_close(g_module);
c551fb0b 187 return false;
e26110cf
FZ
188 }
189
c551fb0b
CF
190 QTAILQ_FOREACH(e, &dso_init_list, node) {
191 e->init();
192 register_module_init(e->init, e->type);
193 }
819b8b13 194 trace_module_load_module(fname);
e26110cf
FZ
195 QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
196 QTAILQ_REMOVE(&dso_init_list, e, node);
197 g_free(e);
198 }
c551fb0b 199 return true;
e26110cf 200}
e26110cf 201
c551fb0b 202int module_load(const char *prefix, const char *name, Error **errp)
e26110cf 203{
c551fb0b 204 int rv = -1;
bd83c861
CE
205#ifdef CONFIG_MODULE_UPGRADES
206 char *version_dir;
207#endif
900610e6 208 const char *search_dir;
267514b3 209 char *dirs[5];
dffa41b4 210 char *module_name;
900610e6 211 int i = 0, n_dirs = 0;
6f13fa7a 212 bool export_symbols = false;
dffa41b4 213 static GHashTable *loaded_modules;
e897b9a7
GH
214 const QemuModinfo *modinfo;
215 const char **sl;
e26110cf
FZ
216
217 if (!g_module_supported()) {
c551fb0b
CF
218 error_setg(errp, "%s", "this platform does not support GLib modules");
219 return -1;
e26110cf
FZ
220 }
221
dffa41b4
FZ
222 if (!loaded_modules) {
223 loaded_modules = g_hash_table_new(g_str_hash, g_str_equal);
224 }
225
c551fb0b
CF
226 /* allocate all resources managed by the out: label here */
227 module_name = g_strdup_printf("%s%s", prefix, name);
dffa41b4 228
64e16fbb 229 if (g_hash_table_contains(loaded_modules, module_name)) {
dffa41b4 230 g_free(module_name);
c551fb0b 231 return 2; /* module already loaded */
dffa41b4 232 }
64e16fbb 233 g_hash_table_add(loaded_modules, module_name);
dffa41b4 234
c551fb0b
CF
235 search_dir = getenv("QEMU_MODULE_DIR");
236 if (search_dir != NULL) {
237 dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
238 }
239 dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
240
241#ifdef CONFIG_MODULE_UPGRADES
242 version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
243 G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
244 '_');
245 dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
246#endif
247 assert(n_dirs <= ARRAY_SIZE(dirs));
248
249 /* end of resources managed by the out: label */
250
e897b9a7 251 for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
d7795d3c
GH
252 if (modinfo->arch) {
253 if (strcmp(modinfo->name, module_name) == 0) {
254 if (!module_check_arch(modinfo)) {
c551fb0b
CF
255 error_setg(errp, "module arch does not match: "
256 "expected '%s', got '%s'", module_arch, modinfo->arch);
257 goto out;
d7795d3c
GH
258 }
259 }
260 }
e897b9a7
GH
261 if (modinfo->deps) {
262 if (strcmp(modinfo->name, module_name) == 0) {
263 /* we depend on other module(s) */
264 for (sl = modinfo->deps; *sl != NULL; sl++) {
c551fb0b
CF
265 int subrv = module_load("", *sl, errp);
266 if (subrv <= 0) {
267 rv = subrv;
268 goto out;
269 }
e897b9a7
GH
270 }
271 } else {
272 for (sl = modinfo->deps; *sl != NULL; sl++) {
273 if (strcmp(module_name, *sl) == 0) {
274 /* another module depends on us */
275 export_symbols = true;
276 }
277 }
278 }
279 }
280 }
281
900610e6 282 for (i = 0; i < n_dirs; i++) {
c551fb0b
CF
283 char *fname = g_strdup_printf("%s/%s%s",
284 dirs[i], module_name, CONFIG_HOST_DSOSUF);
285 int ret = access(fname, F_OK);
286 if (ret != 0 && (errno == ENOENT || errno == ENOTDIR)) {
287 /*
288 * if we don't find the module in this dir, try the next one.
289 * If we don't find it in any dir, that can be fine too: user
290 * did not install the module. We will return 0 in this case
291 * with no error set.
292 */
293 g_free(fname);
294 continue;
295 } else if (ret != 0) {
296 /* most common is EACCES here */
297 error_setg_errno(errp, errno, "error trying to access %s", fname);
298 } else if (module_load_dso(fname, export_symbols, errp)) {
299 rv = 1; /* module successfully loaded */
e26110cf 300 }
c551fb0b
CF
301 g_free(fname);
302 goto out;
e26110cf 303 }
c551fb0b 304 rv = 0; /* module not found */
e26110cf 305
c551fb0b
CF
306out:
307 if (rv <= 0) {
81d8ccb1 308 g_hash_table_remove(loaded_modules, module_name);
638be478 309 g_free(module_name);
81d8ccb1 310 }
900610e6 311 for (i = 0; i < n_dirs; i++) {
e26110cf
FZ
312 g_free(dirs[i]);
313 }
c551fb0b 314 return rv;
e26110cf 315}
28457744 316
28457744
GH
317static bool module_loaded_qom_all;
318
c551fb0b 319int module_load_qom(const char *type, Error **errp)
28457744 320{
9f4a0f09
GH
321 const QemuModinfo *modinfo;
322 const char **sl;
c551fb0b 323 int rv = 0;
28457744 324
d87350b0 325 if (!type) {
c551fb0b
CF
326 error_setg(errp, "%s", "type is NULL");
327 return -1;
d87350b0 328 }
9f4a0f09 329
819b8b13 330 trace_module_lookup_object_type(type);
9f4a0f09
GH
331 for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
332 if (!modinfo->objs) {
333 continue;
334 }
ab0cfc3d
GH
335 if (!module_check_arch(modinfo)) {
336 continue;
337 }
9f4a0f09
GH
338 for (sl = modinfo->objs; *sl != NULL; sl++) {
339 if (strcmp(type, *sl) == 0) {
c551fb0b
CF
340 if (rv > 0) {
341 error_setg(errp, "multiple modules providing '%s'", type);
342 return -1;
343 }
344 rv = module_load("", modinfo->name, errp);
345 if (rv < 0) {
346 return rv;
347 }
9f4a0f09 348 }
28457744
GH
349 }
350 }
c551fb0b 351 return rv;
28457744
GH
352}
353
354void module_load_qom_all(void)
355{
9f4a0f09 356 const QemuModinfo *modinfo;
c551fb0b 357 Error *local_err = NULL;
28457744
GH
358
359 if (module_loaded_qom_all) {
360 return;
361 }
9f4a0f09
GH
362
363 for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
364 if (!modinfo->objs) {
28457744
GH
365 continue;
366 }
ab0cfc3d
GH
367 if (!module_check_arch(modinfo)) {
368 continue;
369 }
c551fb0b
CF
370 if (module_load("", modinfo->name, &local_err) < 0) {
371 error_report_err(local_err);
372 }
28457744
GH
373 }
374 module_loaded_qom_all = true;
375}
9f4a0f09 376
5111edaf
GH
377void qemu_load_module_for_opts(const char *group)
378{
379 const QemuModinfo *modinfo;
380 const char **sl;
381
382 for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
383 if (!modinfo->opts) {
384 continue;
385 }
386 for (sl = modinfo->opts; *sl != NULL; sl++) {
387 if (strcmp(group, *sl) == 0) {
c551fb0b
CF
388 Error *local_err = NULL;
389 if (module_load("", modinfo->name, &local_err) < 0) {
390 error_report_err(local_err);
391 }
5111edaf
GH
392 }
393 }
394 }
395}
396
9f4a0f09
GH
397#else
398
d7795d3c 399void module_allow_arch(const char *arch) {}
5111edaf 400void qemu_load_module_for_opts(const char *group) {}
c551fb0b
CF
401int module_load(const char *prefix, const char *name, Error **errp) { return 2; }
402int module_load_qom(const char *type, Error **errp) { return 2; }
9f4a0f09
GH
403void module_load_qom_all(void) {}
404
405#endif