summaryrefslogtreecommitdiffabout
path: root/src/process.cc
Unidiff
Diffstat (limited to 'src/process.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--src/process.cc118
1 files changed, 107 insertions, 11 deletions
diff --git a/src/process.cc b/src/process.cc
index 1ffac9f..8a5b5d2 100644
--- a/src/process.cc
+++ b/src/process.cc
@@ -4,19 +4,35 @@
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
@@ -176,14 +192,94 @@ void process::notify_mailto(const string& email,const string& id,const string& e
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}