diff --git a/kronosnetd/Makefile.am b/kronosnetd/Makefile.am index f99af09b..b91e1bbd 100644 --- a/kronosnetd/Makefile.am +++ b/kronosnetd/Makefile.am @@ -1,22 +1,25 @@ MAINTAINERCLEANFILES = Makefile.in noinst_HEADERS = \ cfg.h \ logging.h sbin_PROGRAMS = kronosnetd kronosnetd_SOURCES = \ cfg.c \ main.c \ logging.c kronosnetd_CPPFLAGS = \ -I$(top_srcdir)/libtap \ -I$(top_srcdir)/libknet \ -I$(top_srcdir)/libvty +kronosnetd_CFLAGS = $(LIBQB_CFLAGS) + kronosnetd_LDADD = \ $(top_builddir)/libvty/libvty.a \ $(top_builddir)/libknet/libknet.a \ - $(top_builddir)/libtap/libtap.la + $(top_builddir)/libtap/libtap.la \ + $(LIBQB_LIBS) diff --git a/kronosnetd/logging.c b/kronosnetd/logging.c index 73b37567..2fd561c8 100644 --- a/kronosnetd/logging.c +++ b/kronosnetd/logging.c @@ -1,6 +1,46 @@ #include "config.h" #include "logging.h" -int utils_debug = 0; -int utils_syslog = 0; +void logging_init_defaults(int debug, int daemonize, const char *logfile) +{ + int level = SYSLOGLEVEL; + int32_t filetarget; + + if (debug) { + level = LOG_DEBUG; + } + + qb_log_init(PACKAGE_NAME, SYSLOGFACILITY, level); + + qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE); + if (debug) { + qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP, + LOG_INFO - LOG_DEBUG); + } + + /* + * initialize stderr output only if we are not forking in background + */ + if (!daemonize) { + qb_log_format_set(QB_LOG_STDERR, "%t %N [%p]: %b"); + qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE); + qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, + QB_LOG_FILTER_FUNCTION, "", level); + } + + filetarget = qb_log_file_open(logfile); + qb_log_ctl(filetarget, QB_LOG_CONF_ENABLED, QB_TRUE); + qb_log_format_set(filetarget, "%t %N [%p]: %b"); + qb_log_filter_ctl(filetarget, QB_LOG_FILTER_ADD, + QB_LOG_FILTER_FUNCTION, "", level); + + qb_log_thread_start(); + qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_THREADED, QB_TRUE); + qb_log_ctl(filetarget, QB_LOG_CONF_THREADED, QB_TRUE); +} + +void logging_fini(void) +{ + qb_log_fini(); +} diff --git a/kronosnetd/logging.h b/kronosnetd/logging.h index 3c4596d5..b03247cd 100644 --- a/kronosnetd/logging.h +++ b/kronosnetd/logging.h @@ -1,32 +1,18 @@ -#ifndef __UTILS_H__ -#define __UTILS_H__ - -#include -#include -#include -#include - -extern int utils_debug; -extern int utils_syslog; - -#define log_debug(fmt, args...) \ -do { \ - if (utils_debug) { \ - printf("DEBUG(%s:%i|%s): " fmt "\n", __FILE__, __LINE__, __FUNCTION__, ##args); \ - if (utils_syslog) syslog(LOG_DEBUG, "DEBUG(%s:%i|%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ##args); \ - } \ -} while (0); - -#define log_info(fmt, args...) \ -do { \ - fprintf(stderr, "Notice: " fmt "\n", ##args); \ - if (utils_syslog) syslog(LOG_INFO, fmt, ##args); \ -} while (0); - -#define log_error(fmt, args...) \ -do { \ - fprintf(stderr, "Error: " fmt " (%s)\n", ##args, strerror(errno)); \ - if (utils_syslog) syslog(LOG_ERR, fmt, ##args); \ -} while (0); +#ifndef __LOGGING_H__ +#define __LOGGING_H__ + +#include + +#define log_debug(fmt, args...) qb_log(LOG_DEBUG, "(%s:%i|%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ##args); + +#define log_info(fmt, args...) qb_log(LOG_INFO, fmt, ##args); + +#define log_warn(fmt, args...) qb_log(LOG_WARNING, fmt, ##args); + +#define log_error(fmt, args...) qb_log(LOG_ERR, fmt, ##args); + +void logging_init_defaults(int debug, int daemonize, const char *logfile); + +void logging_fini(void); #endif diff --git a/kronosnetd/main.c b/kronosnetd/main.c index 15835622..9e442715 100644 --- a/kronosnetd/main.c +++ b/kronosnetd/main.c @@ -1,318 +1,321 @@ #include "config.h" #include #include #include #include #include #include #include #include #include #include "cfg.h" #include "vty.h" #include "logging.h" #define LOCKFILE_NAME RUNDIR PACKAGE ".pid" #define OPTION_STRING "hdfVc:l:b:p:" +static int debug = 0; static int daemonize = 1; struct knet_cfg_top knet_cfg_head; -extern int utils_debug; - static void print_usage(void) { printf("Usage:\n\n"); printf(PACKAGE " [options]\n\n"); printf("Options:\n\n"); printf(" -b Bind management VTY to ip_addr (default: all)\n"); printf(" -p Bind management VTY to port (default %d)\n", KNET_VTY_DEFAULT_PORT); printf(" -c Use config file (default "DEFAULT_CONFIG_FILE")\n"); printf(" -l Use log file (default "DEFAULT_LOG_FILE")\n"); printf(" -f Do not fork in background\n"); printf(" -d Enable debugging output\n"); printf(" -h This help\n"); printf(" -V Print program version information\n"); return; } static int read_arguments(int argc, char **argv) { int cont = 1; int optchar; int int_port; while (cont) { optchar = getopt(argc, argv, OPTION_STRING); switch (optchar) { case 'b': knet_cfg_head.vty_ip = strdup(optarg); if (!knet_cfg_head.vty_ip) return -1; break; case 'p': int_port = atoi(optarg); if ((int_port < 0) || (int_port > 65535)) { errno = EINVAL; return -1; } knet_cfg_head.vty_port = strdup(optarg); if (!knet_cfg_head.vty_port) return -1; break; case 'c': knet_cfg_head.conffile = strdup(optarg); if (!knet_cfg_head.conffile) return -1; break; case 'l': knet_cfg_head.logfile = strdup(optarg); if (!knet_cfg_head.logfile) return -1; break; case 'd': - utils_debug = 1; + debug = 1; break; case 'f': daemonize = 0; break; case 'h': print_usage(); exit(EXIT_SUCCESS); break; case 'V': printf(PACKAGE " " PACKAGE_VERSION " (built " __DATE__ " " __TIME__ ")\n"); exit(EXIT_SUCCESS); break; case EOF: cont = 0; break; default: fprintf(stderr, "unknown option: %c\n", optchar); print_usage(); exit(EXIT_FAILURE); break; } } return 0; } static int set_scheduler(void) { struct sched_param sched_param; int err; err = sched_get_priority_max(SCHED_RR); if (err < 0) { log_error("Could not get maximum scheduler priority"); return err; } sched_param.sched_priority = err; err = sched_setscheduler(0, SCHED_RR, &sched_param); if (err < 0) log_error("could not set SCHED_RR priority %d", sched_param.sched_priority); return err; } static void remove_lockfile(void) { unlink(LOCKFILE_NAME); } static int create_lockfile(const char *lockfile) { int fd, value; size_t bufferlen; ssize_t write_out; struct flock lock; char buffer[50]; if ((fd = open(lockfile, O_CREAT | O_WRONLY, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { fprintf(stderr, "Cannot open lockfile [%s], error was [%s]\n", lockfile, strerror(errno)); return -1; } lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; retry_fcntl: if (fcntl(fd, F_SETLK, &lock) < 0) { switch (errno) { case EINTR: goto retry_fcntl; break; case EACCES: case EAGAIN: fprintf(stderr, "Cannot lock lockfile [%s], error was [%s]\n", lockfile, strerror(errno)); break; default: fprintf(stderr, "process is already running\n"); } goto fail_close; } if (ftruncate(fd, 0) < 0) { fprintf(stderr, "Cannot truncate pidfile [%s], error was [%s]\n", lockfile, strerror(errno)); goto fail_close_unlink; } memset(buffer, 0, sizeof(buffer)); snprintf(buffer, sizeof(buffer)-1, "%u\n", getpid()); bufferlen = strlen(buffer); write_out = write(fd, buffer, bufferlen); if ((write_out < 0) || (write_out == 0 && errno)) { fprintf(stderr, "Cannot write pid to pidfile [%s], error was [%s]\n", lockfile, strerror(errno)); goto fail_close_unlink; } if ((write_out == 0) || (write_out < bufferlen)) { fprintf(stderr, "Cannot write pid to pidfile [%s], shortwrite of" "[%zu] bytes, expected [%zu]\n", lockfile, write_out, bufferlen); goto fail_close_unlink; } if ((value = fcntl(fd, F_GETFD, 0)) < 0) { fprintf(stderr, "Cannot get close-on-exec flag from pidfile [%s], " "error was [%s]\n", lockfile, strerror(errno)); goto fail_close_unlink; } value |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, value) < 0) { fprintf(stderr, "Cannot set close-on-exec flag from pidfile [%s], " "error was [%s]\n", lockfile, strerror(errno)); goto fail_close_unlink; } atexit(remove_lockfile); return 0; fail_close_unlink: if (unlink(lockfile)) fprintf(stderr, "Unable to unlink %s\n", lockfile); fail_close: if (close(fd)) fprintf(stderr, "Unable to close %s file descriptor\n", lockfile); return -1; } static void set_cfg_defaults(void) { if (!knet_cfg_head.conffile) knet_cfg_head.conffile = strdup(DEFAULT_CONFIG_FILE); if (!knet_cfg_head.conffile) { fprintf(stderr, "Unable to allocate memory for config file\n"); exit(EXIT_FAILURE); } if (!knet_cfg_head.logfile) knet_cfg_head.logfile = strdup(DEFAULT_LOG_FILE); if (!knet_cfg_head.conffile) { fprintf(stderr, "Unable to allocate memory for log file\n"); exit(EXIT_FAILURE); } if (!knet_cfg_head.vty_ip) knet_cfg_head.vty_ip = strdup("::"); if (!knet_cfg_head.vty_ip) { fprintf(stderr, "Unable to allocate memory for default ip address\n"); exit(EXIT_FAILURE); } if (!knet_cfg_head.vty_port) { char portbuf[8]; memset(&portbuf, 0, sizeof(portbuf)); snprintf(portbuf, sizeof(portbuf), "%d", KNET_VTY_DEFAULT_PORT); knet_cfg_head.vty_port = strdup(portbuf); } if (!knet_cfg_head.vty_port) { fprintf(stderr, "Unable to allocate memory for default port address\n"); exit(EXIT_FAILURE); } } int main(int argc, char **argv) { int err; memset(&knet_cfg_head, 0, sizeof(struct knet_cfg_top)); - utils_syslog=1; - - if (create_lockfile(LOCKFILE_NAME) < 0) { - fprintf(stderr, "Unable to create lockfile\n"); - exit(EXIT_FAILURE); - } - if (read_arguments(argc, argv) < 0) { fprintf(stderr, "Unable to parse options\n"); exit(EXIT_FAILURE); } set_cfg_defaults(); + if (create_lockfile(LOCKFILE_NAME) < 0) { + fprintf(stderr, "Unable to create lockfile\n"); + exit(EXIT_FAILURE); + } + if (daemonize) { if (daemon(0, 0) < 0) { perror("Unable to daemonize"); exit(EXIT_FAILURE); } } + logging_init_defaults(debug, daemonize, knet_cfg_head.logfile); log_info(PACKAGE " version " VERSION); err = set_scheduler(); if (err < 0) goto out; - if (knet_vty_main_loop() < 0) + err = knet_vty_main_loop(); + if (err < 0) log_error("Detected fatal error in main loop"); out: + if (knet_cfg_head.logfile) + free(knet_cfg_head.logfile); if (knet_cfg_head.conffile) free(knet_cfg_head.conffile); if (knet_cfg_head.vty_ip) free(knet_cfg_head.vty_ip); if (knet_cfg_head.vty_port) free(knet_cfg_head.vty_port); - return 0; + logging_fini(); + + return err; }