#ifndef __fdset__ #define __fdset__ #include #include #include #include #include class fdset; class fdmask; /* * fdmask does not own the file descriptors and will not close them. * */ class fdmask { public: fdmask() = default; fdmask(const fdmask &) = default; fdmask(fdmask &&) = default; fdmask(const std::array &rhs) : _fds(rhs) {} #if 0 fdmask(std::initializer_list rhs) : _fds(rhs) {} #endif fdmask &operator=(const fdmask &) = default; fdmask &operator=(fdmask &&) = default; fdmask &operator=(const std::array &rhs) { _fds = rhs; return *this; } #if 0 fdmask &operator=(std::initializer_list rhs) { _fds = rhs; } #endif void dup() const { // dup fds to stdin/stdout/stderr. // called after fork, before exec. #define __(index, target) \ if (_fds[index] >= 0 && _fds[index] != target) dup2(_fds[index], target) __(0, STDIN_FILENO); __(1, STDOUT_FILENO); __(2, STDERR_FILENO); #undef __ } int operator[](unsigned index) const { return _fds[index]; } fdmask &operator|=(const fdmask &rhs) { for (unsigned i = 0; i < 3; ++i) { if (_fds[i] < 0) _fds[i] = rhs._fds[i]; } return *this; } private: friend class fdset; std::array _fds = {{ -1, -1, -1 }}; }; /* * fd set owns it's descriptors and will close them. * * */ class fdset { public: fdset() = default; fdset(const fdset &) = delete; fdset(fdset && rhs) { std::swap(rhs._fds, _fds); } ~fdset() { close(); } fdset &operator=(const fdset &) = delete; fdset &operator=(fdset &&rhs) { if (&rhs != this) { std::swap(_fds, rhs._fds); rhs.close(); } return *this; } void close(void) { for (int &fd : _fds) { if (fd >= 0) { ::close(fd); fd = -1; } } } void set(int index, int fd) { std::swap(fd, _fds[index]); if (fd >= 0) ::close(fd); } fdmask to_mask() const { return fdmask(_fds); } private: void reset() { _fds = {{ -1, -1, -1 }}; } std::array _fds = {{ -1, -1, -1 }}; }; inline fdmask operator|(const fdmask &lhs, const fdmask &rhs) { fdmask tmp(lhs); tmp |= rhs; return tmp; } inline fdmask operator|(const fdset &lhs, const fdmask &rhs) { fdmask tmp(lhs.to_mask()); tmp |= rhs; return tmp; } struct process { std::vector arguments; fdset fds; }; #endif