summaryrefslogtreecommitdiffabout
path: root/src/dudki.cc
Unidiff
Diffstat (limited to 'src/dudki.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--src/dudki.cc5
1 files changed, 5 insertions, 0 deletions
diff --git a/src/dudki.cc b/src/dudki.cc
index 3c50e56..b769109 100644
--- a/src/dudki.cc
+++ b/src/dudki.cc
@@ -1,244 +1,249 @@
1#include <unistd.h> 1#include <unistd.h>
2#include <signal.h> 2#include <signal.h>
3#include <syslog.h> 3#include <syslog.h>
4#include <iostream> 4#include <iostream>
5#include <fstream> 5#include <fstream>
6#include <stdexcept> 6#include <stdexcept>
7using namespace std; 7using namespace std;
8#include "configuration.h" 8#include "configuration.h"
9#include "util.h" 9#include "util.h"
10 10
11#include "config.h" 11#include "config.h"
12#ifdef HAVE_GETOPT_H 12#ifdef HAVE_GETOPT_H
13# include <getopt.h> 13# include <getopt.h>
14#endif 14#endif
15 15
16#ifndef DEFAULT_CONF_FILE 16#ifndef DEFAULT_CONF_FILE
17# define DEFAULT_CONF_FILE "/etc/dudki.conf" 17# define DEFAULT_CONF_FILE "/etc/dudki.conf"
18#endif 18#endif
19 19
20#define PHEADER PACKAGE " Version " VERSION 20#define PHEADER PACKAGE " Version " VERSION
21#define PCOPY "Copyright (c) 2004 Klever Group" 21#define PCOPY "Copyright (c) 2004 Klever Group"
22 22
23bool finishing = false; 23bool finishing = false;
24static char **_argv = NULL; 24static char **_argv = NULL;
25 25
26static void lethal_signal_handler(int signum) { 26static void lethal_signal_handler(int signum) {
27 syslog(LOG_NOTICE,"Lethal signal received. Terminating."); 27 syslog(LOG_NOTICE,"Lethal signal received. Terminating.");
28 finishing = true; 28 finishing = true;
29} 29}
30static void sighup_handler(int signum) { 30static void sighup_handler(int signum) {
31 syslog(LOG_NOTICE,"SUGHUP received, reloading."); 31 syslog(LOG_NOTICE,"SUGHUP received, reloading.");
32 execvp(_argv[0],_argv); 32 execvp(_argv[0],_argv);
33} 33}
34 34
35void check_herd(configuration& config) { 35void check_herd(configuration& config) {
36 for(processes_t::iterator i=config.processes.begin();i!=config.processes.end();++i) 36 for(processes_t::iterator i=config.processes.begin();i!=config.processes.end();++i)
37 i->second.check(i->first,config); 37 i->second.check(i->first,config);
38} 38}
39 39
40void signal_self(const configuration& config,int signum) { 40void signal_self(const configuration& config,int signum) {
41 ifstream pids(config.pidfile.c_str(),ios::in); 41 ifstream pids(config.pidfile.c_str(),ios::in);
42 if(!pids) 42 if(!pids)
43 throw runtime_error("Can't detect running instance"); 43 throw runtime_error("Can't detect running instance");
44 pid_t pid = 0; 44 pid_t pid = 0;
45 pids >> pid; 45 pids >> pid;
46 if(!pid) 46 if(!pid)
47 throw runtime_error("Can't detect running instance"); 47 throw runtime_error("Can't detect running instance");
48 if(pid==getpid()) 48 if(pid==getpid())
49 throw 0; 49 throw 0;
50 if(kill(pid,signum)) 50 if(kill(pid,signum))
51 throw runtime_error("Failed to signal running instance"); 51 throw runtime_error("Failed to signal running instance");
52} 52}
53 53
54int main(int argc,char **argv) { 54int main(int argc,char **argv) {
55 try { 55 try {
56 _argv = new char*[argc+1]; 56 _argv = new char*[argc+1];
57 if(!_argv) 57 if(!_argv)
58 throw runtime_error("memory allocation problem at the very start"); 58 throw runtime_error("memory allocation problem at the very start");
59 memmove(_argv,argv,sizeof(*_argv)*(argc+1)); 59 memmove(_argv,argv,sizeof(*_argv)*(argc+1));
60 string config_file = DEFAULT_CONF_FILE; 60 string config_file = DEFAULT_CONF_FILE;
61 enum { 61 enum {
62 op_default, 62 op_default,
63 op_work, 63 op_work,
64 op_hup, 64 op_hup,
65 op_term, 65 op_term,
66 op_check, 66 op_check,
67 op_ensure, 67 op_ensure,
68 op_test 68 op_test
69 } op = op_default; 69 } op = op_default;
70 while(true) { 70 while(true) {
71 #defineSHORTOPTSTRING "f:hVLrkcet" 71 #defineSHORTOPTSTRING "f:hVLrkcet"
72#ifdef HAVE_GETOPT_LONG 72#ifdef HAVE_GETOPT_LONG
73 static struct option opts[] = { 73 static struct option opts[] = {
74 { "help", no_argument, 0, 'h' }, 74 { "help", no_argument, 0, 'h' },
75 { "usage", no_argument, 0, 'h' }, 75 { "usage", no_argument, 0, 'h' },
76 { "version", no_argument, 0, 'V' }, 76 { "version", no_argument, 0, 'V' },
77 { "license", no_argument, 0, 'L' }, 77 { "license", no_argument, 0, 'L' },
78 { "config", required_argument, 0, 'f' }, 78 { "config", required_argument, 0, 'f' },
79 { "kill", no_argument, 0, 'k' }, 79 { "kill", no_argument, 0, 'k' },
80 { "reload", no_argument, 0, 'r' }, 80 { "reload", no_argument, 0, 'r' },
81 { "check", no_argument, 0, 'c' }, 81 { "check", no_argument, 0, 'c' },
82 { "ensure", no_argument, 0, 'e' }, 82 { "ensure", no_argument, 0, 'e' },
83 { "test", no_argument, 0, 't' }, 83 { "test", no_argument, 0, 't' },
84 { NULL, 0, 0, 0 } 84 { NULL, 0, 0, 0 }
85 }; 85 };
86 int c = getopt_long(argc,argv,SHORTOPTSTRING,opts,NULL); 86 int c = getopt_long(argc,argv,SHORTOPTSTRING,opts,NULL);
87#else /* !HAVE_GETOPT_LONG */ 87#else /* !HAVE_GETOPT_LONG */
88 int c = getopt(argc,argv,SHORTOPTSTRING); 88 int c = getopt(argc,argv,SHORTOPTSTRING);
89#endif /* /HAVE_GETOPT_LONG */ 89#endif /* /HAVE_GETOPT_LONG */
90 if(c==-1) 90 if(c==-1)
91 break; 91 break;
92 switch(c) { 92 switch(c) {
93 case 'h': 93 case 'h':
94 cerr << PHEADER << endl 94 cerr << PHEADER << endl
95 << PCOPY << endl << endl << 95 << PCOPY << endl << endl <<
96#ifdef HAVE_GETOPT_LONG 96#ifdef HAVE_GETOPT_LONG
97 " -h, --help\n" 97 " -h, --help\n"
98 " --usage display this text\n" 98 " --usage display this text\n"
99 " -V, --version display version number\n" 99 " -V, --version display version number\n"
100 " -L, --license show license\n" 100 " -L, --license show license\n"
101 " -f filename, --config=filename\n" 101 " -f filename, --config=filename\n"
102 " specify the configuration file to use\n" 102 " specify the configuration file to use\n"
103 "\n" 103 "\n"
104 " -k, --kill stop running instance\n" 104 " -k, --kill stop running instance\n"
105 " -r, --reload reload running instance (send SIGHUP)\n" 105 " -r, --reload reload running instance (send SIGHUP)\n"
106 " -c, --check check if dudki is running\n" 106 " -c, --check check if dudki is running\n"
107 " -e, --ensure ensure that dudki is running\n" 107 " -e, --ensure ensure that dudki is running\n"
108 " -t, --test test configuration file and exit" 108 " -t, --test test configuration file and exit"
109#else /* !HAVE_GETOPT_LONG */ 109#else /* !HAVE_GETOPT_LONG */
110 " -h display this text\n" 110 " -h display this text\n"
111 " -V display version number\n" 111 " -V display version number\n"
112 " -L show license\n" 112 " -L show license\n"
113 " -f filename specify the configuration file to use\n" 113 " -f filename specify the configuration file to use\n"
114 "\n" 114 "\n"
115 " -k stop running instance\n" 115 " -k stop running instance\n"
116 " -r reload running instance (send SIGHUP)\n" 116 " -r reload running instance (send SIGHUP)\n"
117 " -c check if dudki is running\n" 117 " -c check if dudki is running\n"
118 " -e ensure that dudki is running\n" 118 " -e ensure that dudki is running\n"
119 " -t test configuration file and exit" 119 " -t test configuration file and exit"
120#endif /* /HAVE_GETOPT_LONG */ 120#endif /* /HAVE_GETOPT_LONG */
121 << endl; 121 << endl;
122 exit(0); 122 exit(0);
123 break; 123 break;
124 case 'V': 124 case 'V':
125 cerr << VERSION << endl; 125 cerr << VERSION << endl;
126 exit(0); 126 exit(0);
127 break; 127 break;
128 case 'L': 128 case 'L':
129 extern const char *COPYING; 129 extern const char *COPYING;
130 cerr << COPYING << endl; 130 cerr << COPYING << endl;
131 exit(0); 131 exit(0);
132 break; 132 break;
133 case 'f': 133 case 'f':
134 config_file = optarg; 134 config_file = optarg;
135 break; 135 break;
136 case 'k': 136 case 'k':
137 if(op!=op_default) { 137 if(op!=op_default) {
138 cerr << "Can't obey two or more orders at once" << endl; 138 cerr << "Can't obey two or more orders at once" << endl;
139 exit(1); 139 exit(1);
140 } 140 }
141 op = op_term; 141 op = op_term;
142 break; 142 break;
143 case 'r': 143 case 'r':
144 if(op!=op_default) { 144 if(op!=op_default) {
145 cerr << "Can't obey two or more orders at once" << endl; 145 cerr << "Can't obey two or more orders at once" << endl;
146 exit(1); 146 exit(1);
147 } 147 }
148 op = op_hup; 148 op = op_hup;
149 break; 149 break;
150 case 'c': 150 case 'c':
151 if(op!=op_default) { 151 if(op!=op_default) {
152 cerr << "Can't obey two or more orders at once" << endl; 152 cerr << "Can't obey two or more orders at once" << endl;
153 exit(1); 153 exit(1);
154 } 154 }
155 op = op_check; 155 op = op_check;
156 break; 156 break;
157 case 'e': 157 case 'e':
158 if(op!=op_default) { 158 if(op!=op_default) {
159 cerr << "Can't obey two or more orders at once" << endl; 159 cerr << "Can't obey two or more orders at once" << endl;
160 exit(1); 160 exit(1);
161 } 161 }
162 op = op_ensure; 162 op = op_ensure;
163 break; 163 break;
164 case 't': 164 case 't':
165 if(op!=op_default) { 165 if(op!=op_default) {
166 cerr << "Can't obey two or more orders at once" << endl; 166 cerr << "Can't obey two or more orders at once" << endl;
167 exit(1); 167 exit(1);
168 } 168 }
169 op = op_test; 169 op = op_test;
170 break; 170 break;
171 default: 171 default:
172 cerr << "Huh??" << endl; 172 cerr << "Huh??" << endl;
173 exit(1); 173 exit(1);
174 break; 174 break;
175 } 175 }
176 } 176 }
177 const char *sid = *argv; 177 const char *sid = *argv;
178 const char *t; 178 const char *t;
179 while(t = index(sid,'/')) { 179 while(t = index(sid,'/')) {
180 sid = t; sid++; 180 sid = t; sid++;
181 } 181 }
182 openlog(sid,LOG_CONS|LOG_PERROR|LOG_PID,LOG_DAEMON); 182 openlog(sid,LOG_CONS|LOG_PERROR|LOG_PID,LOG_DAEMON);
183 configuration config; 183 configuration config;
184 config.parse(config_file); 184 config.parse(config_file);
185 switch(op) { 185 switch(op) {
186 case op_test: 186 case op_test:
187 cerr << "Configuration OK" << endl; 187 cerr << "Configuration OK" << endl;
188 break; 188 break;
189 case op_hup: 189 case op_hup:
190 signal_self(config,SIGHUP); 190 signal_self(config,SIGHUP);
191 break; 191 break;
192 case op_term: 192 case op_term:
193 signal_self(config,SIGTERM); 193 signal_self(config,SIGTERM);
194 break; 194 break;
195 case op_check: 195 case op_check:
196 try{ 196 try{
197 signal_self(config,0); 197 signal_self(config,0);
198 exit(0); 198 exit(0);
199 }catch(exception& e) { 199 }catch(exception& e) {
200 exit(1); 200 exit(1);
201 } 201 }
202 case op_ensure: 202 case op_ensure:
203 try { 203 try {
204 signal_self(config,0); 204 signal_self(config,0);
205 break; 205 break;
206 }catch(exception& e) { 206 }catch(exception& e) {
207 syslog(LOG_NOTICE,"The dudki process is down, taking its place"); 207 syslog(LOG_NOTICE,"The dudki process is down, taking its place");
208 config.daemonize = true; 208 config.daemonize = true;
209 }catch(int zero) { 209 }catch(int zero) {
210 // we throw zero in case we're ensuring that this very process is running. 210 // we throw zero in case we're ensuring that this very process is running.
211 // we don't have to daemonize if we're daemonic. 211 // we don't have to daemonize if we're daemonic.
212 config.daemonize = false; 212 config.daemonize = false;
213 } 213 }
214 case op_default: 214 case op_default:
215 case op_work: 215 case op_work:
216 { 216 {
217 if(config.daemonize) { 217 if(config.daemonize) {
218 pid_t pf = fork(); 218 pid_t pf = fork();
219 if(pf<0) 219 if(pf<0)
220 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to fork()"); 220 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to fork()");
221 if(pf) { 221 if(pf) {
222 _exit(0); 222 _exit(0);
223 } 223 }
224 } 224 }
225 pid_file pidfile; 225 pid_file pidfile;
226 pidfile.set(config.pidfile); 226 pidfile.set(config.pidfile);
227 signal(SIGINT,lethal_signal_handler); 227 signal(SIGINT,lethal_signal_handler);
228 signal(SIGABRT,lethal_signal_handler); 228 signal(SIGABRT,lethal_signal_handler);
229 signal(SIGTERM,lethal_signal_handler); 229 signal(SIGTERM,lethal_signal_handler);
230 signal(SIGHUP,sighup_handler); 230 signal(SIGHUP,sighup_handler);
231 sigset_t sset;
232 sigemptyset(&sset);
233 sigaddset(&sset,SIGINT); sigaddset(&sset,SIGABRT);
234 sigaddset(&sset,SIGTERM); sigaddset(&sset,SIGHUP);
235 sigprocmask(SIG_UNBLOCK,&sset,NULL);
231 while(!finishing) { 236 while(!finishing) {
232 check_herd(config); 237 check_herd(config);
233 sleep(config.check_interval); 238 sleep(config.check_interval);
234 } 239 }
235 } 240 }
236 break; 241 break;
237 default: 242 default:
238 throw runtime_error(string(__PRETTY_FUNCTION__)+": internal error"); 243 throw runtime_error(string(__PRETTY_FUNCTION__)+": internal error");
239 } 244 }
240 }catch(exception& e) { 245 }catch(exception& e) {
241 cerr << "Oops: " << e.what() << endl; 246 cerr << "Oops: " << e.what() << endl;
242 return 1; 247 return 1;
243 } 248 }
244} 249}