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