diff --git a/src/sources/files.c b/src/sources/files.c index 8604717..44d1cba 100644 --- a/src/sources/files.c +++ b/src/sources/files.c @@ -4,14 +4,15 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include "source.h" - #include #include #include #include +#include "source.h" +#define MODNAME "files" + typedef struct f2b_file_t { struct f2b_file_t *next; bool opened; @@ -22,17 +23,12 @@ typedef struct f2b_file_t { struct _config { char path[256]; - char error[256]; - void (*errcb)(const char *errstr); + void (*logcb)(enum loglevel lvl, const char *msg); f2b_file_t *files; f2b_file_t *current; }; -static void -errcb_stub(const char *str) { - assert(str != NULL); - (void)(str); -} +#include "source.c" static bool file_open(f2b_file_t *file, const char *path) { @@ -77,21 +73,24 @@ file_close(f2b_file_t *file) { } static bool -file_rotated(const f2b_file_t *file) { +file_rotated(const cfg_t *cfg, const f2b_file_t *file) { struct stat st; - assert(file != NULL); if (!file->opened) return true; - if (stat(file->path, &st) != 0) + if (stat(file->path, &st) != 0) { + log_msg(cfg, error, "file stat error: %s", strerror(errno)); return true; + } if (file->st.st_dev != st.st_dev || file->st.st_ino != st.st_ino || - file->st.st_size > st.st_size) + file->st.st_size > st.st_size) { + log_msg(cfg, info, "file replaced: %s", file->path); return true; + } return false; } @@ -117,7 +116,7 @@ create(const char *init) { if ((cfg = calloc(1, sizeof(cfg_t))) == NULL) return NULL; strlcpy(cfg->path, init, sizeof(cfg->path)); - cfg->errcb = &errcb_stub; + cfg->logcb = &logcb_stub; return cfg; } @@ -143,21 +142,6 @@ ready(cfg_t *cfg) { return true; } -char * -error(cfg_t *cfg) { - assert(cfg != NULL); - - return cfg->error; -} - -void -errcb(cfg_t *cfg, void (*cb)(const char *errstr)) { - assert(cfg != NULL); - assert(cb != NULL); - - cfg->errcb = cb; -} - bool start(cfg_t *cfg) { f2b_file_t *file = NULL; @@ -172,11 +156,7 @@ start(cfg_t *cfg) { if ((file = calloc(1, sizeof(f2b_file_t))) == NULL) continue; if (file_open(file, globbuf.gl_pathv[i]) == false) { - if (cfg->errcb) { - snprintf(cfg->error, sizeof(cfg->error), "can't open file: %s -- %s", - globbuf.gl_pathv[i], strerror(errno)); - cfg->errcb(cfg->error); - } + log_msg(cfg, error, "can't open file: %s -- %s", globbuf.gl_pathv[i], strerror(errno)); free(file); continue; } @@ -217,13 +197,10 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { cfg->current = cfg->files; for (f2b_file_t *file = cfg->current; file != NULL; file = file->next) { - if (file_rotated(file)) + if (file_rotated(cfg, file)) file_close(file); if (!file->opened && !file_open(file, NULL)) { - if (cfg->errcb) { - snprintf(cfg->error, sizeof(cfg->error), "can't open file: %s", file->path); - cfg->errcb(cfg->error); - } + log_msg(cfg, error, "can't open file: %s", file->path); continue; } if (file_getline(file, buf, bufsize)) diff --git a/src/sources/portknock.c b/src/sources/portknock.c index 4a23095..d8faafe 100644 --- a/src/sources/portknock.c +++ b/src/sources/portknock.c @@ -4,8 +4,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include "source.h" - #include #include #include @@ -13,6 +11,8 @@ #include #include +#include "source.h" +#define MODNAME "portknock" #define HOST_MAX 48 #define PORT_MAX 6 @@ -25,17 +25,12 @@ typedef struct f2b_port_t { struct _config { char name[32]; - char error[256]; - void (*errcb)(const char *errstr); + void (*logcb)(enum loglevel lvl, const char *msg); f2b_port_t *ports; f2b_port_t *current; }; -static void -errcb_stub(const char *str) { - assert(str != NULL); - (void)(str); -} +#include "source.c" static bool try_parse_listen_opt(f2b_port_t *port, const char *value) { @@ -79,7 +74,7 @@ create(const char *init) { if ((cfg = calloc(1, sizeof(cfg_t))) == NULL) return NULL; strlcpy(cfg->name, init, sizeof(cfg->name)); - cfg->errcb = &errcb_stub; + cfg->logcb = &logcb_stub; return cfg; } @@ -92,11 +87,11 @@ config(cfg_t *cfg, const char *key, const char *value) { if (strcmp(key, "listen") == 0) { f2b_port_t *port = NULL; if ((port = calloc(1, sizeof(f2b_port_t))) == NULL) { - strlcpy(cfg->error, "out of memory", sizeof(cfg->error)); + log_msg(cfg, error, "out of memory"); return false; } if (try_parse_listen_opt(port, value) == false) { - snprintf(cfg->error, sizeof(cfg->error), "can't parse: %s", value); + log_msg(cfg, error, "can't parse: %s", value); free(port); return false; } @@ -116,21 +111,6 @@ ready(cfg_t *cfg) { return false; } -char * -error(cfg_t *cfg) { - assert(cfg != NULL); - - return cfg->error; -} - -void -errcb(cfg_t *cfg, void (*cb)(const char *errstr)) { - assert(cfg != NULL); - assert(cb != NULL); - - cfg->errcb = cb; -} - bool start(cfg_t *cfg) { struct addrinfo hints; @@ -148,8 +128,7 @@ start(cfg_t *cfg) { port->sock = -1; int ret = getaddrinfo(port->host, port->port, &hints, &result); if (ret != 0) { - snprintf(cfg->error, sizeof(cfg->error), "getaddrinfo: %s", gai_strerror(ret)); - cfg->errcb(cfg->error); + log_msg(cfg, error, "getaddrinfo: %s", gai_strerror(ret)); continue; } for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next) { @@ -169,10 +148,8 @@ start(cfg_t *cfg) { } } freeaddrinfo(result); - if (port->sock < 0) { - snprintf(cfg->error, sizeof(cfg->error), "can't bind/listen on %s:%s", port->host, port->port); - cfg->errcb(cfg->error); - } + if (port->sock < 0) + log_msg(cfg, error, "can't bind/listen on %s:%s", port->host, port->port); } return true; @@ -208,8 +185,7 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { if (sock < 0 && errno == EAGAIN) continue; if (sock < 0) { - snprintf(cfg->error, sizeof(cfg->error), "accept error: %s", strerror(errno)); - cfg->errcb(cfg->error); + log_msg(cfg, error, "accept() error: %s", strerror(errno)); continue; } close(sock); @@ -221,7 +197,7 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) &addr)->sin6_addr), buf, bufsize); return true; } - cfg->errcb("can't convert sockaddr to string: unknown AF"); + cfg->logcb(error, "can't convert sockaddr to string: unknown AF"); } return false; diff --git a/src/sources/redis.c b/src/sources/redis.c index 0383a00..fb0ac0b 100644 --- a/src/sources/redis.c +++ b/src/sources/redis.c @@ -4,20 +4,20 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include "source.h" - #include #include #include "../strlcpy.h" +#include "source.h" + +#define MODNAME "redis" #define ID_MAX 32 struct _config { char name[ID_MAX + 1]; char hash[ID_MAX * 2]; - char error[256]; - void (*errcb)(const char *errstr); + void (*logcb)(enum loglevel lvl, const char *msg); time_t timeout; uint8_t database; char password[32]; @@ -26,11 +26,7 @@ struct _config { redisContext *conn; }; -static void -errcb_stub(const char *str) { - assert(str != NULL); - (void)(str); -} +#include "source.c" static bool redis_connect(cfg_t *cfg) { @@ -47,14 +43,14 @@ redis_connect(cfg_t *cfg) { if (!conn) break; if (conn->err) { - snprintf(cfg->error, sizeof(cfg->error), "Connection error: %s", conn->errstr); + log_msg(cfg, error, "connection error: %s", conn->errstr); break; } if (cfg->password[0]) { if ((reply = redisCommand(conn, "AUTH %s", cfg->password)) == NULL) break; if (reply->type == REDIS_REPLY_ERROR) { - snprintf(cfg->error, sizeof(cfg->error), "auth error: %s", reply->str); + log_msg(cfg, error, "auth error: %s", reply->str); break; } freeReplyObject(reply); @@ -63,7 +59,7 @@ redis_connect(cfg_t *cfg) { if ((reply = redisCommand(conn, "SELECT %d", cfg->database)) == NULL) break; if (reply->type == REDIS_REPLY_ERROR) { - snprintf(cfg->error, sizeof(cfg->error), "auth error: %s", reply->str); + log_msg(cfg, error, "reply error: %s", reply->str); break; } freeReplyObject(reply); @@ -71,13 +67,13 @@ redis_connect(cfg_t *cfg) { timeout.tv_sec = 0; timeout.tv_usec = 10000; /* 0.01s */ if (redisSetTimeout(conn, timeout) != REDIS_OK) { - strlcpy(cfg->error, "can't enable nonblocking mode", sizeof(cfg->error)); + log_msg(cfg, error, "can't enable nonblocking mode"); break; } if ((reply = redisCommand(conn, "SUBSCRIBE %s", cfg->hash)) == NULL) break; if (reply->type == REDIS_REPLY_ERROR) { - snprintf(cfg->error, sizeof(cfg->error), "can't subscribe: %s", reply->str); + log_msg(cfg, error, "can't subscribe: %s", reply->str); break; } freeReplyObject(reply); @@ -118,7 +114,7 @@ create(const char *init) { strlcpy(cfg->name, init, sizeof(cfg->name)); strlcpy(cfg->hash, "f2b-banned-", sizeof(cfg->hash)); strlcat(cfg->hash, init, sizeof(cfg->hash)); - cfg->errcb = &errcb_stub; + cfg->logcb = &logcb_stub; return cfg; } @@ -163,21 +159,6 @@ ready(cfg_t *cfg) { return true; } -char * -error(cfg_t *cfg) { - assert(cfg != NULL); - - return cfg->error; -} - -void -errcb(cfg_t *cfg, void (*cb)(const char *errstr)) { - assert(cfg != NULL); - assert(cb != NULL); - - cfg->errcb = cb; -} - bool start(cfg_t *cfg) { assert(cfg != NULL); @@ -209,7 +190,7 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { return false; /* reconnect failure */ if (cfg->conn->err) { - snprintf(cfg->error, sizeof(cfg->error), "connection error: %s", cfg->conn->errstr); + log_msg(cfg, error, "connection error: %s", cfg->conn->errstr); return false; } @@ -221,18 +202,16 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { strlcpy(buf, reply->element[2]->str, bufsize); gotit = true; } else { - cfg->errcb(cfg->error); + log_msg(cfg, error, "wrong redis message type: %s", reply->element[0]->str); } } else { - strlcpy(cfg->error, "reply is not a array type", sizeof(cfg->error)); - cfg->errcb(cfg->error); + log_msg(cfg, error, "reply is not a array type"); } freeReplyObject(reply); } else if (cfg->conn->err == REDIS_ERR_IO && errno == EAGAIN) { cfg->conn->err = 0; /* reset error to prevent reconnecting */ } else { - snprintf(cfg->error, sizeof(cfg->error), "can't get reply from server %s: %s", cfg->host, cfg->conn->errstr); - cfg->errcb(cfg->error); + log_msg(cfg, error, "can't get reply from server %s: %s", cfg->host, cfg->conn->errstr); } return gotit; diff --git a/src/sources/source.c b/src/sources/source.c new file mode 100644 index 0000000..ce8a370 --- /dev/null +++ b/src/sources/source.c @@ -0,0 +1,38 @@ +/* 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. + */ + +/* function shared between modules */ + +static void +logcb_stub(enum loglevel lvl, const char *str) { + assert(str != NULL); + (void)(lvl); + (void)(str); +} + +__attribute__ ((format (printf, 3, 4))) +static void +log_msg(const cfg_t *cfg, enum loglevel lvl, const char *format, ...) { + char buf[4096] = ""; + va_list args; + size_t len; + + len = snprintf(buf, sizeof(buf), "source/%s ", MODNAME); + va_start(args, format); + vsnprintf(buf + len, sizeof(buf) - len, format, args); + va_end(args); + + cfg->logcb(lvl, buf); +} + +void +logcb(cfg_t *cfg, void (*cb)(enum loglevel lvl, const char *msg)) { + assert(cfg != NULL); + assert(cb != NULL); + + cfg->logcb = cb; +} diff --git a/src/sources/source.h b/src/sources/source.h index 566ed16..5bbecb8 100644 --- a/src/sources/source.h +++ b/src/sources/source.h @@ -9,11 +9,21 @@ #include #include #include +#include #include #include #include "../strlcpy.h" +enum loglevel { + debug = 0, + info = 1, + notice = 2, + warn = 3, + error = 4, + fatal = 5, +}; /* see log.h */ + /** * @file * This header describes module API of type 'source' @@ -24,17 +34,15 @@ * f2b, source; * f2b => source [label="create(init)"]; * f2b << source [label="module handler, cfg_t *cfg"]; + * f2b => source [label="logcb(cfg, cb)"]; * |||; * f2b => source [label="config(cfg, param, value)"]; * f2b << source [label="true"]; * f2b => source [label="config(cfg, param, value)"]; * f2b << source [label="true"]; * f2b => source [label="config(cfg, param, value)"]; + * f2b <<= source [label="logcb(level, char *msg)"]; * f2b << source [label="false"]; - * f2b => source [label="error(cfg)"]; - * f2b << source [label="const char *error"]; - * |||; - * f2b => source [label="errcb(cfg, cb), optional"]; * |||; * f2b => source [label="ready(cfg)"]; * f2b << source [label="true"]; @@ -48,7 +56,7 @@ * f2b => source [label="next(cfg, buf, sizeof(buf), true)"]; * f2b << source [label="true"]; * f2b => source [label="next(cfg, buf, sizeof(buf), false)"]; - * f2b <<= source [label="errcb(char *error)"]; + * f2b <<= source [label="logcb(level, char *msg)"]; * f2b << source [label="true"]; * f2b => source [label="next(cfg, buf, sizeof(buf), false)"]; * f2b << source [label="false"]; @@ -81,7 +89,7 @@ extern cfg_t *create(const char *init); * @param cfg Module handler * @param key Parameter name * @param value Parameter value - * @returns true on success, false on error with setting intenal error buffer + * @returns true on success, false on error */ extern bool config(cfg_t *cfg, const char *key, const char *value); /** @@ -91,24 +99,16 @@ extern bool config(cfg_t *cfg, const char *key, const char *value); */ extern bool ready(cfg_t *cfg); /** - * @brief Returns last error description - * @param cfg Module handler - * @returns Pointer to string with description of last error - * @note Returned pointer not marked with const, because libdl complains, - * but contents on pointer should not be modified or written in any way - */ -extern char *error(cfg_t *cfg); -/** - * @brief Sets the error callback for use in processing + * @brief Sets the log callback * @param cfg Module handler - * @param cb Error callback - * @note Optional, if this function is not called, processing errors will be suppressed + * @param cb Logging callback + * @note Optional, if this function is not called, warnings/errors of module will be suppressed */ -extern void errcb(cfg_t *cfg, void (*cb)(const char *errstr)); +extern void logcb(cfg_t *cfg, void (*cb)(enum loglevel l, const char *msg)); /** * @brief Allocate resources and start processing * @param cfg Module handler - * @returns true on success, false on error with setting intenal error buffer + * @returns true on success, false on error */ extern bool start(cfg_t *cfg); /**