summaryrefslogtreecommitdiffabout
path: root/src/dudki.cc
Side-by-side diff
Diffstat (limited to 'src/dudki.cc') (more/less context) (show whitespace changes)
-rw-r--r--src/dudki.cc244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/dudki.cc b/src/dudki.cc
new file mode 100644
index 0000000..3c50e56
--- a/dev/null
+++ b/src/dudki.cc
@@ -0,0 +1,244 @@
+#include <unistd.h>
+#include <signal.h>
+#include <syslog.h>
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+using namespace std;
+#include "configuration.h"
+#include "util.h"
+
+#include "config.h"
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#ifndef DEFAULT_CONF_FILE
+# define DEFAULT_CONF_FILE "/etc/dudki.conf"
+#endif
+
+#define PHEADER PACKAGE " Version " VERSION
+#define PCOPY "Copyright (c) 2004 Klever Group"
+
+bool finishing = false;
+static char **_argv = NULL;
+
+static void lethal_signal_handler(int signum) {
+ syslog(LOG_NOTICE,"Lethal signal received. Terminating.");
+ finishing = true;
+}
+static void sighup_handler(int signum) {
+ syslog(LOG_NOTICE,"SUGHUP received, reloading.");
+ execvp(_argv[0],_argv);
+}
+
+void check_herd(configuration& config) {
+ for(processes_t::iterator i=config.processes.begin();i!=config.processes.end();++i)
+ i->second.check(i->first,config);
+}
+
+void signal_self(const configuration& config,int signum) {
+ ifstream pids(config.pidfile.c_str(),ios::in);
+ if(!pids)
+ throw runtime_error("Can't detect running instance");
+ pid_t pid = 0;
+ pids >> pid;
+ if(!pid)
+ throw runtime_error("Can't detect running instance");
+ if(pid==getpid())
+ throw 0;
+ if(kill(pid,signum))
+ throw runtime_error("Failed to signal running instance");
+}
+
+int main(int argc,char **argv) {
+ try {
+ _argv = new char*[argc+1];
+ if(!_argv)
+ throw runtime_error("memory allocation problem at the very start");
+ memmove(_argv,argv,sizeof(*_argv)*(argc+1));
+ string config_file = DEFAULT_CONF_FILE;
+ enum {
+ op_default,
+ op_work,
+ op_hup,
+ op_term,
+ op_check,
+ op_ensure,
+ op_test
+ } op = op_default;
+ while(true) {
+#define SHORTOPTSTRING "f:hVLrkcet"
+#ifdef HAVE_GETOPT_LONG
+ static struct option opts[] = {
+ { "help", no_argument, 0, 'h' },
+ { "usage", no_argument, 0, 'h' },
+ { "version", no_argument, 0, 'V' },
+ { "license", no_argument, 0, 'L' },
+ { "config", required_argument, 0, 'f' },
+ { "kill", no_argument, 0, 'k' },
+ { "reload", no_argument, 0, 'r' },
+ { "check", no_argument, 0, 'c' },
+ { "ensure", no_argument, 0, 'e' },
+ { "test", no_argument, 0, 't' },
+ { NULL, 0, 0, 0 }
+ };
+ int c = getopt_long(argc,argv,SHORTOPTSTRING,opts,NULL);
+#else /* !HAVE_GETOPT_LONG */
+ int c = getopt(argc,argv,SHORTOPTSTRING);
+#endif /* /HAVE_GETOPT_LONG */
+ if(c==-1)
+ break;
+ switch(c) {
+ case 'h':
+ cerr << PHEADER << endl
+ << PCOPY << endl << endl <<
+#ifdef HAVE_GETOPT_LONG
+ " -h, --help\n"
+ " --usage display this text\n"
+ " -V, --version display version number\n"
+ " -L, --license show license\n"
+ " -f filename, --config=filename\n"
+ " specify the configuration file to use\n"
+ "\n"
+ " -k, --kill stop running instance\n"
+ " -r, --reload reload running instance (send SIGHUP)\n"
+ " -c, --check check if dudki is running\n"
+ " -e, --ensure ensure that dudki is running\n"
+ " -t, --test test configuration file and exit"
+#else /* !HAVE_GETOPT_LONG */
+ " -h display this text\n"
+ " -V display version number\n"
+ " -L show license\n"
+ " -f filename specify the configuration file to use\n"
+ "\n"
+ " -k stop running instance\n"
+ " -r reload running instance (send SIGHUP)\n"
+ " -c check if dudki is running\n"
+ " -e ensure that dudki is running\n"
+ " -t test configuration file and exit"
+#endif /* /HAVE_GETOPT_LONG */
+ << endl;
+ exit(0);
+ break;
+ case 'V':
+ cerr << VERSION << endl;
+ exit(0);
+ break;
+ case 'L':
+ extern const char *COPYING;
+ cerr << COPYING << endl;
+ exit(0);
+ break;
+ case 'f':
+ config_file = optarg;
+ break;
+ case 'k':
+ if(op!=op_default) {
+ cerr << "Can't obey two or more orders at once" << endl;
+ exit(1);
+ }
+ op = op_term;
+ break;
+ case 'r':
+ if(op!=op_default) {
+ cerr << "Can't obey two or more orders at once" << endl;
+ exit(1);
+ }
+ op = op_hup;
+ break;
+ case 'c':
+ if(op!=op_default) {
+ cerr << "Can't obey two or more orders at once" << endl;
+ exit(1);
+ }
+ op = op_check;
+ break;
+ case 'e':
+ if(op!=op_default) {
+ cerr << "Can't obey two or more orders at once" << endl;
+ exit(1);
+ }
+ op = op_ensure;
+ break;
+ case 't':
+ if(op!=op_default) {
+ cerr << "Can't obey two or more orders at once" << endl;
+ exit(1);
+ }
+ op = op_test;
+ break;
+ default:
+ cerr << "Huh??" << endl;
+ exit(1);
+ break;
+ }
+ }
+ const char *sid = *argv;
+ const char *t;
+ while(t = index(sid,'/')) {
+ sid = t; sid++;
+ }
+ openlog(sid,LOG_CONS|LOG_PERROR|LOG_PID,LOG_DAEMON);
+ configuration config;
+ config.parse(config_file);
+ switch(op) {
+ case op_test:
+ cerr << "Configuration OK" << endl;
+ break;
+ case op_hup:
+ signal_self(config,SIGHUP);
+ break;
+ case op_term:
+ signal_self(config,SIGTERM);
+ break;
+ case op_check:
+ try{
+ signal_self(config,0);
+ exit(0);
+ }catch(exception& e) {
+ exit(1);
+ }
+ case op_ensure:
+ try {
+ signal_self(config,0);
+ break;
+ }catch(exception& e) {
+ syslog(LOG_NOTICE,"The dudki process is down, taking its place");
+ config.daemonize = true;
+ }catch(int zero) {
+ // we throw zero in case we're ensuring that this very process is running.
+ // we don't have to daemonize if we're daemonic.
+ config.daemonize = false;
+ }
+ case op_default:
+ case op_work:
+ {
+ if(config.daemonize) {
+ pid_t pf = fork();
+ if(pf<0)
+ throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to fork()");
+ if(pf) {
+ _exit(0);
+ }
+ }
+ pid_file pidfile;
+ pidfile.set(config.pidfile);
+ signal(SIGINT,lethal_signal_handler);
+ signal(SIGABRT,lethal_signal_handler);
+ signal(SIGTERM,lethal_signal_handler);
+ signal(SIGHUP,sighup_handler);
+ while(!finishing) {
+ check_herd(config);
+ sleep(config.check_interval);
+ }
+ }
+ break;
+ default:
+ throw runtime_error(string(__PRETTY_FUNCTION__)+": internal error");
+ }
+ }catch(exception& e) {
+ cerr << "Oops: " << e.what() << endl;
+ return 1;
+ }
+}