You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

247 lines
4.5 KiB

9 years ago
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
9 years ago
#include <unistd.h>
#include "backend.h"
#define ID_MAX 32
typedef struct cmd_t {
struct cmd_t *next;
char *args; /**< stores path of cmd & args, delimited by '\0' */
char **argv; /**< stores array of pointers to args + NULL */
size_t argc; /**< args count */
9 years ago
size_t pos; /**< index+1 in argv[] where to insert IP address (zero means "no placeholder") */
9 years ago
} cmd_t;
struct _config {
char name[ID_MAX + 1];
time_t timeout;
9 years ago
cmd_t *start;
cmd_t *stop;
cmd_t *ban;
cmd_t *unban;
cmd_t *exists;
};
static cmd_t *
cmd_from_str(const char *str) {
cmd_t *cmd = NULL;
const char *delim = " \t";
9 years ago
char *token, *saveptr, **argv;
assert(str != NULL);
9 years ago
if ((cmd = calloc(1, sizeof(cmd_t))) == NULL)
return NULL;
if ((cmd->args = strdup(str)) == NULL)
goto cleanup;
9 years ago
cmd->argc = 1;
if ((cmd->argv = calloc(2, sizeof(cmd->argv))) == NULL)
goto cleanup;
cmd->argv[cmd->argc] = NULL;
9 years ago
strtok_r(cmd->args, delim, &saveptr);
9 years ago
cmd->argv[0] = cmd->args;
9 years ago
while ((token = strtok_r(NULL, delim, &saveptr)) != NULL) {
if ((argv = realloc(cmd->argv, sizeof(cmd->argv) * (cmd->argc + 2))) == NULL)
goto cleanup;
9 years ago
cmd->argv = argv;
9 years ago
if (strcmp(token, HOST_TOKEN) == 0)
9 years ago
cmd->pos = cmd->argc;
9 years ago
cmd->argv[cmd->argc] = token;
cmd->argc++;
}
9 years ago
cmd->argv[cmd->argc] = NULL;
9 years ago
return cmd;
cleanup:
free(cmd->args);
free(cmd->argv);
free(cmd);
return NULL;
}
static cmd_t *
cmd_list_append(cmd_t *list, cmd_t *cmd) {
cmd_t *c = NULL;
assert(cmd != NULL);
if (!list)
return cmd;
for (c = list; c->next != NULL; c = c->next);
c->next = cmd;
return list;
}
static void
cmd_list_destroy(cmd_t *list) {
cmd_t *next = NULL;
for (; list != NULL; list = next) {
next = list->next;
free(list->args);
free(list->argv);
free(list);
}
}
static bool
cmd_list_exec(cmd_t *list, const char *ip, time_t timeout) {
int status = 0;
pid_t pid;
for (cmd_t *cmd = list; cmd != NULL; cmd = cmd->next) {
pid = fork();
if (pid == 0) {
/* child */
if (ip && cmd->pos)
9 years ago
cmd->argv[cmd->pos - 1] = strdup(ip);
if (timeout)
alarm(timeout);
execv(cmd->args, cmd->argv);
} else if (pid > 0) {
/* parent */
waitpid(pid, &status, 0);
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
continue;
return false;
} else {
/* parent, fork error */
return false;
}
}
return true;
}
9 years ago
/* handlers */
cfg_t *
create(const char *id) {
cfg_t *cfg = NULL;
assert(id != NULL);
if ((cfg = calloc(1, sizeof(cfg_t))) == NULL)
return NULL;
strncpy(cfg->name, id, sizeof(cfg->name));
cfg->name[ID_MAX] = '\0';
return cfg;
}
#define CREATE_CMD(TYPE) \
if (strcmp(key, #TYPE) == 0) { \
cmd = cmd_from_str(value); \
if (cmd) { \
cfg->TYPE = cmd_list_append(cfg->TYPE, cmd); \
return true; \
} \
return false; \
}
bool
config(cfg_t *cfg, const char *key, const char *value) {
cmd_t *cmd = NULL;
assert(cfg != NULL);
assert(key != NULL);
assert(value != NULL);
if (strcmp(key, "timeout") == 0) {
cfg->timeout = atoi(value);
return true;
}
9 years ago
CREATE_CMD(start)
CREATE_CMD(stop)
CREATE_CMD(ban)
CREATE_CMD(unban)
CREATE_CMD(exists)
return false;
}
bool
ready(cfg_t *cfg) {
assert(cfg != NULL);
if (cfg->ban && cfg->unban)
return true;
return false;
}
bool
start(cfg_t *cfg) {
assert(cfg != NULL);
if (!cfg->start)
return true;
return cmd_list_exec(cfg->start, NULL, cfg->timeout);
}
bool
stop(cfg_t *cfg) {
assert(cfg != NULL);
if (!cfg->stop)
return true;
return cmd_list_exec(cfg->stop, NULL, cfg->timeout);
}
bool
ban(cfg_t *cfg, const char *ip) {
assert(cfg != NULL && ip != NULL);
return cmd_list_exec(cfg->ban, ip, cfg->timeout);
}
bool
unban(cfg_t *cfg, const char *ip) {
assert(cfg != NULL && ip != NULL);
return cmd_list_exec(cfg->unban, ip, cfg->timeout);
}
bool
exists(cfg_t *cfg, const char *ip) {
assert(cfg != NULL && ip != NULL);
if (!cfg->exists)
return true;
return cmd_list_exec(cfg->exists, ip, cfg->timeout);
}
9 years ago
bool
ping(cfg_t *cfg) {
return cfg != NULL;
}
void
destroy(cfg_t *cfg) {
assert(cfg != NULL);
/* free commands */
cmd_list_destroy(cfg->start);
cmd_list_destroy(cfg->stop);
cmd_list_destroy(cfg->ban);
cmd_list_destroy(cfg->unban);
cmd_list_destroy(cfg->exists);
free(cfg);
}