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#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#ifdef CONFIG_MODULE_UPGRADES
  25#include "qemu-version.h"
  26#endif
  27#include "trace.h"
  28
  29typedef struct ModuleEntry
  30{
  31    void (*init)(void);
  32    QTAILQ_ENTRY(ModuleEntry) node;
  33    module_init_type type;
  34} ModuleEntry;
  35
  36typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
  37
  38static ModuleTypeList init_type_list[MODULE_INIT_MAX];
  39static bool modules_init_done[MODULE_INIT_MAX];
  40
  41static ModuleTypeList dso_init_list;
  42
  43static void init_lists(void)
  44{
  45    static int inited;
  46    int i;
  47
  48    if (inited) {
  49        return;
  50    }
  51
  52    for (i = 0; i < MODULE_INIT_MAX; i++) {
  53        QTAILQ_INIT(&init_type_list[i]);
  54    }
  55
  56    QTAILQ_INIT(&dso_init_list);
  57
  58    inited = 1;
  59}
  60
  61
  62static ModuleTypeList *find_type(module_init_type type)
  63{
  64    init_lists();
  65
  66    return &init_type_list[type];
  67}
  68
  69void register_module_init(void (*fn)(void), module_init_type type)
  70{
  71    ModuleEntry *e;
  72    ModuleTypeList *l;
  73
  74    e = g_malloc0(sizeof(*e));
  75    e->init = fn;
  76    e->type = type;
  77
  78    l = find_type(type);
  79
  80    QTAILQ_INSERT_TAIL(l, e, node);
  81}
  82
  83void register_dso_module_init(void (*fn)(void), module_init_type type)
  84{
  85    ModuleEntry *e;
  86
  87    init_lists();
  88
  89    e = g_malloc0(sizeof(*e));
  90    e->init = fn;
  91    e->type = type;
  92
  93    QTAILQ_INSERT_TAIL(&dso_init_list, e, node);
  94}
  95
  96void module_call_init(module_init_type type)
  97{
  98    ModuleTypeList *l;
  99    ModuleEntry *e;
 100
 101    if (modules_init_done[type]) {
 102        return;
 103    }
 104
 105    l = find_type(type);
 106
 107    QTAILQ_FOREACH(e, l, node) {
 108        e->init();
 109    }
 110
 111    modules_init_done[type] = true;
 112}
 113
 114#ifdef CONFIG_MODULES
 115
 116static const QemuModinfo module_info_stub[] = { {
 117    /* end of list */
 118} };
 119static const QemuModinfo *module_info = module_info_stub;
 120static const char *module_arch;
 121
 122void module_init_info(const QemuModinfo *info)
 123{
 124    module_info = info;
 125}
 126
 127void module_allow_arch(const char *arch)
 128{
 129    module_arch = arch;
 130}
 131
 132static bool module_check_arch(const QemuModinfo *modinfo)
 133{
 134    if (modinfo->arch) {
 135        if (!module_arch) {
 136            /* no arch set -> ignore all */
 137            return false;
 138        }
 139        if (strcmp(module_arch, modinfo->arch) != 0) {
 140            /* mismatch */
 141            return false;
 142        }
 143    }
 144    return true;
 145}
 146
 147static int module_load_file(const char *fname, bool mayfail, bool export_symbols)
 148{
 149    GModule *g_module;
 150    void (*sym)(void);
 151    const char *dsosuf = CONFIG_HOST_DSOSUF;
 152    int len = strlen(fname);
 153    int suf_len = strlen(dsosuf);
 154    ModuleEntry *e, *next;
 155    int ret, flags;
 156
 157    if (len <= suf_len || strcmp(&fname[len - suf_len], dsosuf)) {
 158        /* wrong suffix */
 159        ret = -EINVAL;
 160        goto out;
 161    }
 162    if (access(fname, F_OK)) {
 163        ret = -ENOENT;
 164        goto out;
 165    }
 166
 167    assert(QTAILQ_EMPTY(&dso_init_list));
 168
 169    flags = 0;
 170    if (!export_symbols) {
 171        flags |= G_MODULE_BIND_LOCAL;
 172    }
 173    g_module = g_module_open(fname, flags);
 174    if (!g_module) {
 175        if (!mayfail) {
 176            fprintf(stderr, "Failed to open module: %s\n",
 177                    g_module_error());
 178        }
 179        ret = -EINVAL;
 180        goto out;
 181    }
 182    if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
 183        fprintf(stderr, "Failed to initialize module: %s\n",
 184                fname);
 185        /* Print some info if this is a QEMU module (but from different build),
 186         * this will make debugging user problems easier. */
 187        if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
 188            fprintf(stderr,
 189                    "Note: only modules from the same build can be loaded.\n");
 190        }
 191        g_module_close(g_module);
 192        ret = -EINVAL;
 193    } else {
 194        QTAILQ_FOREACH(e, &dso_init_list, node) {
 195            e->init();
 196            register_module_init(e->init, e->type);
 197        }
 198        ret = 0;
 199    }
 200
 201    trace_module_load_module(fname);
 202    QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
 203        QTAILQ_REMOVE(&dso_init_list, e, node);
 204        g_free(e);
 205    }
 206out:
 207    return ret;
 208}
 209#endif
 210
 211bool module_load_one(const char *prefix, const char *lib_name, bool mayfail)
 212{
 213    bool success = false;
 214
 215#ifdef CONFIG_MODULES
 216    char *fname = NULL;
 217#ifdef CONFIG_MODULE_UPGRADES
 218    char *version_dir;
 219#endif
 220    const char *search_dir;
 221    char *dirs[5];
 222    char *module_name;
 223    int i = 0, n_dirs = 0;
 224    int ret;
 225    bool export_symbols = false;
 226    static GHashTable *loaded_modules;
 227    const QemuModinfo *modinfo;
 228    const char **sl;
 229
 230    if (!g_module_supported()) {
 231        fprintf(stderr, "Module is not supported by system.\n");
 232        return false;
 233    }
 234
 235    if (!loaded_modules) {
 236        loaded_modules = g_hash_table_new(g_str_hash, g_str_equal);
 237    }
 238
 239    module_name = g_strdup_printf("%s%s", prefix, lib_name);
 240
 241    if (g_hash_table_contains(loaded_modules, module_name)) {
 242        g_free(module_name);
 243        return true;
 244    }
 245    g_hash_table_add(loaded_modules, module_name);
 246
 247    for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
 248        if (modinfo->arch) {
 249            if (strcmp(modinfo->name, module_name) == 0) {
 250                if (!module_check_arch(modinfo)) {
 251                    return false;
 252                }
 253            }
 254        }
 255        if (modinfo->deps) {
 256            if (strcmp(modinfo->name, module_name) == 0) {
 257                /* we depend on other module(s) */
 258                for (sl = modinfo->deps; *sl != NULL; sl++) {
 259                    module_load_one("", *sl, false);
 260                }
 261            } else {
 262                for (sl = modinfo->deps; *sl != NULL; sl++) {
 263                    if (strcmp(module_name, *sl) == 0) {
 264                        /* another module depends on us */
 265                        export_symbols = true;
 266                    }
 267                }
 268            }
 269        }
 270    }
 271
 272    search_dir = getenv("QEMU_MODULE_DIR");
 273    if (search_dir != NULL) {
 274        dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
 275    }
 276    dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
 277    dirs[n_dirs++] = g_strdup(qemu_get_exec_dir());
 278
 279#ifdef CONFIG_MODULE_UPGRADES
 280    version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
 281                             G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
 282                             '_');
 283    dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
 284#endif
 285
 286    assert(n_dirs <= ARRAY_SIZE(dirs));
 287
 288    for (i = 0; i < n_dirs; i++) {
 289        fname = g_strdup_printf("%s/%s%s",
 290                dirs[i], module_name, CONFIG_HOST_DSOSUF);
 291        ret = module_load_file(fname, mayfail, export_symbols);
 292        g_free(fname);
 293        fname = NULL;
 294        /* Try loading until loaded a module file */
 295        if (!ret) {
 296            success = true;
 297            break;
 298        }
 299    }
 300
 301    if (!success) {
 302        g_hash_table_remove(loaded_modules, module_name);
 303        g_free(module_name);
 304    }
 305
 306    for (i = 0; i < n_dirs; i++) {
 307        g_free(dirs[i]);
 308    }
 309
 310#endif
 311    return success;
 312}
 313
 314#ifdef CONFIG_MODULES
 315
 316static bool module_loaded_qom_all;
 317
 318void module_load_qom_one(const char *type)
 319{
 320    const QemuModinfo *modinfo;
 321    const char **sl;
 322
 323    if (!type) {
 324        return;
 325    }
 326
 327    trace_module_lookup_object_type(type);
 328    for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
 329        if (!modinfo->objs) {
 330            continue;
 331        }
 332        if (!module_check_arch(modinfo)) {
 333            continue;
 334        }
 335        for (sl = modinfo->objs; *sl != NULL; sl++) {
 336            if (strcmp(type, *sl) == 0) {
 337                module_load_one("", modinfo->name, false);
 338            }
 339        }
 340    }
 341}
 342
 343void module_load_qom_all(void)
 344{
 345    const QemuModinfo *modinfo;
 346
 347    if (module_loaded_qom_all) {
 348        return;
 349    }
 350
 351    for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
 352        if (!modinfo->objs) {
 353            continue;
 354        }
 355        if (!module_check_arch(modinfo)) {
 356            continue;
 357        }
 358        module_load_one("", modinfo->name, false);
 359    }
 360    module_loaded_qom_all = true;
 361}
 362
 363void qemu_load_module_for_opts(const char *group)
 364{
 365    const QemuModinfo *modinfo;
 366    const char **sl;
 367
 368    for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
 369        if (!modinfo->opts) {
 370            continue;
 371        }
 372        for (sl = modinfo->opts; *sl != NULL; sl++) {
 373            if (strcmp(group, *sl) == 0) {
 374                module_load_one("", modinfo->name, false);
 375            }
 376        }
 377    }
 378}
 379
 380#else
 381
 382void module_allow_arch(const char *arch) {}
 383void qemu_load_module_for_opts(const char *group) {}
 384void module_load_qom_one(const char *type) {}
 385void module_load_qom_all(void) {}
 386
 387#endif
 388