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