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