/* * Copyright © 2015, 2020 Christian Persch * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #pragma once #include #include #include #include #include namespace vte::libc { class ErrnoSaver { public: ErrnoSaver() noexcept : m_errsv{errno} { } ~ErrnoSaver() noexcept { errno = m_errsv; } ErrnoSaver(ErrnoSaver const&) = delete; ErrnoSaver(ErrnoSaver&&) = delete; ErrnoSaver& operator=(ErrnoSaver const&) = delete; ErrnoSaver& operator=(ErrnoSaver&&) = delete; inline constexpr operator int () const noexcept { return m_errsv; } inline void reset() noexcept { m_errsv = 0; } private: int m_errsv; }; // class ErrnoSaver class FD { public: constexpr FD() noexcept = default; explicit constexpr FD(int fd) noexcept : m_fd{fd} { } // adopts the FD constexpr FD(FD const&) = delete; constexpr FD(FD&& rhs) noexcept : m_fd{rhs.release()} { } ~FD() noexcept { reset(); } // adopt the file descriptor FD& operator=(int rhs) noexcept { reset(); m_fd = rhs; return *this; } FD& operator=(FD& rhs) = delete; FD& operator=(FD&& rhs) noexcept { if (this != std::addressof(rhs)) { reset(); m_fd = rhs.release(); } return *this; } explicit constexpr operator bool() const noexcept { return m_fd != -1; } constexpr int get() const noexcept { return m_fd; } constexpr int release() noexcept { auto fd = m_fd; m_fd = -1; return fd; } void reset() { if (m_fd != -1) { auto errsv = ErrnoSaver{}; close(m_fd); m_fd = -1; } } /* C++20 constexpr */ void swap(FD& other) { using std::swap; swap(m_fd, other.m_fd); } private: int m_fd{-1}; }; // class FD constexpr bool operator==(FD const& lhs, FD const& rhs) noexcept { return lhs.get() == rhs.get(); } constexpr bool operator==(FD const& lhs, int rhs) noexcept { return lhs.get() == rhs; } constexpr bool operator!=(FD const& lhs, FD const& rhs) noexcept { return !(lhs == rhs); } constexpr bool operator!=(FD const& lhs, int rhs) noexcept { return !(lhs == rhs); } /* C++20 constexpr */ inline void swap(FD& lhs, FD& rhs) noexcept { lhs.swap(rhs); } /* FD convenience functions */ static inline int fd_get_descriptor_flags(int fd) { auto flags = int{}; do { flags = fcntl(fd, F_GETFD); } while (flags == -1 && errno == EINTR); return flags; } static inline int fd_set_descriptor_flags(int fd, int flags) { auto r = int{}; do { r = fcntl(fd, F_SETFD, flags); } while (r == -1 && errno == EINTR); return r; } static inline int fd_change_descriptor_flags(int fd, int set_flags, int unset_flags) { auto const flags = fd_get_descriptor_flags(fd); if (flags == -1) return -1; auto const new_flags = (flags | set_flags) & ~unset_flags; if (new_flags == flags) return 0; return fd_set_descriptor_flags(fd, new_flags); } static inline int fd_get_status_flags(int fd) { auto flags = int{}; do { flags = fcntl(fd, F_GETFL, 0); } while (flags == -1 && errno == EINTR); return flags; } static inline int fd_set_status_flags(int fd, int flags) { auto r = int{}; do { r = fcntl(fd, F_SETFL, flags); } while (r == -1 && errno == EINTR); return r; } static inline int fd_change_status_flags(int fd, int set_flags, int unset_flags) { auto const flags = fd_get_status_flags(fd); if (flags == -1) return -1; auto const new_flags = (flags | set_flags) & ~unset_flags; if (new_flags == flags) return 0; return fd_set_status_flags(fd, new_flags); } static inline bool fd_get_cloexec(int fd) { auto const r = fd_get_descriptor_flags(fd); return r != -1 && (r & FD_CLOEXEC) != 0; } static inline int fd_set_cloexec(int fd) { return fd_change_descriptor_flags(fd, FD_CLOEXEC, 0); } static inline int fd_unset_cloexec(int fd) { return fd_change_descriptor_flags(fd, 0, FD_CLOEXEC); } static inline int fd_set_nonblock(int fd) { return fd_change_status_flags(fd, O_NONBLOCK, 0); } static inline int fd_dup_cloexec(int oldfd, int newfd) { auto r = int{}; do { r = fcntl(oldfd, F_DUPFD_CLOEXEC, newfd); } while (r == -1 && errno == EINTR); return r; } static inline int fd_dup2(int oldfd, int newfd) { auto r = int{}; do { r = dup2(oldfd, newfd); } while (r == -1 && errno == EINTR); return r; } } // namespace vte::libc