xref: /openbmc/qemu/util/module.c (revision d0bf492f)
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  *
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 "qemu/osdep.h"
17 #ifdef CONFIG_MODULES
18 #include <gmodule.h>
19 #endif
20 #include "qemu/queue.h"
21 #include "qemu/module.h"
22 #include "qemu/cutils.h"
23 #include "qemu/config-file.h"
24 #include "qapi/error.h"
25 #ifdef CONFIG_MODULE_UPGRADES
26 #include "qemu-version.h"
27 #endif
28 #include "trace.h"
29 
30 typedef struct ModuleEntry
31 {
32     void (*init)(void);
33     QTAILQ_ENTRY(ModuleEntry) node;
34     module_init_type type;
35 } ModuleEntry;
36 
37 typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
38 
39 static ModuleTypeList init_type_list[MODULE_INIT_MAX];
40 static bool modules_init_done[MODULE_INIT_MAX];
41 
42 static ModuleTypeList dso_init_list;
43 
44 static void init_lists(void)
45 {
46     static int inited;
47     int i;
48 
49     if (inited) {
50         return;
51     }
52 
53     for (i = 0; i < MODULE_INIT_MAX; i++) {
54         QTAILQ_INIT(&init_type_list[i]);
55     }
56 
57     QTAILQ_INIT(&dso_init_list);
58 
59     inited = 1;
60 }
61 
62 
63 static ModuleTypeList *find_type(module_init_type type)
64 {
65     init_lists();
66 
67     return &init_type_list[type];
68 }
69 
70 void register_module_init(void (*fn)(void), module_init_type type)
71 {
72     ModuleEntry *e;
73     ModuleTypeList *l;
74 
75     e = g_malloc0(sizeof(*e));
76     e->init = fn;
77     e->type = type;
78 
79     l = find_type(type);
80 
81     QTAILQ_INSERT_TAIL(l, e, node);
82 }
83 
84 void 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 
97 void module_call_init(module_init_type type)
98 {
99     ModuleTypeList *l;
100     ModuleEntry *e;
101 
102     if (modules_init_done[type]) {
103         return;
104     }
105 
106     l = find_type(type);
107 
108     QTAILQ_FOREACH(e, l, node) {
109         e->init();
110     }
111 
112     modules_init_done[type] = true;
113 }
114 
115 #ifdef CONFIG_MODULES
116 
117 static const QemuModinfo module_info_stub[] = { {
118     /* end of list */
119 } };
120 static const QemuModinfo *module_info = module_info_stub;
121 static const char *module_arch;
122 
123 void module_init_info(const QemuModinfo *info)
124 {
125     module_info = info;
126 }
127 
128 void module_allow_arch(const char *arch)
129 {
130     module_arch = arch;
131 }
132 
133 static 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 
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  */
157 static bool module_load_dso(const char *fname, bool export_symbols,
158                             Error **errp)
159 {
160     GModule *g_module;
161     void (*sym)(void);
162     ModuleEntry *e, *next;
163     int flags;
164 
165     assert(QTAILQ_EMPTY(&dso_init_list));
166 
167     flags = 0;
168     if (!export_symbols) {
169         flags |= G_MODULE_BIND_LOCAL;
170     }
171     g_module = g_module_open(fname, flags);
172     if (!g_module) {
173         error_setg(errp, "failed to open module: %s", g_module_error());
174         return false;
175     }
176     if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
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          */
182         if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
183             error_append_hint(errp,
184                 "Only modules from the same build can be loaded.\n");
185         }
186         g_module_close(g_module);
187         return false;
188     }
189 
190     QTAILQ_FOREACH(e, &dso_init_list, node) {
191         e->init();
192         register_module_init(e->init, e->type);
193     }
194     trace_module_load_module(fname);
195     QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
196         QTAILQ_REMOVE(&dso_init_list, e, node);
197         g_free(e);
198     }
199     return true;
200 }
201 
202 int module_load(const char *prefix, const char *name, Error **errp)
203 {
204     int rv = -1;
205 #ifdef CONFIG_MODULE_UPGRADES
206     char *version_dir;
207 #endif
208     const char *search_dir;
209     char *dirs[5];
210     char *module_name;
211     int i = 0, n_dirs = 0;
212     bool export_symbols = false;
213     static GHashTable *loaded_modules;
214     const QemuModinfo *modinfo;
215     const char **sl;
216 
217     if (!g_module_supported()) {
218         error_setg(errp, "%s", "this platform does not support GLib modules");
219         return -1;
220     }
221 
222     if (!loaded_modules) {
223         loaded_modules = g_hash_table_new(g_str_hash, g_str_equal);
224     }
225 
226     /* allocate all resources managed by the out: label here */
227     module_name = g_strdup_printf("%s%s", prefix, name);
228 
229     if (g_hash_table_contains(loaded_modules, module_name)) {
230         g_free(module_name);
231         return 2; /* module already loaded */
232     }
233     g_hash_table_add(loaded_modules, module_name);
234 
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 
251     for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
252         if (modinfo->arch) {
253             if (strcmp(modinfo->name, module_name) == 0) {
254                 if (!module_check_arch(modinfo)) {
255                     error_setg(errp, "module arch does not match: "
256                         "expected '%s', got '%s'", module_arch, modinfo->arch);
257                     goto out;
258                 }
259             }
260         }
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++) {
265                     int subrv = module_load("", *sl, errp);
266                     if (subrv <= 0) {
267                         rv = subrv;
268                         goto out;
269                     }
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 
282     for (i = 0; i < n_dirs; i++) {
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 */
300         }
301         g_free(fname);
302         goto out;
303     }
304     rv = 0; /* module not found */
305 
306 out:
307     if (rv <= 0) {
308         g_hash_table_remove(loaded_modules, module_name);
309         g_free(module_name);
310     }
311     for (i = 0; i < n_dirs; i++) {
312         g_free(dirs[i]);
313     }
314     return rv;
315 }
316 
317 static bool module_loaded_qom_all;
318 
319 int module_load_qom(const char *type, Error **errp)
320 {
321     const QemuModinfo *modinfo;
322     const char **sl;
323     int rv = 0;
324 
325     if (!type) {
326         error_setg(errp, "%s", "type is NULL");
327         return -1;
328     }
329 
330     trace_module_lookup_object_type(type);
331     for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
332         if (!modinfo->objs) {
333             continue;
334         }
335         if (!module_check_arch(modinfo)) {
336             continue;
337         }
338         for (sl = modinfo->objs; *sl != NULL; sl++) {
339             if (strcmp(type, *sl) == 0) {
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                 }
348             }
349         }
350     }
351     return rv;
352 }
353 
354 void module_load_qom_all(void)
355 {
356     const QemuModinfo *modinfo;
357     Error *local_err = NULL;
358 
359     if (module_loaded_qom_all) {
360         return;
361     }
362 
363     for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
364         if (!modinfo->objs) {
365             continue;
366         }
367         if (!module_check_arch(modinfo)) {
368             continue;
369         }
370         if (module_load("", modinfo->name, &local_err) < 0) {
371             error_report_err(local_err);
372         }
373     }
374     module_loaded_qom_all = true;
375 }
376 
377 void 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) {
388                 Error *local_err = NULL;
389                 if (module_load("", modinfo->name, &local_err) < 0) {
390                     error_report_err(local_err);
391                 }
392             }
393         }
394     }
395 }
396 
397 #else
398 
399 void module_allow_arch(const char *arch) {}
400 void qemu_load_module_for_opts(const char *group) {}
401 int module_load(const char *prefix, const char *name, Error **errp) { return 2; }
402 int module_load_qom(const char *type, Error **errp) { return 2; }
403 void module_load_qom_all(void) {}
404 
405 #endif
406