diff --git a/Makefile b/Makefile index 27060ef..d43127d 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ WWW_OWNER = www-data # ############################ SRC := configfile.c event.c helper.c logging.c network.c pidfile.c plugins.c probe.c -SRC += sammler.c sockaddr.c +SRC += sammler.c signals.c sockaddr.c CFLAGS := -O2 -Wall -MMD -fno-stack-protector -I. LDFLAGS := -ldl -rdynamic diff --git a/event.c b/event.c index 2f255c7..9c91b20 100644 --- a/event.c +++ b/event.c @@ -30,6 +30,7 @@ static LIST_HEAD(event_fd_list); static LIST_HEAD(event_timeout_list); +static int leave_loop; struct event_fd { struct list_head list; @@ -198,6 +199,11 @@ void event_remove_timeout(struct event_timeout *entry) entry->flags |= EVENT_DELETE; } +void event_loop_break(void *dummy) +{ + leave_loop = 1; +} + int event_loop(void) { fd_set *fdsets = malloc(sizeof(fd_set) * 2); @@ -206,7 +212,8 @@ int event_loop(void) return -1; } - while (1) { + leave_loop = 0; + while (!leave_loop) { struct timeval timeout, *timeout_p = NULL; if (!list_empty(&event_timeout_list)) { struct timeval now; @@ -247,6 +254,7 @@ int event_loop(void) fd_set *readfds = NULL, *writefds = NULL; struct event_fd *entry, *tmp; + int maxfd = -1; list_for_each_entry_safe(entry, tmp, &event_fd_list, list) { entry->flags &= ~EVENT_NEW; @@ -272,9 +280,11 @@ int event_loop(void) } FD_SET(entry->fd, writefds); } + + maxfd = (entry->fd > maxfd) ? entry->fd : maxfd; } - int i = select(FD_SETSIZE, readfds, writefds, NULL, timeout_p); + int i = select(maxfd +1, readfds, writefds, NULL, timeout_p); if (i <= 0) { /* On error, -1 is returned, and errno is set * appropriately; the sets and timeout become @@ -295,4 +305,5 @@ int event_loop(void) } } free(fdsets); + return 0; } diff --git a/event.h b/event.h index 05ae63f..28150a8 100644 --- a/event.h +++ b/event.h @@ -37,6 +37,7 @@ struct event_timeout * event_add_timeout( void event_remove_timeout(struct event_timeout *entry); +void event_loop_break(void *dummy); int event_loop(void); #endif /* _EVENT_H_ */ diff --git a/logging.c b/logging.c index 7d7bb14..ddc1128 100644 --- a/logging.c +++ b/logging.c @@ -77,11 +77,15 @@ int log_print(int prio, const char *fmt, ...) void log_close(void) { - if (buffer) + if (buffer) { free(buffer); + buffer = NULL; + } - if (log_fd) + if (log_fd) { fclose(log_fd); + log_fd = NULL; + } } int log_init(const char *logfile) @@ -100,6 +104,7 @@ int log_init(const char *logfile) return -1; } + log_prio = LOG_EVERYTIME; return 0; } diff --git a/network.c b/network.c index 4dcc856..f49fd2c 100644 --- a/network.c +++ b/network.c @@ -200,6 +200,7 @@ void net_close(void) { free(entry); } + fwd_buf_len = 0; if (fwd_buf != NULL) free(fwd_buf); } diff --git a/probe.c b/probe.c index d38194f..12a5590 100644 --- a/probe.c +++ b/probe.c @@ -19,6 +19,8 @@ static const char *hostname; int probe_init(void) { const char *fwd_only = config_get_string("global", "forward_only", "false"); + submit_flags = 0; + if (!strncmp(fwd_only, "true", 4)) submit_flags |= SUBMIT_NET_ONLY; diff --git a/sammler.c b/sammler.c index c2dc4d1..84626e3 100644 --- a/sammler.c +++ b/sammler.c @@ -35,6 +35,7 @@ #include "pidfile.h" #include "plugins.h" #include "probe.h" +#include "signals.h" #define DEFAULT_CONFIG "sammler.conf" #define DEFAULT_LOGFILE "sammler.log" @@ -84,7 +85,7 @@ int main(int argc, char *argv[]) } while (code != -1); /* parse config file */ - if (config_parse(config)) + if (config_parse(config) < 0) exit(1); /* check logfile */ @@ -98,7 +99,6 @@ int main(int argc, char *argv[]) } /* start logging */ - const char *logfile = config_get_string("global", "logfile", DEFAULT_LOGFILE); if (log_init(logfile) < 0) exit(1); @@ -112,22 +112,44 @@ int main(int argc, char *argv[]) } } - log_print(LOG_EVERYTIME, "sammler (pid:%d)", getpid()); + signal_init(); + signal_set_callback(SIGUSR1, event_loop_break, NULL); - if (probe_init()) - exit(1); + log_print(LOG_EVERYTIME, "sammler started (pid:%d)", getpid()); - if (net_init()) - exit(1); + while (1) { + if (probe_init()) + break; - if (sammler_rrd_init()) - exit(1); + if (net_init()) + break; + + if (sammler_rrd_init()) + break; + + if (plugin_init()) + break; + + /* exited on restart / SIGUSR1 */ + event_loop(); + + plugin_close(); - if (plugin_init()) { net_close(); - exit(1); + + log_close(); + + config_free(); + + if (config_parse(config) < 0) + break; + + logfile = config_get_string("global", "logfile", DEFAULT_LOGFILE); + if (log_init(logfile) < 0) + break; + + log_print(LOG_EVERYTIME, "sammler restarted (pid:%d) ", getpid()); } - event_loop(); return 0; } diff --git a/signals.c b/signals.c new file mode 100644 index 0000000..9d99acf --- /dev/null +++ b/signals.c @@ -0,0 +1,153 @@ +/*************************************************************************** + * Copyright (C) 05/2009 by Olaf Rempel * + * razzor@kopf-tisch.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; version 2 of the License * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include +#include + +#include +#include + +#include "event.h" +#include "list.h" +#include "logging.h" +#include "signals.h" + +struct signal_entry { + struct list_head list; + int signum; + int deleted; + + void (*callback)(void *privdata); + void *privdata; +}; + +static LIST_HEAD(callback_list); +static int sig_pipe[2]; + +static void sig_handler(int signal) +{ + unsigned char signum = (signal & 0xFF); + write(sig_pipe[1], &signum, 1); +} + +int signal_remove_callback(int signum, int type) +{ + /* mark all old handler for deletion */ + struct signal_entry *search; + list_for_each_entry(search, &callback_list, list) { + if (search->signum == signum) + search->deleted = 1; + } + + struct sigaction sig_action; + + switch (type) { + case SIG_IGNORE: + sig_action.sa_handler = SIG_IGN; + break; + + default: + case SIG_DEFAULT: + sig_action.sa_handler = SIG_DFL; + break; + } + + if (sigaction(signum, &sig_action, NULL) < 0) { + log_print(LOG_WARN, "signal_remove_callback(): sigaction()"); + return -1; + } + + /* trigger remove */ + sig_handler(0); + return 0; +} + +int signal_set_callback(int signum, void (*callback)(void *privdata), void *privdata) +{ + signal_remove_callback(signum, SIG_DEFAULT); + + struct signal_entry *entry = malloc(sizeof(struct signal_entry)); + if (entry == NULL) { + log_print(LOG_WARN, "signal_add_callback(): out of memory"); + return -1; + } + + entry->signum = signum; + entry->deleted = 0; + entry->callback = callback; + entry->privdata = privdata; + list_add_tail(&entry->list, &callback_list); + + struct sigaction sig_action = { + .sa_handler = sig_handler, + }; + + if (sigaction(signum, &sig_action, NULL) < 0) { + log_print(LOG_WARN, "signal_add_callback(): sigaction()"); + list_del(&entry->list); + free(entry); + return -1; + } + + return 0; +} + +static int sig_event(int fd, void *privdata) +{ + unsigned char signum; + int len = read(fd, &signum, 1); + if (len <= 0) { + log_print(LOG_WARN, "sig_event(): read()"); + return -1; + } + + struct signal_entry *search, *tmp; + list_for_each_entry_safe(search, tmp, &callback_list, list) { + if (search->deleted) { + list_del(&search->list); + free(search); + continue; + } + + if (search->signum == signum) + search->callback(search->privdata); + } + + return 0; +} + +int signal_init(void) +{ + if (pipe(sig_pipe) < 0) { + log_print(LOG_ERROR, "signal_init(): pipe()"); + return -1; + } + + if (fcntl(sig_pipe[0], F_SETFD, FD_CLOEXEC) < 0) { + log_print(LOG_WARN, "signal_init(): fcntl(FD_CLOEXEC)"); + return -1; + } + + if (fcntl(sig_pipe[1], F_SETFD, FD_CLOEXEC) < 0) { + log_print(LOG_WARN, "signal_init(): fcntl(FD_CLOEXEC)"); + return -1; + } + + event_add_readfd(NULL, sig_pipe[0], sig_event, NULL); + return 0; +} diff --git a/signals.h b/signals.h new file mode 100644 index 0000000..a6d777c --- /dev/null +++ b/signals.h @@ -0,0 +1,12 @@ +#ifndef _SIGNALS_H +#define _SIGNALS_H + +#define SIG_DEFAULT 0x00 +#define SIG_IGNORE 0x01 + +int signal_remove_callback(int signum, int type); +int signal_set_callback(int signum, void (*callback)(void *privdata), void *privdata); + +int signal_init(void); + +#endif // _SIGNALS_H