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