summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2004-07-21 20:59:33 (UTC)
committer Michael Krelin <hacker@klever.net>2004-07-21 20:59:33 (UTC)
commit4b2d32eca61f62bfd1370fd64254514152ecd23c (patch) (unidiff)
treeab7d32f4b1572a33d1384d3127495feaea3978b4
parent5e437102c59f4544e3803598eabcb643d403272d (diff)
downloaddudki-4b2d32eca61f62bfd1370fd64254514152ecd23c.zip
dudki-4b2d32eca61f62bfd1370fd64254514152ecd23c.tar.gz
dudki-4b2d32eca61f62bfd1370fd64254514152ecd23c.tar.bz2
more civilized restart, bumped up version.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--NEWS3
-rw-r--r--configure.ac2
-rw-r--r--src/dudki.cc5
3 files changed, 8 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index efd0c31..b6a3774 100644
--- a/NEWS
+++ b/NEWS
@@ -1,2 +1,5 @@
10.1
2 - initgroups() before executing RestartCommand.
3 - more civilized restart.
10.0 40.0
2 - Initial release. 5 - Initial release.
diff --git a/configure.ac b/configure.ac
index 8a2a10b..8521a34 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,38 +1,38 @@
1AC_INIT([dudki], [0.0], [dudki-bugs@klever.net]) 1AC_INIT([dudki], [0.1], [dudki-bugs@klever.net])
2AC_CONFIG_SRCDIR([src/dudki.cc]) 2AC_CONFIG_SRCDIR([src/dudki.cc])
3AC_CONFIG_HEADER([config.h]) 3AC_CONFIG_HEADER([config.h])
4AM_INIT_AUTOMAKE([dist-bzip2]) 4AM_INIT_AUTOMAKE([dist-bzip2])
5 5
6AC_PROG_CXX 6AC_PROG_CXX
7AC_PROG_CC 7AC_PROG_CC
8 8
9AC_HEADER_SYS_WAIT 9AC_HEADER_SYS_WAIT
10AC_CHECK_HEADERS([syslog.h unistd.h getopt.h]) 10AC_CHECK_HEADERS([syslog.h unistd.h getopt.h])
11 11
12AC_HEADER_STDBOOL 12AC_HEADER_STDBOOL
13AC_C_CONST 13AC_C_CONST
14AC_TYPE_UID_T 14AC_TYPE_UID_T
15AC_TYPE_PID_T 15AC_TYPE_PID_T
16 16
17AC_FUNC_FORK 17AC_FUNC_FORK
18AC_HEADER_STDC 18AC_HEADER_STDC
19AC_TYPE_SIGNAL 19AC_TYPE_SIGNAL
20AC_CHECK_FUNCS([dup2 strtol]) 20AC_CHECK_FUNCS([dup2 strtol])
21AC_CHECK_FUNC([getopt_long],[ 21AC_CHECK_FUNC([getopt_long],[
22 AC_DEFINE([HAVE_GETOPT_LONG],[1],[Define to make use of getopt_long]) 22 AC_DEFINE([HAVE_GETOPT_LONG],[1],[Define to make use of getopt_long])
23 AC_SUBST(HAVE_GETOPT_LONG,1) 23 AC_SUBST(HAVE_GETOPT_LONG,1)
24],[ 24],[
25 AC_SUBST(HAVE_GETOPT_LONG,0) 25 AC_SUBST(HAVE_GETOPT_LONG,0)
26]) 26])
27 27
28PKG_CHECK_MODULES(DOTCONF,[dotconf],,[ 28PKG_CHECK_MODULES(DOTCONF,[dotconf],,[
29 AC_MSG_ERROR([no dotconf library found]) 29 AC_MSG_ERROR([no dotconf library found])
30]) 30])
31 31
32AC_CONFIG_FILES([ 32AC_CONFIG_FILES([
33 Makefile 33 Makefile
34 src/Makefile 34 src/Makefile
35 man/Makefile 35 man/Makefile
36 man/dudki.8 man/dudki.conf.5 36 man/dudki.8 man/dudki.conf.5
37]) 37])
38AC_OUTPUT 38AC_OUTPUT
diff --git a/src/dudki.cc b/src/dudki.cc
index b769109..b4e95a7 100644
--- a/src/dudki.cc
+++ b/src/dudki.cc
@@ -1,128 +1,129 @@
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;
24bool restarting = false;
24static char **_argv = NULL; 25static char **_argv = NULL;
25 26
26static void lethal_signal_handler(int signum) { 27static void lethal_signal_handler(int signum) {
27 syslog(LOG_NOTICE,"Lethal signal received. Terminating."); 28 syslog(LOG_NOTICE,"Lethal signal received. Terminating.");
28 finishing = true; 29 finishing = true;
29} 30}
30static void sighup_handler(int signum) { 31static void sighup_handler(int signum) {
31 syslog(LOG_NOTICE,"SUGHUP received, reloading."); 32 syslog(LOG_NOTICE,"SUGHUP received, reloading.");
32 execvp(_argv[0],_argv); 33 restarting = finishing = true;
33} 34}
34 35
35void check_herd(configuration& config) { 36void check_herd(configuration& config) {
36 for(processes_t::iterator i=config.processes.begin();i!=config.processes.end();++i) 37 for(processes_t::iterator i=config.processes.begin();i!=config.processes.end();++i)
37 i->second.check(i->first,config); 38 i->second.check(i->first,config);
38} 39}
39 40
40void signal_self(const configuration& config,int signum) { 41void signal_self(const configuration& config,int signum) {
41 ifstream pids(config.pidfile.c_str(),ios::in); 42 ifstream pids(config.pidfile.c_str(),ios::in);
42 if(!pids) 43 if(!pids)
43 throw runtime_error("Can't detect running instance"); 44 throw runtime_error("Can't detect running instance");
44 pid_t pid = 0; 45 pid_t pid = 0;
45 pids >> pid; 46 pids >> pid;
46 if(!pid) 47 if(!pid)
47 throw runtime_error("Can't detect running instance"); 48 throw runtime_error("Can't detect running instance");
48 if(pid==getpid()) 49 if(pid==getpid())
49 throw 0; 50 throw 0;
50 if(kill(pid,signum)) 51 if(kill(pid,signum))
51 throw runtime_error("Failed to signal running instance"); 52 throw runtime_error("Failed to signal running instance");
52} 53}
53 54
54int main(int argc,char **argv) { 55int main(int argc,char **argv) {
55 try { 56 try {
56 _argv = new char*[argc+1]; 57 _argv = new char*[argc+1];
57 if(!_argv) 58 if(!_argv)
58 throw runtime_error("memory allocation problem at the very start"); 59 throw runtime_error("memory allocation problem at the very start");
59 memmove(_argv,argv,sizeof(*_argv)*(argc+1)); 60 memmove(_argv,argv,sizeof(*_argv)*(argc+1));
60 string config_file = DEFAULT_CONF_FILE; 61 string config_file = DEFAULT_CONF_FILE;
61 enum { 62 enum {
62 op_default, 63 op_default,
63 op_work, 64 op_work,
64 op_hup, 65 op_hup,
65 op_term, 66 op_term,
66 op_check, 67 op_check,
67 op_ensure, 68 op_ensure,
68 op_test 69 op_test
69 } op = op_default; 70 } op = op_default;
70 while(true) { 71 while(true) {
71 #defineSHORTOPTSTRING "f:hVLrkcet" 72 #defineSHORTOPTSTRING "f:hVLrkcet"
72#ifdef HAVE_GETOPT_LONG 73#ifdef HAVE_GETOPT_LONG
73 static struct option opts[] = { 74 static struct option opts[] = {
74 { "help", no_argument, 0, 'h' }, 75 { "help", no_argument, 0, 'h' },
75 { "usage", no_argument, 0, 'h' }, 76 { "usage", no_argument, 0, 'h' },
76 { "version", no_argument, 0, 'V' }, 77 { "version", no_argument, 0, 'V' },
77 { "license", no_argument, 0, 'L' }, 78 { "license", no_argument, 0, 'L' },
78 { "config", required_argument, 0, 'f' }, 79 { "config", required_argument, 0, 'f' },
79 { "kill", no_argument, 0, 'k' }, 80 { "kill", no_argument, 0, 'k' },
80 { "reload", no_argument, 0, 'r' }, 81 { "reload", no_argument, 0, 'r' },
81 { "check", no_argument, 0, 'c' }, 82 { "check", no_argument, 0, 'c' },
82 { "ensure", no_argument, 0, 'e' }, 83 { "ensure", no_argument, 0, 'e' },
83 { "test", no_argument, 0, 't' }, 84 { "test", no_argument, 0, 't' },
84 { NULL, 0, 0, 0 } 85 { NULL, 0, 0, 0 }
85 }; 86 };
86 int c = getopt_long(argc,argv,SHORTOPTSTRING,opts,NULL); 87 int c = getopt_long(argc,argv,SHORTOPTSTRING,opts,NULL);
87#else /* !HAVE_GETOPT_LONG */ 88#else /* !HAVE_GETOPT_LONG */
88 int c = getopt(argc,argv,SHORTOPTSTRING); 89 int c = getopt(argc,argv,SHORTOPTSTRING);
89#endif /* /HAVE_GETOPT_LONG */ 90#endif /* /HAVE_GETOPT_LONG */
90 if(c==-1) 91 if(c==-1)
91 break; 92 break;
92 switch(c) { 93 switch(c) {
93 case 'h': 94 case 'h':
94 cerr << PHEADER << endl 95 cerr << PHEADER << endl
95 << PCOPY << endl << endl << 96 << PCOPY << endl << endl <<
96#ifdef HAVE_GETOPT_LONG 97#ifdef HAVE_GETOPT_LONG
97 " -h, --help\n" 98 " -h, --help\n"
98 " --usage display this text\n" 99 " --usage display this text\n"
99 " -V, --version display version number\n" 100 " -V, --version display version number\n"
100 " -L, --license show license\n" 101 " -L, --license show license\n"
101 " -f filename, --config=filename\n" 102 " -f filename, --config=filename\n"
102 " specify the configuration file to use\n" 103 " specify the configuration file to use\n"
103 "\n" 104 "\n"
104 " -k, --kill stop running instance\n" 105 " -k, --kill stop running instance\n"
105 " -r, --reload reload running instance (send SIGHUP)\n" 106 " -r, --reload reload running instance (send SIGHUP)\n"
106 " -c, --check check if dudki is running\n" 107 " -c, --check check if dudki is running\n"
107 " -e, --ensure ensure that dudki is running\n" 108 " -e, --ensure ensure that dudki is running\n"
108 " -t, --test test configuration file and exit" 109 " -t, --test test configuration file and exit"
109#else /* !HAVE_GETOPT_LONG */ 110#else /* !HAVE_GETOPT_LONG */
110 " -h display this text\n" 111 " -h display this text\n"
111 " -V display version number\n" 112 " -V display version number\n"
112 " -L show license\n" 113 " -L show license\n"
113 " -f filename specify the configuration file to use\n" 114 " -f filename specify the configuration file to use\n"
114 "\n" 115 "\n"
115 " -k stop running instance\n" 116 " -k stop running instance\n"
116 " -r reload running instance (send SIGHUP)\n" 117 " -r reload running instance (send SIGHUP)\n"
117 " -c check if dudki is running\n" 118 " -c check if dudki is running\n"
118 " -e ensure that dudki is running\n" 119 " -e ensure that dudki is running\n"
119 " -t test configuration file and exit" 120 " -t test configuration file and exit"
120#endif /* /HAVE_GETOPT_LONG */ 121#endif /* /HAVE_GETOPT_LONG */
121 << endl; 122 << endl;
122 exit(0); 123 exit(0);
123 break; 124 break;
124 case 'V': 125 case 'V':
125 cerr << VERSION << endl; 126 cerr << VERSION << endl;
126 exit(0); 127 exit(0);
127 break; 128 break;
128 case 'L': 129 case 'L':
@@ -144,106 +145,108 @@ int main(int argc,char **argv) {
144 if(op!=op_default) { 145 if(op!=op_default) {
145 cerr << "Can't obey two or more orders at once" << endl; 146 cerr << "Can't obey two or more orders at once" << endl;
146 exit(1); 147 exit(1);
147 } 148 }
148 op = op_hup; 149 op = op_hup;
149 break; 150 break;
150 case 'c': 151 case 'c':
151 if(op!=op_default) { 152 if(op!=op_default) {
152 cerr << "Can't obey two or more orders at once" << endl; 153 cerr << "Can't obey two or more orders at once" << endl;
153 exit(1); 154 exit(1);
154 } 155 }
155 op = op_check; 156 op = op_check;
156 break; 157 break;
157 case 'e': 158 case 'e':
158 if(op!=op_default) { 159 if(op!=op_default) {
159 cerr << "Can't obey two or more orders at once" << endl; 160 cerr << "Can't obey two or more orders at once" << endl;
160 exit(1); 161 exit(1);
161 } 162 }
162 op = op_ensure; 163 op = op_ensure;
163 break; 164 break;
164 case 't': 165 case 't':
165 if(op!=op_default) { 166 if(op!=op_default) {
166 cerr << "Can't obey two or more orders at once" << endl; 167 cerr << "Can't obey two or more orders at once" << endl;
167 exit(1); 168 exit(1);
168 } 169 }
169 op = op_test; 170 op = op_test;
170 break; 171 break;
171 default: 172 default:
172 cerr << "Huh??" << endl; 173 cerr << "Huh??" << endl;
173 exit(1); 174 exit(1);
174 break; 175 break;
175 } 176 }
176 } 177 }
177 const char *sid = *argv; 178 const char *sid = *argv;
178 const char *t; 179 const char *t;
179 while(t = index(sid,'/')) { 180 while(t = index(sid,'/')) {
180 sid = t; sid++; 181 sid = t; sid++;
181 } 182 }
182 openlog(sid,LOG_CONS|LOG_PERROR|LOG_PID,LOG_DAEMON); 183 openlog(sid,LOG_CONS|LOG_PERROR|LOG_PID,LOG_DAEMON);
183 configuration config; 184 configuration config;
184 config.parse(config_file); 185 config.parse(config_file);
185 switch(op) { 186 switch(op) {
186 case op_test: 187 case op_test:
187 cerr << "Configuration OK" << endl; 188 cerr << "Configuration OK" << endl;
188 break; 189 break;
189 case op_hup: 190 case op_hup:
190 signal_self(config,SIGHUP); 191 signal_self(config,SIGHUP);
191 break; 192 break;
192 case op_term: 193 case op_term:
193 signal_self(config,SIGTERM); 194 signal_self(config,SIGTERM);
194 break; 195 break;
195 case op_check: 196 case op_check:
196 try{ 197 try{
197 signal_self(config,0); 198 signal_self(config,0);
198 exit(0); 199 exit(0);
199 }catch(exception& e) { 200 }catch(exception& e) {
200 exit(1); 201 exit(1);
201 } 202 }
202 case op_ensure: 203 case op_ensure:
203 try { 204 try {
204 signal_self(config,0); 205 signal_self(config,0);
205 break; 206 break;
206 }catch(exception& e) { 207 }catch(exception& e) {
207 syslog(LOG_NOTICE,"The dudki process is down, taking its place"); 208 syslog(LOG_NOTICE,"The dudki process is down, taking its place");
208 config.daemonize = true; 209 config.daemonize = true;
209 }catch(int zero) { 210 }catch(int zero) {
210 // we throw zero in case we're ensuring that this very process is running. 211 // 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 // we don't have to daemonize if we're daemonic.
212 config.daemonize = false; 213 config.daemonize = false;
213 } 214 }
214 case op_default: 215 case op_default:
215 case op_work: 216 case op_work:
216 { 217 {
217 if(config.daemonize) { 218 if(config.daemonize) {
218 pid_t pf = fork(); 219 pid_t pf = fork();
219 if(pf<0) 220 if(pf<0)
220 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to fork()"); 221 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to fork()");
221 if(pf) { 222 if(pf) {
222 _exit(0); 223 _exit(0);
223 } 224 }
224 } 225 }
225 pid_file pidfile; 226 pid_file pidfile;
226 pidfile.set(config.pidfile); 227 pidfile.set(config.pidfile);
227 signal(SIGINT,lethal_signal_handler); 228 signal(SIGINT,lethal_signal_handler);
228 signal(SIGABRT,lethal_signal_handler); 229 signal(SIGABRT,lethal_signal_handler);
229 signal(SIGTERM,lethal_signal_handler); 230 signal(SIGTERM,lethal_signal_handler);
230 signal(SIGHUP,sighup_handler); 231 signal(SIGHUP,sighup_handler);
231 sigset_t sset; 232 sigset_t sset;
232 sigemptyset(&sset); 233 sigemptyset(&sset);
233 sigaddset(&sset,SIGINT); sigaddset(&sset,SIGABRT); 234 sigaddset(&sset,SIGINT); sigaddset(&sset,SIGABRT);
234 sigaddset(&sset,SIGTERM); sigaddset(&sset,SIGHUP); 235 sigaddset(&sset,SIGTERM); sigaddset(&sset,SIGHUP);
235 sigprocmask(SIG_UNBLOCK,&sset,NULL); 236 sigprocmask(SIG_UNBLOCK,&sset,NULL);
236 while(!finishing) { 237 while(!finishing) {
237 check_herd(config); 238 check_herd(config);
238 sleep(config.check_interval); 239 sleep(config.check_interval);
239 } 240 }
241 if(restarting)
242 execvp(_argv[0],_argv);
240 } 243 }
241 break; 244 break;
242 default: 245 default:
243 throw runtime_error(string(__PRETTY_FUNCTION__)+": internal error"); 246 throw runtime_error(string(__PRETTY_FUNCTION__)+": internal error");
244 } 247 }
245 }catch(exception& e) { 248 }catch(exception& e) {
246 cerr << "Oops: " << e.what() << endl; 249 cerr << "Oops: " << e.what() << endl;
247 return 1; 250 return 1;
248 } 251 }
249} 252}