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