diff --git a/include/monitor_conf.h b/include/monitor_conf.h new file mode 100644 index 0000000..b98b929 --- /dev/null +++ b/include/monitor_conf.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 Benoit Masson (yahoo@perenite.com) + * + * 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; either version 2 of the + * License, or (at your option) any later version. + * + * 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. + */ + +#ifndef MONITORCONF_H_ +#define MONITORCONF_H_ + +#include "stdbool.h" + +unsigned int monitorConf_init(const char *config_file); +void monitorConf_close(void); +bool monitorConf_hasChanged(void); + +#endif /* JSON_H_ */ diff --git a/src/Makefile.am b/src/Makefile.am index 16fb35e..6d96a1f 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,6 +18,7 @@ automatic_SOURCES = \ $(top_srcdir)/src/file.c \ $(top_srcdir)/src/json.c \ $(top_srcdir)/src/list.c \ + $(top_srcdir)/src/monitor_conf.c \ $(top_srcdir)/src/output.c \ $(top_srcdir)/src/filters.c \ $(top_srcdir)/src/prowl.c \ @@ -42,6 +43,7 @@ noinst_HEADERS = \ $(top_srcdir)/include/file.h \ $(top_srcdir)/include/json.h \ $(top_srcdir)/include/list.h \ + $(top_srcdir)/include/monitor_conf.h \ $(top_srcdir)/include/output.h \ $(top_srcdir)/include/filters.h \ $(top_srcdir)/include/prowl.h \ diff --git a/src/automatic.c b/src/automatic.c index ae95da7..36b3a1a 100644 --- a/src/automatic.c +++ b/src/automatic.c @@ -60,6 +60,7 @@ #include "version.h" #include "web.h" #include "xml_parser.h" +#include "monitor_conf.h" PRIVATE char AutoConfigFile[MAXPATHLEN + 1]; PRIVATE void session_free(auto_handle *as); @@ -69,17 +70,19 @@ PRIVATE bool closing = false; PRIVATE bool nofork = AM_DEFAULT_NOFORK; PRIVATE bool isRunning = false; PRIVATE bool seenHUP = false; +PRIVATE bool monitorConf = false; /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// PRIVATE void usage(void) { - printf("usage: automatic [-fh] [-v level] [-l logfile] [-c file]\n" + printf("usage: automatic [-fhn] [-v level] [-l logfile] [-c file]\n" "\n" "Automatic %s\n" "\n" " -f --nodeamon Run in the foreground and log to stderr\n" " -h --help Display this message\n" + " -n --config-monitor Monitor config file changes\n" " -v --verbose Set output level to (default=1)\n" " -c --configfile Path to configuration file\n" " -o --once Quit Automatic after first check of RSS feeds\n" @@ -92,20 +95,21 @@ PRIVATE void usage(void) { /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// -PRIVATE void readargs(int argc, char ** argv, char **c_file, char** logfile, char **xmlfile, +PRIVATE void readargs(int argc, char ** argv, char **c_file, bool * monitorConf, char** logfile, char **xmlfile, bool * nofork, uint8_t * verbose, uint8_t * once, uint8_t * append_log, uint8_t * match_only) { - char optstr[] = "afhv:c:l:ox:m"; + char optstr[] = "anfhv:c:l:ox:m"; struct option longopts[] = { - { "verbose", required_argument, NULL, 'v' }, - { "nodaemon", no_argument, NULL, 'f' }, - { "help", no_argument, NULL, 'h' }, - { "configfile", required_argument, NULL, 'c' }, - { "once", no_argument, NULL, 'o' }, - { "logfile", required_argument, NULL, 'l' }, - { "append-log", no_argument, NULL, 'a' }, - { "xml", required_argument, NULL, 'x' }, - { "match-only", no_argument, NULL, 'm' }, + { "verbose", required_argument, NULL, 'v' }, + { "nodaemon", no_argument, NULL, 'f' }, + { "help", no_argument, NULL, 'h' }, + { "config-monitor", no_argument, NULL, 'n' }, + { "configfile", required_argument, NULL, 'c' }, + { "once", no_argument, NULL, 'o' }, + { "logfile", required_argument, NULL, 'l' }, + { "append-log", no_argument, NULL, 'a' }, + { "xml", required_argument, NULL, 'x' }, + { "match-only", no_argument, NULL, 'm' }, { NULL, 0, NULL, 0 } }; int opt; @@ -120,6 +124,9 @@ PRIVATE void readargs(int argc, char ** argv, char **c_file, char** logfile, cha case 'f': *nofork = true; break; + case 'n': + *monitorConf = true; + break; case 'c': *c_file = optarg; break; @@ -154,6 +161,7 @@ PRIVATE void shutdown_daemon(auto_handle *as) { } session_free(as); SessionID_free(); + monitorConf_close(); log_close(); exit(EXIT_SUCCESS); } @@ -728,7 +736,7 @@ int main(int argc, char **argv) { */ log_init(NULL, verbose, 0); - readargs(argc, argv, &config_file, &logfile, &xmlfile, &nofork, &verbose, &once, &append_log, &match_only); + readargs(argc, argv, &config_file, &monitorConf, &logfile, &xmlfile, &nofork, &verbose, &once, &append_log, &match_only); /* reinitialize the logging with the values from the command line */ log_init(logfile, verbose, append_log); @@ -770,6 +778,12 @@ int main(int argc, char **argv) { dbg_printft( P_MSG, "Daemon started"); } + if (monitorConf) { + if (monitorConf_init(config_file) != 0) { + monitorConf = false; /* avoid testing inotify if not able to initialize */ + } + } + dbg_printf(P_INFO, "verbose level: %d", verbose); dbg_printf(P_INFO, "foreground mode: %s", nofork == true ? "yes" : "no"); @@ -800,6 +814,11 @@ int main(int argc, char **argv) { isRunning = false; + if (monitorConf && monitorConf_hasChanged()) { + /* consider a config file change is a SIGHUP signal */ + seenHUP = true; + } + if(seenHUP) { signal_handler(SIGHUP); } diff --git a/src/monitor_conf.c b/src/monitor_conf.c new file mode 100644 index 0000000..8fea96b --- /dev/null +++ b/src/monitor_conf.c @@ -0,0 +1,125 @@ +/* $Id$ + * $Name$ + * $ProjectName$ + */ + +/** + * @file monitor_conf.c + * + * Provides output functionality. + */ + +/* Copyright (C) 2015 Benoit Masson (yahoo@perenite.com) + * + * 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; either version 2 of the + * License, or (at your option) any later version. + * + * 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 +#include +#include + +#include "utils.h" +#include "output.h" +#include "monitor_conf.h" + +#define MAX_EVENTS 1024 /*Max. number of events to process at one go*/ +#define LEN_NAME 16 /*Assuming that the length of the filename won't exceed 16 bytes*/ +#define EVENT_SIZE ( sizeof (struct inotify_event) ) /*size of one event*/ +#define BUF_LEN ( MAX_EVENTS * ( EVENT_SIZE + LEN_NAME )) /*buffer to store the data of events*/ + +PRIVATE int fd = 0; +PRIVATE int wd = 0; +PRIVATE char *buffer; + +unsigned int monitorConf_init(const char *config_file) { + + /* check fd, wd are null if not close them */ + if (fd || wd ) { + monitorConf_close(); + } + + dbg_printf(P_DBG, "Monitor Conf init"); + + fd = inotify_init(); + if ( fd < 0 ) { + dbg_printf(P_ERROR, "Couldn't initialize inotify"); + return 1; + } + + /* non blocking inotify */ + if (fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK) <0 ) { + dbg_printf(P_ERROR, "Couldn't initialize non blocking IO inotify"); + monitorConf_close(); + return 1; + } + + /* add watch to config directory */ + wd = inotify_add_watch(fd, config_file, IN_CREATE | IN_MODIFY | IN_DELETE); + + if (wd == -1) { + dbg_printf(P_ERROR, "Couldn't add watch to %s\n",config_file); + } else { + dbg_printf(P_MSG, "Watching: %s\n",config_file); + } + + /* inititialize buffer for inotify read events */ + buffer = (char *) malloc(BUF_LEN); + + return 0; +} + +void monitorConf_close(void) { + dbg_printf(P_DBG, "Monitor Conf close"); + if (fd || wd) { + inotify_rm_watch(fd, wd); + } + free(buffer); +} + +bool monitorConf_hasChanged(void) { + bool changed = false; + struct inotify_event *event = NULL; + int length = 0; + int i = 0; + + dbg_printf(P_DBG, "Monitor file conf check haschanged"); + + if ( fd ) { + dbg_printf(P_DBG, "Monitor file conf fd > 0"); + + dbg_printf(P_DBG, "Monitor file conf before read"); + length = read( fd, buffer, BUF_LEN ); + dbg_printf(P_DBG, "Monitor file conf after read, length:%d", length); + + if (length >0) { /* >0 include both no data & EAGAIN error for non-blocking */ + while ( i < length ) { + event = ( struct inotify_event * ) &buffer[ i ]; + dbg_printf(P_DBG, "Monitor file conf event->len:%d , event->mask:%d", event->len, event->mask); + if ( event->mask & IN_MODIFY) { + dbg_printf(P_INFO2, "Monitor file conf MODIFY event detected"); + changed = true; + } + i += EVENT_SIZE + event->len; + } + } + } + + dbg_printf(P_DBG, "Monitor file conf check haschanged end"); + return changed; +}