blob: 87185689f94d77730dd63374be27e95a3eb6bb18 [file] [log] [blame]
#include <config.h>
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <stdio.h>
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ctype.h>
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include <dlfcn.h>
#include "mibincl.h"
#include "struct.h"
#include "read_config.h"
#include "agent_read_config.h"
#include "dlmod.h"
static struct dlmod *dlmods = NULL;
int dlmod_next_index = 1;
static void dlmod_parse_config(char *, char *);
static void dlmod_free_config (void);
static char dlmod_path[1024];
void
init_dlmod (void)
{
char *p;
int l;
snmpd_register_config_handler("dlmod", dlmod_parse_config,
dlmod_free_config,
"dlmod-file-to-load");
p = getenv("SNMP_DLMOD_PATH");
strncpy(dlmod_path, DLMOD_DEFAULT_PATH, sizeof(dlmod_path));
if (p) {
if (p[0] == '+') {
l = strlen(dlmod_path);
if (dlmod_path[l - 1] != ':')
strncat(dlmod_path, ":", sizeof(dlmod_path) - l);
strncat(dlmod_path, p + 1,
sizeof(dlmod_path) - strlen(dlmod_path));
} else
strncpy(dlmod_path, p, sizeof(dlmod_path));
}
#if 1
DEBUGMSGTL(("dlmod", "dlmod_path: %s\n", dlmod_path));
#endif
}
void
deinit_dlmod (void)
{
snmpd_unregister_config_handler("dlmod");
}
static void
dlmod_parse_config(char *token,
char *cptr)
{
char *dlm_name, *dlm_path;
struct dlmod *dlm;
if (cptr == NULL) {
config_perror("Bad dlmod line");
return;
}
/* remove comments */
*(cptr + strcspn(cptr, "#;\r\n")) = '\0';
dlm = dlmod_create_module();
if (!dlm)
return;
/* dynamic module name */
dlm_name = strtok(cptr, "\t ");
if (dlm_name == NULL) {
config_perror("Bad dlmod line");
dlmod_delete_module(dlm);
return;
}
strncpy(dlm->name, dlm_name, sizeof(dlm->name));
/* dynamic module path */
dlm_path = strtok(NULL, "\t ");
if (dlm_path)
strncpy(dlm->path, dlm_path, sizeof(dlm->path));
else
strncpy(dlm->path, dlm_name, sizeof(dlm->path));
dlmod_load_module(dlm);
if (dlm->status == DLMOD_ERROR)
snmp_log(LOG_ERR, "%s\n", dlm->error);
}
static void
dlmod_free_config (void)
{
struct dlmod *dtmp, *dtmp2;
for (dtmp = dlmods; dtmp != NULL;) {
dtmp2 = dtmp;
dtmp = dtmp->next;
dlmod_unload_module(dtmp2);
free(dtmp2);
}
dlmods = NULL;
dlmod_next_index = 1;
}
struct dlmod *
dlmod_create_module (void)
{
struct dlmod **pdlmod, *dlm;
#if 1
DEBUGMSGTL(("dlmod", "dlmod_create_module\n"));
#endif
dlm = calloc(1, sizeof(struct dlmod));
if (dlm == NULL)
return NULL;
dlm->index = dlmod_next_index++;
dlm->status = DLMOD_UNLOADED;
for (pdlmod = &dlmods; *pdlmod != NULL; pdlmod = &((*pdlmod)->next))
;
(*pdlmod) = dlm;
return dlm;
}
void
dlmod_delete_module(struct dlmod *dlm)
{
struct dlmod **pdlmod;
#if 1
DEBUGMSGTL(("dlmod", "dlmod_delete_module\n"));
#endif
if (!dlm || dlm->status != DLMOD_UNLOADED)
return;
for (pdlmod = &dlmods; *pdlmod; pdlmod = &((*pdlmod)->next))
if (*pdlmod == dlm) {
*pdlmod = dlm->next;
free(dlm);
return;
}
}
void
dlmod_load_module(struct dlmod *dlm)
{
char sym_init[64];
char *p, tmp_path[255];
int (*dl_init)(void);
#if 1
DEBUGMSGTL(("dlmod", "dlmod_load_module\n"));
#endif
if (!dlm || !dlm->path || !dlm->name || dlm->status != DLMOD_UNLOADED)
return;
if (dlm->path[0] == '/') {
dlm->handle = dlopen(dlm->path, RTLD_NOW);
if (dlm->handle == NULL) {
snprintf(dlm->error, sizeof(dlm->error),
"dlopen failed: %s", dlerror());
dlm->status = DLMOD_ERROR;
return;
}
} else {
for (p = strtok(dlmod_path, ":"); p; p = strtok(NULL, ":")) {
snprintf(tmp_path, sizeof(tmp_path), "%s/%s.so", p, dlm->path);
#if 1
DEBUGMSGTL(("dlmod", "p: %s tmp_path: %s\n", p, tmp_path));
#endif
dlm->handle = dlopen(tmp_path, RTLD_NOW);
if (dlm->handle == NULL) {
snprintf(dlm->error, sizeof(dlm->error),
"dlopen failed: %s", dlerror());
dlm->status = DLMOD_ERROR;
}
}
strncpy(dlm->path, tmp_path, sizeof(dlm->path));
if (dlm->status == DLMOD_ERROR)
return;
}
snprintf(sym_init, sizeof(sym_init), "_dynamic_init_%s", dlm->name);
dl_init = dlsym(dlm->handle, sym_init);
if (dl_init == NULL) {
snprintf(dlm->error, sizeof(dlm->error),
"dlsym failed: can't find \'%s\'", sym_init);
dlm->status = DLMOD_ERROR;
return;
}
if (dl_init()) {
snprintf(dlm->error, sizeof(dlm->error), "\'%s\' failed", sym_init);
dlm->status = DLMOD_ERROR;
return;
}
dlm->error[0] = '\0';
dlm->status = DLMOD_LOADED;
}
void
dlmod_unload_module (struct dlmod *dlm)
{
char sym_deinit[64];
char buf[256];
int (* dl_deinit)(void);
if (!dlm || dlm->status != DLMOD_LOADED)
return;
snprintf(sym_deinit, sizeof(sym_deinit), "_dynamic_deinit_%s", dlm->name);
dl_deinit = dlsym(dlm->handle, sym_deinit);
if (dl_deinit == NULL) {
/** it's right way ? */
dlm->status = DLMOD_ERROR;
return;
}
dl_deinit();
dlclose(dlm->handle);
dlm->status = DLMOD_UNLOADED;
#if 1
DEBUGMSGTL(("dlmod", "Module %s unloaded\n", dlm->name));
#endif
}
int
dlmod_get_next_index (void)
{
return dlmod_next_index;
}
struct dlmod *
dlmod_get_by_index (int iindex)
{
struct dlmod *dlmod;
for (dlmod = dlmods; dlmod; dlmod=dlmod->next)
if (dlmod->index == iindex)
return dlmod;
return NULL;
}
#if 0
struct dlmod *
dlmod_get_next(struct dlmod *dlm)
{
if (dlm)
return dlmods;
else
return dlm->next;
}
#endif