]> Git Repo - qemu.git/blob - util/module.c
Merge remote-tracking branch 'remotes/xtensa/tags/20140224-xtensa' into staging
[qemu.git] / util / module.c
1 /*
2  * QEMU Module Infrastructure
3  *
4  * Copyright IBM, Corp. 2009
5  *
6  * Authors:
7  *  Anthony Liguori   <[email protected]>
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  *
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.
14  */
15
16 #include <stdlib.h>
17 #include <gmodule.h>
18 #include "qemu-common.h"
19 #include "qemu/queue.h"
20 #include "qemu/module.h"
21
22 typedef struct ModuleEntry
23 {
24     void (*init)(void);
25     QTAILQ_ENTRY(ModuleEntry) node;
26     module_init_type type;
27 } ModuleEntry;
28
29 typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
30
31 static ModuleTypeList init_type_list[MODULE_INIT_MAX];
32
33 static ModuleTypeList dso_init_list;
34
35 static void init_lists(void)
36 {
37     static int inited;
38     int i;
39
40     if (inited) {
41         return;
42     }
43
44     for (i = 0; i < MODULE_INIT_MAX; i++) {
45         QTAILQ_INIT(&init_type_list[i]);
46     }
47
48     QTAILQ_INIT(&dso_init_list);
49
50     inited = 1;
51 }
52
53
54 static ModuleTypeList *find_type(module_init_type type)
55 {
56     ModuleTypeList *l;
57
58     init_lists();
59
60     l = &init_type_list[type];
61
62     return l;
63 }
64
65 void register_module_init(void (*fn)(void), module_init_type type)
66 {
67     ModuleEntry *e;
68     ModuleTypeList *l;
69
70     e = g_malloc0(sizeof(*e));
71     e->init = fn;
72     e->type = type;
73
74     l = find_type(type);
75
76     QTAILQ_INSERT_TAIL(l, e, node);
77 }
78
79 void register_dso_module_init(void (*fn)(void), module_init_type type)
80 {
81     ModuleEntry *e;
82
83     init_lists();
84
85     e = g_malloc0(sizeof(*e));
86     e->init = fn;
87     e->type = type;
88
89     QTAILQ_INSERT_TAIL(&dso_init_list, e, node);
90 }
91
92 static void module_load(module_init_type type);
93
94 void module_call_init(module_init_type type)
95 {
96     ModuleTypeList *l;
97     ModuleEntry *e;
98
99     module_load(type);
100     l = find_type(type);
101
102     QTAILQ_FOREACH(e, l, node) {
103         e->init();
104     }
105 }
106
107 #ifdef CONFIG_MODULES
108 static int module_load_file(const char *fname)
109 {
110     GModule *g_module;
111     void (*sym)(void);
112     const char *dsosuf = HOST_DSOSUF;
113     int len = strlen(fname);
114     int suf_len = strlen(dsosuf);
115     ModuleEntry *e, *next;
116     int ret;
117
118     if (len <= suf_len || strcmp(&fname[len - suf_len], dsosuf)) {
119         /* wrong suffix */
120         ret = -EINVAL;
121         goto out;
122     }
123     if (access(fname, F_OK)) {
124         ret = -ENOENT;
125         goto out;
126     }
127
128     assert(QTAILQ_EMPTY(&dso_init_list));
129
130     g_module = g_module_open(fname, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
131     if (!g_module) {
132         fprintf(stderr, "Failed to open module: %s\n",
133                 g_module_error());
134         ret = -EINVAL;
135         goto out;
136     }
137     if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
138         fprintf(stderr, "Failed to initialize module: %s\n",
139                 fname);
140         /* Print some info if this is a QEMU module (but from different build),
141          * this will make debugging user problems easier. */
142         if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
143             fprintf(stderr,
144                     "Note: only modules from the same build can be loaded.\n");
145         }
146         g_module_close(g_module);
147         ret = -EINVAL;
148     } else {
149         QTAILQ_FOREACH(e, &dso_init_list, node) {
150             register_module_init(e->init, e->type);
151         }
152         ret = 0;
153     }
154
155     QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
156         QTAILQ_REMOVE(&dso_init_list, e, node);
157         g_free(e);
158     }
159 out:
160     return ret;
161 }
162 #endif
163
164 void module_load(module_init_type type)
165 {
166 #ifdef CONFIG_MODULES
167     char *fname = NULL;
168     const char **mp;
169     static const char *block_modules[] = {
170         CONFIG_BLOCK_MODULES
171     };
172     char *exec_dir;
173     char *dirs[3];
174     int i = 0;
175     int ret;
176
177     if (!g_module_supported()) {
178         fprintf(stderr, "Module is not supported by system.\n");
179         return;
180     }
181
182     switch (type) {
183     case MODULE_INIT_BLOCK:
184         mp = block_modules;
185         break;
186     default:
187         /* no other types have dynamic modules for now*/
188         return;
189     }
190
191     exec_dir = qemu_get_exec_dir();
192     dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR);
193     dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : "");
194     dirs[i++] = g_strdup_printf("%s", exec_dir ? : "");
195     assert(i == ARRAY_SIZE(dirs));
196     g_free(exec_dir);
197     exec_dir = NULL;
198
199     for ( ; *mp; mp++) {
200         for (i = 0; i < ARRAY_SIZE(dirs); i++) {
201             fname = g_strdup_printf("%s/%s%s", dirs[i], *mp, HOST_DSOSUF);
202             ret = module_load_file(fname);
203             /* Try loading until loaded a module file */
204             if (!ret) {
205                 break;
206             }
207             g_free(fname);
208             fname = NULL;
209         }
210         if (ret == -ENOENT) {
211             fprintf(stderr, "Can't find module: %s\n", *mp);
212         }
213
214         g_free(fname);
215     }
216
217     for (i = 0; i < ARRAY_SIZE(dirs); i++) {
218         g_free(dirs[i]);
219     }
220
221 #endif
222 }
This page took 0.033353 seconds and 4 git commands to generate.