/* * This source code is released into the public domain. */ #include "fd.hh" namespace lfjail { fd::fd(int fd_) noexcept : _fd(fd_) {} fd::fd(fd &&other) noexcept : _fd(std::exchange(other._fd, _invalid_fd)) {} auto fd::operator=(fd &&other) noexcept -> fd & { if (this != &other) _fd = std::exchange(other._fd, _invalid_fd); return *this; } fd::operator bool(this fd const &self) noexcept { return self._fd != _invalid_fd; } fd::~fd() { if (*this) this->close(); } auto fd::close(this fd &self) -> void { (void)::close(self.get()); self._fd = _invalid_fd; } auto fd::get(this fd const &self) -> int { if (!self) std::abort(); return self._fd; } auto fd::release() && noexcept -> int { if (!*this) std::abort(); return std::exchange(_fd, _invalid_fd); } // Create a copy of this fd by calling dup(). auto dup(fd const &self) -> fd { auto thisfd = self.get(); auto const newfd = ::dup(thisfd); if (newfd == -1) throw generic_error("dup({}): {}", thisfd, std::strerror(errno)); return {newfd}; } // Create a copy of this fd by calling dup2(). The second argument // must not be managed by an instance of the fd class, or else it // will be closed twice. auto dup(fd const &self, int newfd) -> fd { auto thisfd = self.get(); // dup2() allows the existing and new fd to be the same, // but this is error-prone and usually a logic error, so // we reject it. if (thisfd == newfd) std::abort(); auto const ret = ::dup2(thisfd, newfd); if (ret == -1) throw generic_error("dup({}): {}", thisfd, std::strerror(errno)); return {newfd}; } // Return the fnctl flags for this fd. auto getflags(fd const &self) -> int { auto const flags = ::fcntl(self.get(), F_GETFL); if (flags == -1) throw generic_error("fcntl({}, F_GETFL): {}", self.get(), strerror(errno)); return flags; } // Replace the fnctl flags for this fd. auto replaceflags(fd &self, int newflags) -> void { auto const ret = ::fcntl(self.get(), F_SETFL, newflags); if (ret == -1) throw generic_error("fcntl({}, F_SETFL, {}): {}", self.get(), newflags, strerror(errno)); } // Add bits to the fcntl flags for this fd. auto setflags(fd &self, int newflags) -> void { auto flags = getflags(self); flags |= newflags; replaceflags(self, flags); } // Remove bits from the fcntl flags for this fd. auto clearflags(fd &self, int clrflags) -> void { auto flags = getflags(self); flags &= ~clrflags; replaceflags(self, flags); } // Create two fds by calling pipe() and return them. auto pipe() -> std::pair { auto fds = std::array{}; if (auto const ret = ::pipe(fds.data()); ret != 0) throw generic_error("pipe(): {}", std::strerror(errno)); return {fd(fds[0]), fd(fds[1])}; } } // namespace lfjail