summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2004-07-23 21:31:57 (UTC)
committer Michael Krelin <hacker@klever.net>2004-07-23 21:31:57 (UTC)
commit125671c860a82643d36bc3da279d0b831fae4b34 (patch) (unidiff)
treeab5edcac7c58e769c9d8436ae0e803edb2ebca9f
parent0a7f5999eb47ce113b3cd47b03198947441945a7 (diff)
downloaddudki-125671c860a82643d36bc3da279d0b831fae4b34.zip
dudki-125671c860a82643d36bc3da279d0b831fae4b34.tar.gz
dudki-125671c860a82643d36bc3da279d0b831fae4b34.tar.bz2
ability to send arbitrary signals
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--NEWS.xml2
-rw-r--r--man/dudki.8.in11
-rw-r--r--src/dudki.cc20
3 files changed, 29 insertions, 4 deletions
diff --git a/NEWS.xml b/NEWS.xml
index 646bb90..cd12d05 100644
--- a/NEWS.xml
+++ b/NEWS.xml
@@ -1,14 +1,14 @@
1<?xml version="1.0" encoding="us-ascii"?> 1<?xml version="1.0" encoding="us-ascii"?>
2<news> 2<news>
3 <version version="0.2" date="July 23rd, 2004"> 3 <version version="0.2" date="July 23rd, 2004">
4 <ni>now dudki sends signals to the processes being monitored from the command line</ni> 4 <ni>now dudki sends arbitrary signals to the processes being monitored from the command line</ni>
5 </version> 5 </version>
6 <version version="0.1" date="July 21st, 2004"> 6 <version version="0.1" date="July 21st, 2004">
7 <ni><kbd>initgroups()</kbd> called before executing <kbd>RestartCommand</kbd></ni> 7 <ni><kbd>initgroups()</kbd> called before executing <kbd>RestartCommand</kbd></ni>
8 <ni>more civilized way of restarting on <kbd>SIGHUP</kbd></ni> 8 <ni>more civilized way of restarting on <kbd>SIGHUP</kbd></ni>
9 <ni>minor changes to build process</ni> 9 <ni>minor changes to build process</ni>
10 </version> 10 </version>
11 <version version="0.0" date="July 11th, 2004"> 11 <version version="0.0" date="July 11th, 2004">
12 <ni>Initial release</ni> 12 <ni>Initial release</ni>
13 </version> 13 </version>
14</news> 14</news>
diff --git a/man/dudki.8.in b/man/dudki.8.in
index 05db733..be60f53 100644
--- a/man/dudki.8.in
+++ b/man/dudki.8.in
@@ -1,128 +1,135 @@
1.TH dudki 8 "June 9th, 2004" "dudki(8)" "Klever Group (http://www.klever.net/)" 1.TH dudki 8 "July 23rd, 2004" "dudki(8)" "Klever Group (http://www.klever.net/)"
2.hla en 2.hla en
3.ds longopt @HAVE_GETOPT_LONG@ 3.ds longopt @HAVE_GETOPT_LONG@
4 4
5.SH NAME 5.SH NAME
6 6
7dudki \- a process monitoring daemon 7dudki \- a process maintenance daemon
8 8
9.SH SYNOPSYS 9.SH SYNOPSYS
10 10
11\fBdudki\fR [\fB-h\fR] 11\fBdudki\fR [\fB-h\fR]
12.if \*[longopt] [\fB--help\fR] [\fB--usage\fR] 12.if \*[longopt] [\fB--help\fR] [\fB--usage\fR]
13[\fB-V\fR] 13[\fB-V\fR]
14.if \*[longopt] [\fB--version\fR] 14.if \*[longopt] [\fB--version\fR]
15[\fB-L\fR] 15[\fB-L\fR]
16.if \*[longopt] [\fB--license\fR] 16.if \*[longopt] [\fB--license\fR]
17[\fB-f\fR \fIconfigfile\fR] 17[\fB-f\fR \fIconfigfile\fR]
18.if \*[longopt] [\fB--config=\fR\fIconfigfile\fR] 18.if \*[longopt] [\fB--config=\fR\fIconfigfile\fR]
19[\fB-k\fR] 19[\fB-k\fR]
20.if \*[longopt] [\fB--kill\fR] 20.if \*[longopt] [\fB--kill\fR]
21[\fB-r\fR] 21[\fB-r\fR]
22.if \*[longopt] [\fB--reload\fR] 22.if \*[longopt] [\fB--reload\fR]
23[\fB-c\fR] 23[\fB-c\fR]
24.if \*[longopt] [\fB--check\fR] 24.if \*[longopt] [\fB--check\fR]
25[\fB-s\fR \fIsignum\fR]
26.if \*[longopt] [\fB--signal=\fR\fIsignum\fR]
25[\fB-e\fR] 27[\fB-e\fR]
26.if \*[longopt] [\fB--ensure\fR] 28.if \*[longopt] [\fB--ensure\fR]
27[\fB-t\fR] 29[\fB-t\fR]
28.if \*[longopt] [\fB--test\fR] 30.if \*[longopt] [\fB--test\fR]
29[\fI<process-list>\fR] 31[\fI<process-list>\fR]
30 32
31.SH DESCRIPTION 33.SH DESCRIPTION
32 34
33dudki daemon is designed to run in the background and periodically 35dudki daemon is designed to run in the background and periodically
34check if certain processes specified in the configuration file are 36check if certain processes specified in the configuration file are
35running. If a process is detected as dead dudki tries to restart it 37running. If a process is detected as dead dudki tries to restart it
36using the command line specified in the configuration file and notifies 38using the command line specified in the configuration file and notifies
37the specified contact (currently only via email). 39the specified contact (currently only via email).
38 40
39.SH OPTIONS 41.SH OPTIONS
40 42
41.TP 43.TP
42.ie \*[longopt] \fB-f\fR \fIconfigfile\fR, \fB--config=\fR\fIconfigfile\fR 44.ie \*[longopt] \fB-f\fR \fIconfigfile\fR, \fB--config=\fR\fIconfigfile\fR
43.el \fB-f\fR \fIconfigfile\fR 45.el \fB-f\fR \fIconfigfile\fR
44Specify the configuration file to use (default is 46Specify the configuration file to use (default is
45\fI@sysconfdir@/dudki.conf\fR). 47\fI@sysconfdir@/dudki.conf\fR).
46.TP 48.TP
47.ie \*[longopt] \fB-k\fR, \fB--kill\fR 49.ie \*[longopt] \fB-k\fR, \fB--kill\fR
48.el \fB-k\fR 50.el \fB-k\fR
49Stop the running instance by sending the \fBSIGTERM\fR signal. If no process 51Stop the running instance by sending the \fBSIGTERM\fR signal. If no process
50name specified on the command line, dudki kills his own running instance. 52name specified on the command line, dudki kills his own running instance.
51.TP 53.TP
52.ie \*[longopt] \fB-r\fR, \fB--reload\fR 54.ie \*[longopt] \fB-r\fR, \fB--reload\fR
53.el \fB-r\fR 55.el \fB-r\fR
54Reload the running instance by sending the \fBSIGHUP\fR signal. Like with 56Reload the running instance by sending the \fBSIGHUP\fR signal. Like with
55\fB-k\fR, if no process name specified on the command line, dudki sends 57\fB-k\fR, if no process name specified on the command line, dudki sends
56\fBSIGHUP\fR to his own running instance. 58\fBSIGHUP\fR to his own running instance.
57.TP 59.TP
60.ie \*[longopt] \fB-s\fR \fIsignum\fR, \fB--signal=\fR\fIsignum\fR
61.el \fB-s\fR \fIsignum\fR
62Send arbitrary signal to the names processes (or self, but it doesn't make much
63sense).
64.TP
58.ie \*[longopt] \fB-c\fR, \fB--check\fR 65.ie \*[longopt] \fB-c\fR, \fB--check\fR
59.el \fB-c\fR 66.el \fB-c\fR
60Check if dudki is running. Exit with non-zero status if not. The same target 67Check if dudki is running. Exit with non-zero status if not. The same target
61rules as in \fB-k\fR and \fB-r\fR apply here. 68rules as in \fB-k\fR and \fB-r\fR apply here.
62.TP 69.TP
63.ie \*[longopt] \fB-e\fR, \fB--ensure\fR 70.ie \*[longopt] \fB-e\fR, \fB--ensure\fR
64.el \fB-e\fR 71.el \fB-e\fR
65Ensure that dudki is running. Load, if not. Useful for running as a 72Ensure that dudki is running. Load, if not. Useful for running as a
66cron job once in a while. If the daemon is running runs quietly 73cron job once in a while. If the daemon is running runs quietly
67providing no output. 74providing no output.
68.TP 75.TP
69.ie \*[longopt] \fB-t\fR, \fB--test\fR 76.ie \*[longopt] \fB-t\fR, \fB--test\fR
70.el \fB-t\fR 77.el \fB-t\fR
71Check the syntax of configuration file and exit. 78Check the syntax of configuration file and exit.
72.TP 79.TP
73.ie \*[longopt] \fB-h\fR, \fB--help\fR, \fB--usage\fR 80.ie \*[longopt] \fB-h\fR, \fB--help\fR, \fB--usage\fR
74.el \fB-h\fR 81.el \fB-h\fR
75Display short usage message and exit. 82Display short usage message and exit.
76.TP 83.TP
77.ie \*[longopt] \fB-V\fR, \fB--version\fR 84.ie \*[longopt] \fB-V\fR, \fB--version\fR
78.el \fB-V\fR 85.el \fB-V\fR
79Report version and exit. 86Report version and exit.
80.TP 87.TP
81.ie \*[longopt] \fB-L\fR, \fB--license\fR 88.ie \*[longopt] \fB-L\fR, \fB--license\fR
82.el \fB-L\fR 89.el \fB-L\fR
83Show licensing terms. 90Show licensing terms.
84 91
85.SH EXIT STATUS 92.SH EXIT STATUS
86 93
87Zero in case of success, non-zero otherwise. 94Zero in case of success, non-zero otherwise.
88 95
89.SH FILES 96.SH FILES
90.TP 97.TP
91@sysconfdir@/dudki.conf 98@sysconfdir@/dudki.conf
92Default configuration file. 99Default configuration file.
93.TP 100.TP
94/var/run/dudki.pid 101/var/run/dudki.pid
95Default pid-file for the dudki process. 102Default pid-file for the dudki process.
96 103
97.SH AUTHOR 104.SH AUTHOR
98 105
99Written by Michael 'hacker' Krelin <hacker@klever.net> 106Written by Michael 'hacker' Krelin <hacker@klever.net>
100 107
101.SH COPYRIGHT 108.SH COPYRIGHT
102 109
103Copyright (c) 2004 Klever Group (http://www.klever.net/) 110Copyright (c) 2004 Klever Group (http://www.klever.net/)
104 111
105Permission is hereby granted, free of charge, to any person obtaining a copy of 112Permission is hereby granted, free of charge, to any person obtaining a copy of
106this software and associated documentation files (the "Software"), to deal in 113this software and associated documentation files (the "Software"), to deal in
107the Software without restriction, including without limitation the rights to 114the Software without restriction, including without limitation the rights to
108use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 115use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
109of the Software, and to permit persons to whom the Software is furnished to do 116of the Software, and to permit persons to whom the Software is furnished to do
110so, subject to the following conditions: 117so, subject to the following conditions:
111 118
112The above copyright notice and this permission notice shall be included in all 119The above copyright notice and this permission notice shall be included in all
113copies or substantial portions of the Software. 120copies or substantial portions of the Software.
114 121
115THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 122THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
116IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 123IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
117FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 124FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
118AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 125AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
119LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 126LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
120OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 127OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
121SOFTWARE. 128SOFTWARE.
122 129
123.SH BUGS 130.SH BUGS
124 131
125You tell me. Send reports to <dudki-bugs@klever.net> 132You tell me. Send reports to <dudki-bugs@klever.net>
126 133
127.SH SEE ALSO 134.SH SEE ALSO
128\fBdudki.conf\fR(5) 135\fBdudki.conf\fR(5)
diff --git a/src/dudki.cc b/src/dudki.cc
index e91ad5e..9562079 100644
--- a/src/dudki.cc
+++ b/src/dudki.cc
@@ -1,269 +1,287 @@
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 <iostream> 5#include <iostream>
5#include <fstream> 6#include <fstream>
6#include <stdexcept> 7#include <stdexcept>
7using namespace std; 8using namespace std;
8#include "configuration.h" 9#include "configuration.h"
9#include "util.h" 10#include "util.h"
10 11
11#include "config.h" 12#include "config.h"
12#ifdef HAVE_GETOPT_H 13#ifdef HAVE_GETOPT_H
13# include <getopt.h> 14# include <getopt.h>
14#endif 15#endif
15 16
16#ifndef DEFAULT_CONF_FILE 17#ifndef DEFAULT_CONF_FILE
17# define DEFAULT_CONF_FILE "/etc/dudki.conf" 18# define DEFAULT_CONF_FILE "/etc/dudki.conf"
18#endif 19#endif
19 20
20#define PHEADER PACKAGE " Version " VERSION 21#define PHEADER PACKAGE " Version " VERSION
21#define PCOPY "Copyright (c) 2004 Klever Group" 22#define PCOPY "Copyright (c) 2004 Klever Group"
22 23
23bool finishing = false; 24bool finishing = false;
24bool restarting = false; 25bool restarting = false;
25static char **_argv = NULL; 26static char **_argv = NULL;
26 27
27static void lethal_signal_handler(int signum) { 28static void lethal_signal_handler(int signum) {
28 syslog(LOG_NOTICE,"Lethal signal received. Terminating."); 29 syslog(LOG_NOTICE,"Lethal signal received. Terminating.");
29 finishing = true; 30 finishing = true;
30} 31}
31static void sighup_handler(int signum) { 32static void sighup_handler(int signum) {
32 syslog(LOG_NOTICE,"SUGHUP received, reloading."); 33 syslog(LOG_NOTICE,"SUGHUP received, reloading.");
33 restarting = finishing = true; 34 restarting = finishing = true;
34} 35}
35 36
36void check_herd(configuration& config) { 37void check_herd(configuration& config) {
37 for(processes_t::iterator i=config.processes.begin();i!=config.processes.end();++i) 38 for(processes_t::iterator i=config.processes.begin();i!=config.processes.end();++i)
38 i->second.check(i->first,config); 39 i->second.check(i->first,config);
39} 40}
40 41
41void signal_self(const configuration& config,int signum) { 42void signal_self(const configuration& config,int signum) {
42 ifstream pids(config.pidfile.c_str(),ios::in); 43 ifstream pids(config.pidfile.c_str(),ios::in);
43 if(!pids) 44 if(!pids)
44 throw runtime_error("Can't detect running instance"); 45 throw runtime_error("Can't detect running instance");
45 pid_t pid = 0; 46 pid_t pid = 0;
46 pids >> pid; 47 pids >> pid;
47 if(!pid) 48 if(!pid)
48 throw runtime_error("Can't detect running instance"); 49 throw runtime_error("Can't detect running instance");
49 if(pid==getpid()) 50 if(pid==getpid())
50 throw 0; 51 throw 0;
51 if(kill(pid,signum)) 52 if(kill(pid,signum))
52 throw runtime_error("Failed to signal running instance"); 53 throw runtime_error("Failed to signal running instance");
53} 54}
54 55
55int main(int argc,char **argv) { 56int main(int argc,char **argv) {
56 try { 57 try {
57 _argv = new char*[argc+1]; 58 _argv = new char*[argc+1];
58 if(!_argv) 59 if(!_argv)
59 throw runtime_error("memory allocation problem at the very start"); 60 throw runtime_error("memory allocation problem at the very start");
60 memmove(_argv,argv,sizeof(*_argv)*(argc+1)); 61 memmove(_argv,argv,sizeof(*_argv)*(argc+1));
61 string config_file = DEFAULT_CONF_FILE; 62 string config_file = DEFAULT_CONF_FILE;
62 enum { 63 enum {
63 op_default, 64 op_default,
64 op_work, 65 op_work,
65 op_signal, 66 op_signal,
66 op_ensure, 67 op_ensure,
67 op_test 68 op_test
68 } op = op_default; 69 } op = op_default;
69 int op_signum = 0; 70 int op_signum = 0;
70 while(true) { 71 while(true) {
71 #defineSHORTOPTSTRING "f:hVLrkcet" 72 #defineSHORTOPTSTRING "f:hVLrkcets:"
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' },
82 { "signal", required_argument, 0, 's' },
81 { "check", no_argument, 0, 'c' }, 83 { "check", no_argument, 0, 'c' },
82 { "ensure", no_argument, 0, 'e' }, 84 { "ensure", no_argument, 0, 'e' },
83 { "test", no_argument, 0, 't' }, 85 { "test", no_argument, 0, 't' },
84 { NULL, 0, 0, 0 } 86 { NULL, 0, 0, 0 }
85 }; 87 };
86 int c = getopt_long(argc,argv,SHORTOPTSTRING,opts,NULL); 88 int c = getopt_long(argc,argv,SHORTOPTSTRING,opts,NULL);
87#else /* !HAVE_GETOPT_LONG */ 89#else /* !HAVE_GETOPT_LONG */
88 int c = getopt(argc,argv,SHORTOPTSTRING); 90 int c = getopt(argc,argv,SHORTOPTSTRING);
89#endif /* /HAVE_GETOPT_LONG */ 91#endif /* /HAVE_GETOPT_LONG */
90 if(c==-1) 92 if(c==-1)
91 break; 93 break;
92 switch(c) { 94 switch(c) {
93 case 'h': 95 case 'h':
94 cerr << PHEADER << endl 96 cerr << PHEADER << endl
95 << PCOPY << endl << endl 97 << PCOPY << endl << endl
96 << " " << argv[0] << " [options] [processes]" << endl << endl << 98 << " " << argv[0] << " [options] [processes]" << endl << endl <<
97#ifdef HAVE_GETOPT_LONG 99#ifdef HAVE_GETOPT_LONG
98 " -h, --help\n" 100 " -h, --help\n"
99 " --usage display this text\n" 101 " --usage display this text\n"
100 " -V, --version display version number\n" 102 " -V, --version display version number\n"
101 " -L, --license show license\n" 103 " -L, --license show license\n"
102 " -f filename, --config=filename\n" 104 " -f filename, --config=filename\n"
103 " specify the configuration file to use\n" 105 " specify the configuration file to use\n"
104 "\n" 106 "\n"
105 " -k, --kill stop running instance (send SIGTERM)\n" 107 " -k, --kill stop running instance (send SIGTERM)\n"
106 " -r, --reload reload running instance (send SIGHUP)\n" 108 " -r, --reload reload running instance (send SIGHUP)\n"
109 " -s signum, --signal=signum\n"
110 " send the specified signal to the running process\n"
107 " -c, --check check if the process is running\n" 111 " -c, --check check if the process is running\n"
108 " (the above commands operate on dudki itself if no\n" 112 " (the above commands operate on dudki itself if no\n"
109 " process name has been specified)\n" 113 " process name has been specified)\n"
110 " -e, --ensure ensure that dudki is running\n" 114 " -e, --ensure ensure that dudki is running\n"
111 " -t, --test test configuration file and exit" 115 " -t, --test test configuration file and exit"
112#else /* !HAVE_GETOPT_LONG */ 116#else /* !HAVE_GETOPT_LONG */
113 " -h display this text\n" 117 " -h display this text\n"
114 " -V display version number\n" 118 " -V display version number\n"
115 " -L show license\n" 119 " -L show license\n"
116 " -f filename specify the configuration file to use\n" 120 " -f filename specify the configuration file to use\n"
117 "\n" 121 "\n"
118 " -k stop running instance (send SIGTERM)\n" 122 " -k stop running instance (send SIGTERM)\n"
119 " -r reload running instance (send SIGHUP)\n" 123 " -r reload running instance (send SIGHUP)\n"
124 " -s signum send the specified signal to the running process\n"
120 " -c check if the process is running\n" 125 " -c check if the process is running\n"
121 " (the above commands operate on dudki itself if no\n" 126 " (the above commands operate on dudki itself if no\n"
122 " process name has been specified)\n" 127 " process name has been specified)\n"
123 " -e ensure that dudki is running\n" 128 " -e ensure that dudki is running\n"
124 " -t test configuration file and exit" 129 " -t test configuration file and exit"
125#endif /* /HAVE_GETOPT_LONG */ 130#endif /* /HAVE_GETOPT_LONG */
126 << endl; 131 << endl;
127 exit(0); 132 exit(0);
128 break; 133 break;
129 case 'V': 134 case 'V':
130 cerr << VERSION << endl; 135 cerr << VERSION << endl;
131 exit(0); 136 exit(0);
132 break; 137 break;
133 case 'L': 138 case 'L':
134 extern const char *COPYING; 139 extern const char *COPYING;
135 cerr << COPYING << endl; 140 cerr << COPYING << endl;
136 exit(0); 141 exit(0);
137 break; 142 break;
138 case 'f': 143 case 'f':
139 config_file = optarg; 144 config_file = optarg;
140 break; 145 break;
141 case 'k': 146 case 'k':
142 if(op!=op_default) { 147 if(op!=op_default) {
143 cerr << "Can't obey two or more orders at once" << endl; 148 cerr << "Can't obey two or more orders at once" << endl;
144 exit(1); 149 exit(1);
145 } 150 }
146 op = op_signal; op_signum = SIGTERM; 151 op = op_signal; op_signum = SIGTERM;
147 break; 152 break;
148 case 'r': 153 case 'r':
149 if(op!=op_default) { 154 if(op!=op_default) {
150 cerr << "Can't obey two or more orders at once" << endl; 155 cerr << "Can't obey two or more orders at once" << endl;
151 exit(1); 156 exit(1);
152 } 157 }
153 op = op_signal; op_signum = SIGHUP; 158 op = op_signal; op_signum = SIGHUP;
154 break; 159 break;
155 case 'c': 160 case 'c':
156 if(op!=op_default) { 161 if(op!=op_default) {
157 cerr << "Can't obey two or more orders at once" << endl; 162 cerr << "Can't obey two or more orders at once" << endl;
158 exit(1); 163 exit(1);
159 } 164 }
160 op = op_signal; op_signum = 0; 165 op = op_signal; op_signum = 0;
161 break; 166 break;
162 case 'e': 167 case 'e':
163 if(op!=op_default) { 168 if(op!=op_default) {
164 cerr << "Can't obey two or more orders at once" << endl; 169 cerr << "Can't obey two or more orders at once" << endl;
165 exit(1); 170 exit(1);
166 } 171 }
167 op = op_ensure; 172 op = op_ensure;
168 break; 173 break;
169 case 't': 174 case 't':
170 if(op!=op_default) { 175 if(op!=op_default) {
171 cerr << "Can't obey two or more orders at once" << endl; 176 cerr << "Can't obey two or more orders at once" << endl;
172 exit(1); 177 exit(1);
173 } 178 }
174 op = op_test; 179 op = op_test;
175 break; 180 break;
181 case 's':
182 if(op!=op_default) {
183 cerr << "Can't obey two or more orders at once" << endl;
184 exit(1);
185 }
186 op = op_signal;
187 errno = 0;
188 op_signum = strtol(optarg,NULL,0);
189 if(errno) {
190 cerr << "Can't obtain the signal value" << endl;
191 exit(1);
192 }
193 break;
176 default: 194 default:
177 cerr << "Huh??" << endl; 195 cerr << "Huh??" << endl;
178 exit(1); 196 exit(1);
179 break; 197 break;
180 } 198 }
181 } 199 }
182 const char *sid = *argv; 200 const char *sid = *argv;
183 const char *t; 201 const char *t;
184 while(t = index(sid,'/')) { 202 while(t = index(sid,'/')) {
185 sid = t; sid++; 203 sid = t; sid++;
186 } 204 }
187 openlog(sid,LOG_CONS|LOG_PERROR|LOG_PID,LOG_DAEMON); 205 openlog(sid,LOG_CONS|LOG_PERROR|LOG_PID,LOG_DAEMON);
188 configuration config; 206 configuration config;
189 config.parse(config_file); 207 config.parse(config_file);
190 switch(op) { 208 switch(op) {
191 case op_test: 209 case op_test:
192 cerr << "Configuration OK" << endl; 210 cerr << "Configuration OK" << endl;
193 break; 211 break;
194 case op_signal: 212 case op_signal:
195 try { 213 try {
196 if(optind>=argc) { 214 if(optind>=argc) {
197 signal_self(config,op_signum); 215 signal_self(config,op_signum);
198 }else{ 216 }else{
199 int failures = 0; 217 int failures = 0;
200 for(int narg=optind;narg<argc;narg++) { 218 for(int narg=optind;narg<argc;narg++) {
201 try { 219 try {
202 processes_t::const_iterator i = config.processes.find(argv[narg]); 220 processes_t::const_iterator i = config.processes.find(argv[narg]);
203 if(i==config.processes.end()) 221 if(i==config.processes.end())
204 throw runtime_error("no such process configured"); 222 throw runtime_error("no such process configured");
205 i->second.signal(op_signum); 223 i->second.signal(op_signum);
206 }catch(exception& e) { 224 }catch(exception& e) {
207 cerr << "dudki(" << argv[narg] << "): " << e.what() << endl; 225 cerr << "dudki(" << argv[narg] << "): " << e.what() << endl;
208 failures++; 226 failures++;
209 } 227 }
210 } 228 }
211 if(failures) 229 if(failures)
212 throw runtime_error("not all processes have been successfully signaled"); 230 throw runtime_error("not all processes have been successfully signaled");
213 } 231 }
214 if(!op_signum) 232 if(!op_signum)
215 exit(0); 233 exit(0);
216 }catch(exception& e) { 234 }catch(exception& e) {
217 if(!op_signum) 235 if(!op_signum)
218 exit(1); 236 exit(1);
219 } 237 }
220 case op_ensure: 238 case op_ensure:
221 try { 239 try {
222 signal_self(config,0); 240 signal_self(config,0);
223 break; 241 break;
224 }catch(exception& e) { 242 }catch(exception& e) {
225 syslog(LOG_NOTICE,"The dudki process is down, taking its place"); 243 syslog(LOG_NOTICE,"The dudki process is down, taking its place");
226 config.daemonize = true; 244 config.daemonize = true;
227 }catch(int zero) { 245 }catch(int zero) {
228 // we throw zero in case we're ensuring that this very process is running. 246 // we throw zero in case we're ensuring that this very process is running.
229 // we don't have to daemonize if we're daemonic. 247 // we don't have to daemonize if we're daemonic.
230 config.daemonize = false; 248 config.daemonize = false;
231 } 249 }
232 case op_default: 250 case op_default:
233 case op_work: 251 case op_work:
234 { 252 {
235 if(config.daemonize) { 253 if(config.daemonize) {
236 pid_t pf = fork(); 254 pid_t pf = fork();
237 if(pf<0) 255 if(pf<0)
238 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to fork()"); 256 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to fork()");
239 if(pf) { 257 if(pf) {
240 _exit(0); 258 _exit(0);
241 } 259 }
242 } 260 }
243 pid_file pidfile; 261 pid_file pidfile;
244 pidfile.set(config.pidfile); 262 pidfile.set(config.pidfile);
245 signal(SIGINT,lethal_signal_handler); 263 signal(SIGINT,lethal_signal_handler);
246 signal(SIGABRT,lethal_signal_handler); 264 signal(SIGABRT,lethal_signal_handler);
247 signal(SIGTERM,lethal_signal_handler); 265 signal(SIGTERM,lethal_signal_handler);
248 signal(SIGHUP,sighup_handler); 266 signal(SIGHUP,sighup_handler);
249 sigset_t sset; 267 sigset_t sset;
250 sigemptyset(&sset); 268 sigemptyset(&sset);
251 sigaddset(&sset,SIGINT); sigaddset(&sset,SIGABRT); 269 sigaddset(&sset,SIGINT); sigaddset(&sset,SIGABRT);
252 sigaddset(&sset,SIGTERM); sigaddset(&sset,SIGHUP); 270 sigaddset(&sset,SIGTERM); sigaddset(&sset,SIGHUP);
253 sigprocmask(SIG_UNBLOCK,&sset,NULL); 271 sigprocmask(SIG_UNBLOCK,&sset,NULL);
254 while(!finishing) { 272 while(!finishing) {
255 check_herd(config); 273 check_herd(config);
256 sleep(config.check_interval); 274 sleep(config.check_interval);
257 } 275 }
258 if(restarting) 276 if(restarting)
259 execvp(_argv[0],_argv); 277 execvp(_argv[0],_argv);
260 } 278 }
261 break; 279 break;
262 default: 280 default:
263 throw runtime_error(string(__PRETTY_FUNCTION__)+": internal error"); 281 throw runtime_error(string(__PRETTY_FUNCTION__)+": internal error");
264 } 282 }
265 }catch(exception& e) { 283 }catch(exception& e) {
266 cerr << "Oops: " << e.what() << endl; 284 cerr << "Oops: " << e.what() << endl;
267 return 1; 285 return 1;
268 } 286 }
269} 287}