1 #include "module.h" |
1 #include "module.h" |
2 #include "log.h" |
2 #include <lib/log.h> |
3 |
3 |
4 #include <stdlib.h> |
4 #include <stdlib.h> |
5 #include <unistd.h> |
5 #include <unistd.h> |
6 #include <dlfcn.h> |
6 #include <dlfcn.h> |
7 #include <string.h> |
7 #include <string.h> |
8 #include <assert.h> |
8 #include <assert.h> |
9 |
9 |
10 const struct error_list module_errors = ERROR_LIST("module", |
10 const struct error_list module_errors = ERROR_LIST("module", |
11 ERROR_TYPE_STRING( ERR_MODULE_NAME, "invalid module name" ), |
11 ERROR_TYPE_STRING( ERR_MODULE_NAME, "invalid module name" ), |
12 ERROR_TYPE( ERR_MODULE_DUP, "module already loaded" ), |
12 ERROR_TYPE( ERR_MODULE_DUP, "module already loaded" ), |
13 ERROR_TYPE_STRING( ERR_MODULE_PATH, "invalid module path" ), |
13 ERROR_TYPE_STRING( ERR_MODULE_PATH, "invalid module path" ), |
14 ERROR_TYPE_STRING( ERR_MODULE_OPEN, "module dlopen() failed" ), |
14 ERROR_TYPE_STRING( ERR_MODULE_OPEN, "module dlopen() failed" ), |
15 ERROR_TYPE_STRING( ERR_MODULE_SYM, "module dlsym() failed" ), |
15 ERROR_TYPE_STRING( ERR_MODULE_SYM, "module dlsym() failed" ), |
16 ERROR_TYPE_STRING( ERR_MODULE_INIT_FUNC, "invalid module init func" ), |
16 ERROR_TYPE_STRING( ERR_MODULE_INIT_FUNC, "invalid module init func" ), |
17 ERROR_TYPE_STRING( ERR_MODULE_CONF, "module_conf" ) |
17 ERROR_TYPE_STRING( ERR_MODULE_CONF, "module_conf" ), |
|
18 ERROR_TYPE( ERR_MODULE_STATE, "module in wrong state for operation" ), |
|
19 ERROR_TYPE( ERR_MODULE_UNLOAD, "unable to unload module" ) |
18 ); |
20 ); |
19 |
21 |
20 err_t modules_create (struct modules **modules_ptr, struct nexus *nexus) |
22 err_t modules_create (struct modules **modules_ptr, struct nexus *nexus, error_t *err) |
21 { |
23 { |
22 struct modules *modules; |
24 struct modules *modules; |
23 |
25 |
24 // alloc |
26 // alloc |
25 if ((modules = calloc(1, sizeof(*modules))) == NULL) |
27 if ((modules = calloc(1, sizeof(*modules))) == NULL) |
26 return ERR_CALLOC; |
28 return SET_ERROR_MEM(err); |
27 |
29 |
28 // init |
30 // init |
29 TAILQ_INIT(&modules->list); |
31 TAILQ_INIT(&modules->list); |
30 |
32 |
31 // store |
33 // store |
83 } |
85 } |
84 |
86 |
85 err_t modules_unload (struct modules *modules) |
87 err_t modules_unload (struct modules *modules) |
86 { |
88 { |
87 struct module *module; |
89 struct module *module; |
88 err_t err; |
90 error_t err; |
89 |
91 |
90 // unload each module in turn |
92 // unload each module in turn |
91 while ((module = TAILQ_FIRST(&modules->list))) { |
93 while ((module = TAILQ_FIRST(&modules->list))) { |
92 if ((err = module_unload(module))) |
94 if (module_unload(module, &err)) |
93 log_warn("module_unload(%s) failed: %s", module->info.name, error_name(err)); |
95 log_warn_error(&err, "module_unload(%s) failed", module->info.name); |
94 } |
96 } |
95 |
97 |
96 // ok |
98 // ok |
97 return SUCCESS; |
99 return SUCCESS; |
98 } |
100 } |
206 if (modules_lookup(modules, _info->name)) |
208 if (modules_lookup(modules, _info->name)) |
207 return SET_ERROR(err, &module_errors, ERR_MODULE_DUP); |
209 return SET_ERROR(err, &module_errors, ERR_MODULE_DUP); |
208 |
210 |
209 // alloc |
211 // alloc |
210 if ((module = calloc(1, sizeof(*module))) == NULL) |
212 if ((module = calloc(1, sizeof(*module))) == NULL) |
211 return SET_ERROR(err, &module_errors, ERR_CALLOC); |
213 return SET_ERROR_MEM(err); |
212 |
214 |
213 // initialize |
215 // initialize |
214 module->info = *_info; |
216 module->info = *_info; |
215 module->modules = modules; |
217 module->modules = modules; |
216 module->refcount = 1; |
218 module->refcount = 1; |
238 // load it |
240 // load it |
239 if ((module->handle = dlopen(module->info.path, RTLD_NOW)) == NULL) |
241 if ((module->handle = dlopen(module->info.path, RTLD_NOW)) == NULL) |
240 JUMP_SET_ERROR_STR(err, &module_errors, ERR_MODULE_OPEN, dlerror()); |
242 JUMP_SET_ERROR_STR(err, &module_errors, ERR_MODULE_OPEN, dlerror()); |
241 |
243 |
242 // load the funcs symbol |
244 // load the funcs symbol |
243 if ((ERROR_CODE(err) = module_symbol(module, (void **) &module->desc, "module"))) |
245 if (module_symbol(module, (void **) &module->desc, "module", err)) |
244 JUMP_SET_ERROR_STR(err, &module_errors, ERROR_CODE(err), dlerror()); |
246 goto error; |
245 |
247 |
246 // call the init func |
248 // call the init func |
247 if ((module->desc->init(modules->nexus, &module->ctx, err))) |
249 if ((module->desc->init(modules->nexus, &module->ctx, err))) |
248 goto error; |
250 goto error; |
249 |
251 |
277 |
279 |
278 err_t module_conf_raw (struct module *module, const char *name, char *value, error_t *err) |
280 err_t module_conf_raw (struct module *module, const char *name, char *value, error_t *err) |
279 { |
281 { |
280 // sanity-check |
282 // sanity-check |
281 if (!module->desc->config_options) |
283 if (!module->desc->config_options) |
282 RETURN_SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module does not have any config options"); |
284 return SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module does not have any config options"); |
283 |
285 |
284 // wrong state |
286 // wrong state |
285 if (module->unloading) |
287 if (module->unloading) |
286 RETURN_SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded"); |
288 return SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded"); |
287 |
289 |
288 // parse/apply using the module's stuff |
290 // parse/apply using the module's stuff |
289 // XXX: error namespaces? |
291 // XXX: error namespaces? |
290 return config_apply_raw(module->desc->config_options, module->modules->nexus, module->ctx, name, value, err); |
292 return config_apply_raw(module->desc->config_options, module->modules->nexus, module->ctx, name, value, err); |
291 } |
293 } |
306 |
308 |
307 err_t module_conf (struct module *module, const struct config_option *opt, const struct config_value *value, error_t *err) |
309 err_t module_conf (struct module *module, const struct config_option *opt, const struct config_value *value, error_t *err) |
308 { |
310 { |
309 // wrong state |
311 // wrong state |
310 if (module->unloading) |
312 if (module->unloading) |
311 RETURN_SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded"); |
313 return SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded"); |
312 |
314 |
313 // apply with the module's ctx |
315 // apply with the module's ctx |
314 // XXX: error namespaces? |
316 // XXX: error namespaces? |
315 return config_apply_opt(opt, module->ctx, value, err); |
317 return config_apply_opt(opt, module->ctx, value, err); |
316 } |
318 } |
317 |
319 |
318 err_t module_unload (struct module *module) |
320 err_t module_unload (struct module *module, error_t *err) |
319 { |
321 { |
320 err_t err; |
|
321 |
|
322 // wrong state |
322 // wrong state |
323 if (module->unloading) |
323 if (module->unloading) |
324 return ERR_MODULE_STATE; |
324 return SET_ERROR(err, &module_errors, ERR_MODULE_STATE); |
325 |
325 |
326 // remove from modules list |
326 // remove from modules list |
327 TAILQ_REMOVE(&module->modules->list, module, modules_list); |
327 TAILQ_REMOVE(&module->modules->list, module, modules_list); |
328 |
328 |
329 // update status |
329 // update status |
330 module->unloading = true; |
330 module->unloading = true; |
331 |
331 |
332 if (module->desc->unload) { |
332 if (module->desc->unload) { |
333 // invoke the unload func, passing it our reference |
333 // invoke the unload func, passing it our reference |
334 // note that the module might not exist anymore after calling this |
334 // note that the module might not exist anymore after calling this |
335 if ((err = module->desc->unload(module->ctx, module))) { |
335 if (module->desc->unload(module->ctx, module, err)) { |
336 // mark it as "unloaded" |
336 // mark it as "unloaded" |
337 module_unloaded(module); |
337 module_unloaded(module); |
338 |
338 |
339 return err; |
339 return PUSH_ERROR(err, &module_errors, ERR_MODULE_UNLOAD); |
340 } |
340 } |
341 |
341 |
342 } else { |
342 } else { |
343 // no unload procedure, just destroy it as soon as needed |
343 // no unload procedure, just destroy it as soon as needed |
344 module_unloaded(module); |
344 module_unloaded(module); |