about summary refs log tree commit diff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/util.cc107
-rw-r--r--src/libutil/util.hh18
2 files changed, 125 insertions, 0 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index d3446d38a6d8..d4345eac3699 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -7,9 +7,11 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <fcntl.h>
+#include <signal.h>
 
 #include "util.hh"
 
@@ -337,6 +339,10 @@ void writeFull(int fd, const unsigned char * buf, size_t count)
 }
 
 
+
+//////////////////////////////////////////////////////////////////////
+
+
 AutoDelete::AutoDelete(const string & p) : path(p)
 {
     del = true;
@@ -353,16 +359,22 @@ void AutoDelete::cancel()
 }
 
 
+
+//////////////////////////////////////////////////////////////////////
+
+
 AutoCloseFD::AutoCloseFD()
 {
     fd = -1;
 }
 
+
 AutoCloseFD::AutoCloseFD(int fd)
 {
     this->fd = fd;
 }
 
+
 AutoCloseFD::~AutoCloseFD()
 {
     try {
@@ -372,17 +384,20 @@ AutoCloseFD::~AutoCloseFD()
     }
 }
 
+
 void AutoCloseFD::operator =(int fd)
 {
     if (this->fd != fd) close();
     this->fd = fd;
 }
 
+
 AutoCloseFD::operator int()
 {
     return fd;
 }
 
+
 void AutoCloseFD::close()
 {
     if (fd != -1) {
@@ -393,6 +408,7 @@ void AutoCloseFD::close()
     }
 }
 
+
 bool AutoCloseFD::isOpen()
 {
     return fd != -1;
@@ -408,32 +424,119 @@ void Pipe::create()
 }
 
 
+
+//////////////////////////////////////////////////////////////////////
+
+
 AutoCloseDir::AutoCloseDir()
 {
     dir = 0;
 }
 
+
 AutoCloseDir::AutoCloseDir(DIR * dir)
 {
     this->dir = dir;
 }
 
+
 AutoCloseDir::~AutoCloseDir()
 {
     if (dir) closedir(dir);
 }
 
+
 void AutoCloseDir::operator =(DIR * dir)
 {
     this->dir = dir;
 }
 
+
 AutoCloseDir::operator DIR *()
 {
     return dir;
 }
 
 
+
+//////////////////////////////////////////////////////////////////////
+
+
+Pid::Pid()
+{
+    pid = -1;
+    separatePG = false;
+}
+
+
+Pid::~Pid()
+{
+    kill();
+}
+
+
+void Pid::operator =(pid_t pid)
+{
+    if (this->pid != pid) kill();
+    this->pid = pid;
+}
+
+
+Pid::operator pid_t()
+{
+    return pid;
+}
+
+
+void Pid::kill()
+{
+    if (pid == -1) return;
+    
+    printMsg(lvlError, format("killing child process %1%") % pid);
+
+    /* Send a KILL signal to the child.  If it has its own process
+       group, send the signal to every process in the child process
+       group (which hopefully includes *all* its children). */
+    if (::kill(separatePG ? -pid : pid, SIGKILL) != 0)
+        printMsg(lvlError, format("killing process %1%") % pid);
+    else {
+        /* Wait until the child dies, disregarding the exit status. */
+        int status;
+        while (waitpid(pid, &status, 0) == -1)
+            if (errno != EINTR) printMsg(lvlError,
+                format("waiting for process %1%") % pid);
+    }
+
+    pid = -1;
+}
+
+
+int Pid::wait(bool block)
+{
+    while (1) {
+        int status;
+        int res = waitpid(pid, &status, block ? 0 : WNOHANG);
+        if (res == pid) {
+            pid = -1;
+            return status;
+        }
+        if (res == 0 && !block) return -1;
+        if (errno != EINTR)
+            throw SysError("cannot get child exit status");
+    }
+}
+
+
+void Pid::setSeparatePG(bool separatePG)
+{
+    this->separatePG = separatePG;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+
+
 volatile sig_atomic_t _isInterrupted = 0;
 
 void _interrupted()
@@ -448,6 +551,10 @@ void _interrupted()
 }
 
 
+
+//////////////////////////////////////////////////////////////////////
+
+
 string packStrings(const Strings & strings)
 {
     string d;
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 21c6774b9d07..67661eb5f882 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -172,6 +172,7 @@ public:
     void cancel();
 };
 
+
 class AutoCloseFD
 {
     int fd;
@@ -185,6 +186,7 @@ public:
     bool isOpen();
 };
 
+
 class Pipe
 {
 public:
@@ -192,6 +194,7 @@ public:
     void create();
 };
 
+
 class AutoCloseDir
 {
     DIR * dir;
@@ -204,6 +207,21 @@ public:
 };
 
 
+class Pid
+{
+    pid_t pid;
+    bool separatePG;
+public:
+    Pid();
+    ~Pid();
+    void operator =(pid_t pid);
+    operator pid_t();
+    void kill();
+    int wait(bool block);
+    void setSeparatePG(bool separatePG);
+};
+
+
 /* User interruption. */
 
 extern volatile sig_atomic_t _isInterrupted;