/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include "common.h" #include "config.h" #include "log.h" #include "mod-defs.h" #include "source.h" #include #define SOURCE_LIBRARY_PARAM "load" f2b_source_t * f2b_source_create(const char *name, const char *init) { f2b_source_t *source = NULL; if ((source = calloc(1, sizeof(f2b_source_t))) == NULL) return NULL; strlcpy(source->name, name, sizeof(source->name)); strlcpy(source->init, init, sizeof(source->init)); return source; } bool f2b_source_init(f2b_source_t *source, f2b_config_section_t *config) { f2b_config_param_t *param = NULL; int flags = RTLD_NOW | RTLD_LOCAL; const char *dlerr = NULL; assert(config != NULL); assert(config->type == t_source); param = f2b_config_param_find(config->param, SOURCE_LIBRARY_PARAM); if (!param) { f2b_log_msg(log_error, "can't find '%s' param in source config", SOURCE_LIBRARY_PARAM); return false; } if ((source->h = dlopen(param->value, flags)) == NULL) goto cleanup; if ((*(void **) (&source->create) = dlsym(source->h, "create")) == NULL) goto cleanup; if ((*(void **) (&source->config) = dlsym(source->h, "config")) == NULL) goto cleanup; if ((*(void **) (&source->state) = dlsym(source->h, "state")) == NULL) goto cleanup; if ((*(void **) (&source->logcb) = dlsym(source->h, "logcb")) == NULL) goto cleanup; if ((*(void **) (&source->start) = dlsym(source->h, "start")) == NULL) goto cleanup; if ((*(void **) (&source->next) = dlsym(source->h, "next")) == NULL) goto cleanup; if ((*(void **) (&source->stats) = dlsym(source->h, "stats")) == NULL) goto cleanup; if ((*(void **) (&source->stop) = dlsym(source->h, "stop")) == NULL) goto cleanup; if ((*(void **) (&source->destroy) = dlsym(source->h, "destroy")) == NULL) goto cleanup; if ((source->cfg = source->create(source->init)) == NULL) { f2b_log_msg(log_error, "source create config failed"); goto cleanup; } if ((source->state(source->cfg) & MOD_TYPE_SOURCE) == 0) { f2b_log_msg(log_error, "loaded module is not source type"); goto cleanup; } source->logcb(source->cfg, f2b_log_mod_cb); /* try init */ for (param = config->param; param != NULL; param = param->next) { if (strcmp(param->name, SOURCE_LIBRARY_PARAM) == 0) continue; if (source->config(source->cfg, param->name, param->value)) continue; f2b_log_msg(log_warn, "param pair not accepted by source '%s': %s=%s", config->name, param->name, param->value); } if ((source->flags = source->state(source->cfg)) < 0) { f2b_log_msg(log_error, "can't get module state"); goto cleanup; } if (source->flags & MOD_WRONG_API) { f2b_log_msg(log_error, "module reports wrong api version"); goto cleanup; } if (source->flags & MOD_IS_READY) return true; /* still not ready */ f2b_log_msg(log_error, "source '%s' not fully configured", config->name); cleanup: dlerr = dlerror(); if (dlerr) f2b_log_msg(log_error, "source load error: %s", dlerr); if (source->h) { if (source->cfg && source->destroy) { source->destroy(source->cfg); source->cfg = NULL; } dlclose(source->h); source->create = NULL; source->config = NULL; source->state = NULL; source->logcb = NULL; source->start = NULL; source->next = NULL; source->stats = NULL; source->stop = NULL; source->destroy = NULL; source->h = NULL; } return false; } void f2b_source_destroy(f2b_source_t *source) { if (!source) return; if (source->h) { if (source->cfg) source->destroy(source->cfg); dlclose(source->h); } free(source); } uint32_t f2b_source_next(f2b_source_t *source, char *buf, size_t bufsize, bool reset) { assert(source != NULL); return source->next(source->cfg, buf, bufsize, reset); } bool f2b_source_stats(f2b_source_t *source, char *buf, size_t bufsize) { assert(source != NULL); return source->stats(source->cfg, buf, bufsize); } #define SOURCE_CMD_ARG0(CMD, RETURNS) \ RETURNS \ f2b_source_ ## CMD(f2b_source_t *source) { \ assert(source != NULL); \ return source->CMD(source->cfg); \ } SOURCE_CMD_ARG0(start, bool) SOURCE_CMD_ARG0(stop, bool) void f2b_source_cmd_stats(char *buf, size_t bufsize, f2b_source_t *source) { assert(source != NULL); assert(buf != NULL); source->stats(source->cfg, buf, bufsize); }