summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2004-07-24 00:24:07 (UTC)
committer Michael Krelin <hacker@klever.net>2004-07-24 00:24:07 (UTC)
commitfbc32792b8d8266ff90aa60403f5da78739236f4 (patch) (unidiff)
tree77bc3f196a3733c9c86290f8a73d60bb609bbdd5
parent125671c860a82643d36bc3da279d0b831fae4b34 (diff)
downloaddudki-fbc32792b8d8266ff90aa60403f5da78739236f4.zip
dudki-fbc32792b8d8266ff90aa60403f5da78739236f4.tar.gz
dudki-fbc32792b8d8266ff90aa60403f5da78739236f4.tar.bz2
processes specified by process names (pidof-like).
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--NEWS.xml3
-rw-r--r--man/dudki.conf.5.in6
-rw-r--r--src/configuration.cc5
-rw-r--r--src/dudki.cc7
-rw-r--r--src/process.cc118
-rw-r--r--src/process.h6
6 files changed, 131 insertions, 14 deletions
diff --git a/NEWS.xml b/NEWS.xml
index cd12d05..cc6085d 100644
--- a/NEWS.xml
+++ b/NEWS.xml
@@ -1,10 +1,11 @@
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 24th, 2004">
4 <ni>now dudki sends arbitrary 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 <ni>detection of running processes which do not keep pidfiles, using process name</ni>
5 </version> 6 </version>
6 <version version="0.1" date="July 21st, 2004"> 7 <version version="0.1" date="July 21st, 2004">
7 <ni><kbd>initgroups()</kbd> called before executing <kbd>RestartCommand</kbd></ni> 8 <ni><kbd>initgroups()</kbd> called before executing <kbd>RestartCommand</kbd></ni>
8 <ni>more civilized way of restarting on <kbd>SIGHUP</kbd></ni> 9 <ni>more civilized way of restarting on <kbd>SIGHUP</kbd></ni>
9 <ni>minor changes to build process</ni> 10 <ni>minor changes to build process</ni>
10 </version> 11 </version>
diff --git a/man/dudki.conf.5.in b/man/dudki.conf.5.in
index 23f636d..7d365d3 100644
--- a/man/dudki.conf.5.in
+++ b/man/dudki.conf.5.in
@@ -1,7 +1,7 @@
1.TH dudki.conf 5 "July 9th, 2004" "dudki.conf(5)" "Klever Group (http://www.klever.net/)" 1.TH dudki.conf 5 "July 24th, 2004" "dudki.conf(5)" "Klever Group (http://www.klever.net/)"
2.hla en 2.hla en
3 3
4.SH NAME 4.SH NAME
5 5
6dudki.conf \- The configuration file for the dudki process 6dudki.conf \- The configuration file for the dudki process
7monitoring daemon 7monitoring daemon
@@ -57,12 +57,16 @@ And parameters pertaining to the process.
57\fBPidFile\fR \fIfilename\fR 57\fBPidFile\fR \fIfilename\fR
58Specifies the file where to fetch process id of the process being 58Specifies the file where to fetch process id of the process being
59monitored from. The absence of file, as well as the absence of process 59monitored from. The absence of file, as well as the absence of process
60specified by the pid stored in the file signifies the process death and 60specified by the pid stored in the file signifies the process death and
61triggers restart. 61triggers restart.
62.TP 62.TP
63\fBProcessName\fR \fIprocess name\fR
64Specifies the name of the process. The alternative way to find process if it
65doesn't keep pid in the file. Similar to \fBpidof\fR(1).
66.TP
63\fBRestartCommand\fR \fIcommand\fR 67\fBRestartCommand\fR \fIcommand\fR
64Specifies the command to run in order to restart the process. 68Specifies the command to run in order to restart the process.
65.TP 69.TP
66\fBUser\fR \fIuser\fR 70\fBUser\fR \fIuser\fR
67Specifies the unix user to change to before executing the command 71Specifies the unix user to change to before executing the command
68specified by \fBRestartCommand\fR. 72specified by \fBRestartCommand\fR.
diff --git a/src/configuration.cc b/src/configuration.cc
index eb010c1..edc8c04 100644
--- a/src/configuration.cc
+++ b/src/configuration.cc
@@ -89,12 +89,16 @@ static DOTCONF_CB(dco_process) { dc_context *dcc = (dc_context*)ctx;
89static DOTCONF_CB(dco__process) { dc_context *dcc = (dc_context*)ctx; 89static DOTCONF_CB(dco__process) { dc_context *dcc = (dc_context*)ctx;
90 dcc->ps = NULL; 90 dcc->ps = NULL;
91 dcc->ctx = DCC_ROOT; 91 dcc->ctx = DCC_ROOT;
92 return NULL; 92 return NULL;
93} 93}
94 94
95static DOTCONF_CB(dco_process_name) { dc_context *dcc = (dc_context*)ctx;
96 dcc->ps->process_name = cmd->data.str;
97 return NULL;
98}
95static DOTCONF_CB(dco_restart_command) { dc_context *dcc = (dc_context*)ctx; 99static DOTCONF_CB(dco_restart_command) { dc_context *dcc = (dc_context*)ctx;
96 dcc->ps->restart_cmd = cmd->data.str; 100 dcc->ps->restart_cmd = cmd->data.str;
97 return NULL; 101 return NULL;
98} 102}
99static DOTCONF_CB(dco_user) { dc_context *dcc = (dc_context*)ctx; 103static DOTCONF_CB(dco_user) { dc_context *dcc = (dc_context*)ctx;
100 dcc->ps->user = cmd->data.str; 104 dcc->ps->user = cmd->data.str;
@@ -113,12 +117,13 @@ static const configoption_t dc_options[] = {
113 { "CheckInterval", ARG_INT, dco_check_interval, NULL, DCC_ROOT }, 117 { "CheckInterval", ARG_INT, dco_check_interval, NULL, DCC_ROOT },
114 { "Daemonize", ARG_TOGGLE, dco_daemonize, NULL, DCC_ROOT }, 118 { "Daemonize", ARG_TOGGLE, dco_daemonize, NULL, DCC_ROOT },
115 { "PidFile", ARG_STR, dco_pid_file, NULL, DCC_ROOT|DCC_PROCESS }, 119 { "PidFile", ARG_STR, dco_pid_file, NULL, DCC_ROOT|DCC_PROCESS },
116 { "MailtoHeader", ARG_STR, dco_mailto_header, NULL, DCC_ROOT|DCC_PROCESS }, 120 { "MailtoHeader", ARG_STR, dco_mailto_header, NULL, DCC_ROOT|DCC_PROCESS },
117 { "Notify", ARG_STR, dco_notify, NULL, DCC_ROOT|DCC_PROCESS }, 121 { "Notify", ARG_STR, dco_notify, NULL, DCC_ROOT|DCC_PROCESS },
118 { "<Process", ARG_STR, dco_process, NULL, DCC_ROOT }, 122 { "<Process", ARG_STR, dco_process, NULL, DCC_ROOT },
123 { "ProcessName", ARG_STR, dco_process_name, NULL, DCC_PROCESS },
119 { "RestartCommand", ARG_STR, dco_restart_command, NULL, DCC_PROCESS }, 124 { "RestartCommand", ARG_STR, dco_restart_command, NULL, DCC_PROCESS },
120 { "User", ARG_STR, dco_user, NULL, DCC_PROCESS }, 125 { "User", ARG_STR, dco_user, NULL, DCC_PROCESS },
121 { "Group", ARG_STR, dco_group, NULL, DCC_PROCESS }, 126 { "Group", ARG_STR, dco_group, NULL, DCC_PROCESS },
122 { "Chroot", ARG_STR, dco_chroot, NULL, DCC_PROCESS }, 127 { "Chroot", ARG_STR, dco_chroot, NULL, DCC_PROCESS },
123 { "</Process>", ARG_NONE, dco__process, NULL, DCC_PROCESS }, 128 { "</Process>", ARG_NONE, dco__process, NULL, DCC_PROCESS },
124 LAST_OPTION 129 LAST_OPTION
diff --git a/src/dudki.cc b/src/dudki.cc
index 9562079..c966695 100644
--- a/src/dudki.cc
+++ b/src/dudki.cc
@@ -32,14 +32,16 @@ static void lethal_signal_handler(int signum) {
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");
@@ -217,13 +219,16 @@ int main(int argc,char **argv) {
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)
diff --git a/src/process.cc b/src/process.cc
index 1ffac9f..8a5b5d2 100644
--- a/src/process.cc
+++ b/src/process.cc
@@ -1,25 +1,41 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <sys/types.h> 2#include <sys/types.h>
3#include <unistd.h> 3#include <unistd.h>
4#include <signal.h> 4#include <signal.h>
5#include <pwd.h> 5#include <pwd.h>
6#include <grp.h> 6#include <grp.h>
7#include <dirent.h>
7#include <sys/wait.h> 8#include <sys/wait.h>
8#include <syslog.h> 9#include <syslog.h>
9#include <errno.h> 10#include <errno.h>
10#include <iostream> 11#include <iostream>
11#include <fstream> 12#include <fstream>
13#include <sstream>
12#include <stdexcept> 14#include <stdexcept>
15#include <string>
16#include <vector>
13using namespace std; 17using namespace std;
14#include "process.h" 18#include "process.h"
15#include "configuration.h" 19#include "configuration.h"
16 20
21static multimap<string,pid_t> procpids;
22
23void process::check() const {
24 if(!pidfile.empty()) {
25 signal(0);
26 }else if(!process_name.empty()) {
27 if(procpids.empty())
28 gather_proc_info();
29 if(procpids.find(process_name)==procpids.end())
30 throw runtime_error("no such process");
31 } // XXX: or else?
32}
17void process::check(const string& id,configuration& config) { 33void process::check(const string& id,configuration& config) {
18 try { 34 try {
19 signal(0); 35 check();
20 patience = 0; 36 patience = 0;
21 }catch(exception& e) { 37 }catch(exception& e) {
22 if(patience>60) { // TODO: configurable 38 if(patience>60) { // TODO: configurable
23 patience = 0; 39 patience = 0;
24 }else{ 40 }else{
25 if(patience<10) { // TODO: configurable 41 if(patience<10) { // TODO: configurable
@@ -173,17 +189,97 @@ void process::notify_mailto(const string& email,const string& id,const string& e
173 int status; 189 int status;
174 waitpid(pid,&status,0); 190 waitpid(pid,&status,0);
175 // TODO: check the return code 191 // TODO: check the return code
176} 192}
177 193
178void process::signal(int signum) const { 194void process::signal(int signum) const {
179 ifstream pids(pidfile.c_str(),ios::in); 195 if(!pidfile.empty()) {
180 if(!pids) 196 ifstream pids(pidfile.c_str(),ios::in);
181 throw runtime_error("no pidfile found"); 197 if(!pids)
182 pid_t pid = 0; 198 throw runtime_error("no pidfile found");
183 pids >> pid; 199 pid_t pid = 0;
184 pids.close(); 200 pids >> pid;
185 if(!pid) 201 pids.close();
186 throw runtime_error("no pid in pidfile"); 202 if(!pid)
187 if(kill(pid,signum)) 203 throw runtime_error("no pid in pidfile");
188 throw runtime_error("failed to signal process"); 204 if(kill(pid,signum))
205 throw runtime_error("failed to signal process");
206 }else if(!process_name.empty()) {
207 if(procpids.empty())
208 gather_proc_info();
209 pair<multimap<string,pid_t>::const_iterator,multimap<string,pid_t>::const_iterator> range = procpids.equal_range(process_name);
210 int count = 0;
211 for(multimap<string,pid_t>::const_iterator i=range.first;i!=range.second;++i) {
212 pid_t pid = i->second;
213 if(kill(i->second,signum))
214 throw runtime_error("failed to signal process");
215 count++;
216 }
217 if(!count)
218 throw runtime_error("no running instance detected");
219 }else
220 throw runtime_error("nothing is known about the process");
221}
222
223void process::prepare_herd() {
224 procpids.clear();
225}
226void process::unprepare_herd() {
227 procpids.clear();
228}
229void process::gather_proc_info() {
230 vector<pid_t> allpids;
231 DIR *pd = opendir("/proc");
232 if(!pd)
233 throw runtime_error("failed to open /proc");
234 struct dirent *pde;
235 pid_t selfpid = getpid();
236 while(pde=readdir(pd)) {
237 errno=0;
238 pid_t pid = atoi(pde->d_name);
239 if((!pid) || pid==selfpid)
240 continue;
241 allpids.push_back(pid);
242 }
243 closedir(pd);
244 char s[256];
245 procpids.clear();
246 for(vector<pid_t>::const_iterator i=allpids.begin();i!=allpids.end();++i) {
247 int r = snprintf(s,sizeof(s),"/proc/%d/stat",*i);
248 if(r>=sizeof(s) || r<1)
249 continue;
250 string cmd;
251 ifstream ss(s,ios::in);
252 if(!ss)
253 continue;
254 getline(ss,cmd);
255 string::size_type op = cmd.find('(');
256 if(op==string::npos)
257 continue;
258 cmd.erase(0,op+1);
259 string::size_type cp = cmd.find(')');
260 if(cp==string::npos)
261 continue;
262 cmd.erase(cp);
263 r = snprintf(s,sizeof(s),"/proc/%d/cmdline",*i);
264 if(r>=sizeof(s) || r<1)
265 continue;
266 ifstream cs(s,ios::binary);
267 if(!cs)
268 continue;
269 string command;
270 while(cs) {
271 string cl;
272 getline(cs,cl,(char)0);
273 string::size_type lsl = cl.rfind('/');
274 if(lsl!=string::npos)
275 cl.erase(0,lsl+1);
276 if(cl.substr(0,cmd.length())==cmd) {
277 command = cl;
278 break;
279 }
280 }
281 procpids.insert(pair<string,pid_t>(cmd,*i));
282 if((!command.empty()) && cmd!=command)
283 procpids.insert(pair<string,pid_t>(command,*i));
284 }
189} 285}
diff --git a/src/process.h b/src/process.h
index 27ee049..90b12d9 100644
--- a/src/process.h
+++ b/src/process.h
@@ -9,12 +9,13 @@ class configuration;
9 9
10typedef map<string,string> headers_t; 10typedef map<string,string> headers_t;
11 11
12class process { 12class process {
13 public: 13 public:
14 string pidfile; 14 string pidfile;
15 string process_name;
15 string restart_cmd; 16 string restart_cmd;
16 string notify; 17 string notify;
17 string user; 18 string user;
18 string group; 19 string group;
19 string chroot; 20 string chroot;
20 headers_t mailto_headers; 21 headers_t mailto_headers;
@@ -28,11 +29,16 @@ class process {
28 void launch(const string& id,configuration& config); 29 void launch(const string& id,configuration& config);
29 void do_notify(const string& id,const string& event,const string& description,configuration& config); 30 void do_notify(const string& id,const string& event,const string& description,configuration& config);
30 void notify_mailto(const string& email,const string& id,const string& event, 31 void notify_mailto(const string& email,const string& id,const string& event,
31 const string& description,configuration& config); 32 const string& description,configuration& config);
32 33
33 void signal(int signum) const; 34 void signal(int signum) const;
35 void check() const;
36
37 static void prepare_herd();
38 static void gather_proc_info();
39 static void unprepare_herd();
34}; 40};
35 41
36typedef map<string,process> processes_t; 42typedef map<string,process> processes_t;
37 43
38#endif /* __PROCESS_H */ 44#endif /* __PROCESS_H */