summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2004-07-23 20:40:46 (UTC)
committer Michael Krelin <hacker@klever.net>2004-07-23 20:40:46 (UTC)
commit546858a1e4d13d179a6af27b474e1396cfdf0c29 (patch) (side-by-side diff)
treeac19b0ff5e4b3164ad5375bda112a9d6d2f88c2b
parent76921288a0aa39acb53102863523c388b5d0f9ee (diff)
downloaddudki-546858a1e4d13d179a6af27b474e1396cfdf0c29.zip
dudki-546858a1e4d13d179a6af27b474e1396cfdf0c29.tar.gz
dudki-546858a1e4d13d179a6af27b474e1396cfdf0c29.tar.bz2
the ability to check/kill/reload any of the processes being monitored added.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--man/dudki.8.in11
-rw-r--r--src/dudki.cc61
-rw-r--r--src/process.cc30
-rw-r--r--src/process.h2
4 files changed, 65 insertions, 39 deletions
diff --git a/man/dudki.8.in b/man/dudki.8.in
index 3011034..05db733 100644
--- a/man/dudki.8.in
+++ b/man/dudki.8.in
@@ -17,52 +17,57 @@ dudki \- a process monitoring daemon
[\fB-f\fR \fIconfigfile\fR]
.if \*[longopt] [\fB--config=\fR\fIconfigfile\fR]
[\fB-k\fR]
.if \*[longopt] [\fB--kill\fR]
[\fB-r\fR]
.if \*[longopt] [\fB--reload\fR]
[\fB-c\fR]
.if \*[longopt] [\fB--check\fR]
[\fB-e\fR]
.if \*[longopt] [\fB--ensure\fR]
[\fB-t\fR]
.if \*[longopt] [\fB--test\fR]
+[\fI<process-list>\fR]
.SH DESCRIPTION
dudki daemon is designed to run in the background and periodically
check if certain processes specified in the configuration file are
running. If a process is detected as dead dudki tries to restart it
using the command line specified in the configuration file and notifies
the specified contact (currently only via email).
.SH OPTIONS
.TP
.ie \*[longopt] \fB-f\fR \fIconfigfile\fR, \fB--config=\fR\fIconfigfile\fR
.el \fB-f\fR \fIconfigfile\fR
Specify the configuration file to use (default is
\fI@sysconfdir@/dudki.conf\fR).
.TP
.ie \*[longopt] \fB-k\fR, \fB--kill\fR
.el \fB-k\fR
-Stop the running instance by sending the \fBSIGTERM\fR signal.
+Stop the running instance by sending the \fBSIGTERM\fR signal. If no process
+name specified on the command line, dudki kills his own running instance.
.TP
.ie \*[longopt] \fB-r\fR, \fB--reload\fR
.el \fB-r\fR
-Reload the running instance by sending the \fBSIGHUP\fR signal.
+Reload the running instance by sending the \fBSIGHUP\fR signal. Like with
+\fB-k\fR, if no process name specified on the command line, dudki sends
+\fBSIGHUP\fR to his own running instance.
.TP
.ie \*[longopt] \fB-c\fR, \fB--check\fR
.el \fB-c\fR
-Check if dudki is running. Exit with non-zero status if not.
+Check if dudki is running. Exit with non-zero status if not. The same target
+rules as in \fB-k\fR and \fB-r\fR apply here.
.TP
.ie \*[longopt] \fB-e\fR, \fB--ensure\fR
.el \fB-e\fR
Ensure that dudki is running. Load, if not. Useful for running as a
cron job once in a while. If the daemon is running runs quietly
providing no output.
.TP
.ie \*[longopt] \fB-t\fR, \fB--test\fR
.el \fB-t\fR
Check the syntax of configuration file and exit.
.TP
.ie \*[longopt] \fB-h\fR, \fB--help\fR, \fB--usage\fR
diff --git a/src/dudki.cc b/src/dudki.cc
index b4e95a7..e91ad5e 100644
--- a/src/dudki.cc
+++ b/src/dudki.cc
@@ -53,30 +53,29 @@ void signal_self(const configuration& config,int signum) {
}
int main(int argc,char **argv) {
try {
_argv = new char*[argc+1];
if(!_argv)
throw runtime_error("memory allocation problem at the very start");
memmove(_argv,argv,sizeof(*_argv)*(argc+1));
string config_file = DEFAULT_CONF_FILE;
enum {
op_default,
op_work,
- op_hup,
- op_term,
- op_check,
+ op_signal,
op_ensure,
op_test
} op = op_default;
+ int op_signum = 0;
while(true) {
#define SHORTOPTSTRING "f:hVLrkcet"
#ifdef HAVE_GETOPT_LONG
static struct option opts[] = {
{ "help", no_argument, 0, 'h' },
{ "usage", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V' },
{ "license", no_argument, 0, 'L' },
{ "config", required_argument, 0, 'f' },
{ "kill", no_argument, 0, 'k' },
{ "reload", no_argument, 0, 'r' },
{ "check", no_argument, 0, 'c' },
@@ -84,85 +83,90 @@ int main(int argc,char **argv) {
{ "test", no_argument, 0, 't' },
{ NULL, 0, 0, 0 }
};
int c = getopt_long(argc,argv,SHORTOPTSTRING,opts,NULL);
#else /* !HAVE_GETOPT_LONG */
int c = getopt(argc,argv,SHORTOPTSTRING);
#endif /* /HAVE_GETOPT_LONG */
if(c==-1)
break;
switch(c) {
case 'h':
cerr << PHEADER << endl
- << PCOPY << endl << endl <<
+ << PCOPY << endl << endl
+ << " " << argv[0] << " [options] [processes]" << endl << endl <<
#ifdef HAVE_GETOPT_LONG
" -h, --help\n"
" --usage display this text\n"
" -V, --version display version number\n"
" -L, --license show license\n"
" -f filename, --config=filename\n"
" specify the configuration file to use\n"
"\n"
- " -k, --kill stop running instance\n"
+ " -k, --kill stop running instance (send SIGTERM)\n"
" -r, --reload reload running instance (send SIGHUP)\n"
- " -c, --check check if dudki is running\n"
+ " -c, --check check if the process is running\n"
+ " (the above commands operate on dudki itself if no\n"
+ " process name has been specified)\n"
" -e, --ensure ensure that dudki is running\n"
" -t, --test test configuration file and exit"
#else /* !HAVE_GETOPT_LONG */
" -h display this text\n"
" -V display version number\n"
" -L show license\n"
" -f filename specify the configuration file to use\n"
"\n"
- " -k stop running instance\n"
+ " -k stop running instance (send SIGTERM)\n"
" -r reload running instance (send SIGHUP)\n"
- " -c check if dudki is running\n"
+ " -c check if the process is running\n"
+ " (the above commands operate on dudki itself if no\n"
+ " process name has been specified)\n"
" -e ensure that dudki is running\n"
" -t test configuration file and exit"
#endif /* /HAVE_GETOPT_LONG */
<< endl;
exit(0);
break;
case 'V':
cerr << VERSION << endl;
exit(0);
break;
case 'L':
extern const char *COPYING;
cerr << COPYING << endl;
exit(0);
break;
case 'f':
config_file = optarg;
break;
case 'k':
if(op!=op_default) {
cerr << "Can't obey two or more orders at once" << endl;
exit(1);
}
- op = op_term;
+ op = op_signal; op_signum = SIGTERM;
break;
case 'r':
if(op!=op_default) {
cerr << "Can't obey two or more orders at once" << endl;
exit(1);
}
- op = op_hup;
+ op = op_signal; op_signum = SIGHUP;
break;
case 'c':
if(op!=op_default) {
cerr << "Can't obey two or more orders at once" << endl;
exit(1);
}
- op = op_check;
+ op = op_signal; op_signum = 0;
break;
case 'e':
if(op!=op_default) {
cerr << "Can't obey two or more orders at once" << endl;
exit(1);
}
op = op_ensure;
break;
case 't':
if(op!=op_default) {
cerr << "Can't obey two or more orders at once" << endl;
exit(1);
@@ -178,36 +182,49 @@ int main(int argc,char **argv) {
const char *sid = *argv;
const char *t;
while(t = index(sid,'/')) {
sid = t; sid++;
}
openlog(sid,LOG_CONS|LOG_PERROR|LOG_PID,LOG_DAEMON);
configuration config;
config.parse(config_file);
switch(op) {
case op_test:
cerr << "Configuration OK" << endl;
break;
- case op_hup:
- signal_self(config,SIGHUP);
- break;
- case op_term:
- signal_self(config,SIGTERM);
- break;
- case op_check:
- try{
- signal_self(config,0);
- exit(0);
+ case op_signal:
+ try {
+ if(optind>=argc) {
+ signal_self(config,op_signum);
+ }else{
+ int failures = 0;
+ for(int narg=optind;narg<argc;narg++) {
+ try {
+ processes_t::const_iterator i = config.processes.find(argv[narg]);
+ if(i==config.processes.end())
+ throw runtime_error("no such process configured");
+ i->second.signal(op_signum);
+ }catch(exception& e) {
+ cerr << "dudki(" << argv[narg] << "): " << e.what() << endl;
+ failures++;
+ }
+ }
+ if(failures)
+ throw runtime_error("not all processes have been successfully signaled");
+ }
+ if(!op_signum)
+ exit(0);
}catch(exception& e) {
- exit(1);
+ if(!op_signum)
+ exit(1);
}
case op_ensure:
try {
signal_self(config,0);
break;
}catch(exception& e) {
syslog(LOG_NOTICE,"The dudki process is down, taking its place");
config.daemonize = true;
}catch(int zero) {
// we throw zero in case we're ensuring that this very process is running.
// we don't have to daemonize if we're daemonic.
config.daemonize = false;
diff --git a/src/process.cc b/src/process.cc
index bfab311..1ffac9f 100644
--- a/src/process.cc
+++ b/src/process.cc
@@ -6,39 +6,28 @@
#include <grp.h>
#include <sys/wait.h>
#include <syslog.h>
#include <errno.h>
#include <iostream>
#include <fstream>
#include <stdexcept>
using namespace std;
#include "process.h"
#include "configuration.h"
void process::check(const string& id,configuration& config) {
- bool running = false;
- ifstream pids(pidfile.c_str(),ios::in);
- if(pids) {
- pid_t pid = 0;
- pids >> pid;
- pids.close();
- if(pid) {
- if(!kill(pid,0)) {
- running = true;
- }
- }
- }
- if(running){
+ try {
+ signal(0);
patience = 0;
- }else{
+ }catch(exception& e) {
if(patience>60) { // TODO: configurable
patience = 0;
}else{
if(patience<10) { // TODO: configurable
syslog(LOG_NOTICE,"The process '%s' is down, trying to launch.",id.c_str());
do_notify(id,"Starting up",
"The named process seems to be down. Dudki will try\n"
"to revive it by running the specified command.\n",
config);
try {
launch(id,config);
}catch(exception& e) {
@@ -176,12 +165,25 @@ void process::notify_mailto(const string& email,const string& id,const string& e
fprintf(mta,
"Subject: [%s] %s\n\n"
"%s\n"
"---\n"
"This message was sent automatically by the 'dudki' daemon\n",
id.c_str(), event.c_str(),
description.c_str() );
fclose(mta);
int status;
waitpid(pid,&status,0);
// TODO: check the return code
}
+
+void process::signal(int signum) const {
+ ifstream pids(pidfile.c_str(),ios::in);
+ if(!pids)
+ throw runtime_error("no pidfile found");
+ pid_t pid = 0;
+ pids >> pid;
+ pids.close();
+ if(!pid)
+ throw runtime_error("no pid in pidfile");
+ if(kill(pid,signum))
+ throw runtime_error("failed to signal process");
+}
diff --git a/src/process.h b/src/process.h
index b6d7091..27ee049 100644
--- a/src/process.h
+++ b/src/process.h
@@ -20,17 +20,19 @@ class process {
headers_t mailto_headers;
int patience;
process()
: patience(0) { }
void check(const string& id,configuration& config);
void launch(const string& id,configuration& config);
void do_notify(const string& id,const string& event,const string& description,configuration& config);
void notify_mailto(const string& email,const string& id,const string& event,
const string& description,configuration& config);
+
+ void signal(int signum) const;
};
typedef map<string,process> processes_t;
#endif /* __PROCESS_H */