diff options
Diffstat (limited to 'src/libutil')
-rw-r--r-- | src/libutil/util.cc | 107 | ||||
-rw-r--r-- | src/libutil/util.hh | 18 |
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; |