src/module.c
author Tero Marttila <terom@fixme.fi>
Mon, 16 Mar 2009 01:14:36 +0200
changeset 66 ef8c9d7daf62
parent 65 d7508879ad01
child 70 a9a4c5e6aa30
permissions -rw-r--r--
all options are now fully implemented
#include "module.h"
#include "log.h"

#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
#include <assert.h>

err_t modules_create (struct modules **modules_ptr, struct nexus *nexus)
{
    struct modules *modules;

    // alloc
    if ((modules = calloc(1, sizeof(*modules))) == NULL)
        return ERR_CALLOC;
    
    // init
    TAILQ_INIT(&modules->list);

    // store
    modules->nexus = nexus;

    // ok
    *modules_ptr = modules;

    return SUCCESS;
}

/**
 * Load the symbol named "<module>_<suffix>".
 */ 
static err_t module_symbol (struct module *module, void **sym, const char *suffix)
{
    char sym_name[MODULE_SYMBOL_MAX];

    // validate the length of the suffix
    assert(strlen(module->info.name) <= MODULE_NAME_MAX);
    assert(strlen(suffix) <= MODULE_SUFFIX_MAX);

    // format
    sprintf(sym_name, "%s_%s", module->info.name, suffix);

    // load
    if ((*sym = dlsym(module->handle, sym_name)) == NULL)
       return ERR_MODULE_SYM;

    // ok
    return SUCCESS;
}

err_t module_load (struct modules *modules, struct module **module_ptr, const struct module_info *info, struct error_info *err)
{
    struct module *module;

    // validate the module name
    if (strlen(info->name) > MODULE_NAME_MAX)
        return SET_ERROR(err, ERR_MODULE_NAME);
    
    // alloc
    if ((module = calloc(1, sizeof(*module))) == NULL)
        return SET_ERROR(err, ERR_CALLOC);
    
    // store
    module->info = *info;

    // clear dlerrors
    (void) dlerror();

    // load it
    if ((module->handle = dlopen(info->path, RTLD_NOW)) == NULL)
        JUMP_SET_ERROR_STR(err, ERR_MODULE_OPEN, dlerror());
    
    // load the funcs symbol
    if ((ERROR_CODE(err) = module_symbol(module, (void **) &module->funcs, "funcs")))
        JUMP_SET_ERROR_STR(err, ERROR_CODE(err), dlerror());

    // call the init func
    if ((module->funcs->init(modules->nexus, &module->ctx, err)))
        goto error;

    // add to modules list
    TAILQ_INSERT_TAIL(&modules->list, module, modules_list);

    // ok
    if (module_ptr)
        *module_ptr = module;

    return SUCCESS;

error:
    // XXX: cleanup
    free(module);

    return ERROR_CODE(err);    
}

struct module* module_get (struct modules *modules, const char *name)
{
    struct module *module = NULL;

    // look for it...
    TAILQ_FOREACH(module, &modules->list, modules_list) {
        if (strcasecmp(module->info.name, name) == 0)
            // found it
            return module;
    }

    // no such module
    return NULL;
}

err_t module_conf (struct module *module, const char *name, char *value, struct error_info *err)
{
    // call the conf func
    return module->funcs->conf(module->ctx, name, value, err);
}