diff --git a/src/config/ConfigWatcher.cpp b/src/config/ConfigWatcher.cpp index c0a9c5917..8d086bac4 100644 --- a/src/config/ConfigWatcher.cpp +++ b/src/config/ConfigWatcher.cpp @@ -5,27 +5,24 @@ #include #include +using namespace Hyprutils::OS; + CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) { - if (m_inotifyFd < 0) { + if (!m_inotifyFd.isValid()) { Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded"); return; } - const int FLAGS = fcntl(m_inotifyFd, F_GETFL, 0); - if (fcntl(m_inotifyFd, F_SETFL, FLAGS | O_NONBLOCK) < 0) { + // TODO: make CFileDescriptor take F_GETFL, F_SETFL + const int FLAGS = fcntl(m_inotifyFd.get(), F_GETFL, 0); + if (fcntl(m_inotifyFd.get(), F_SETFL, FLAGS | O_NONBLOCK) < 0) { Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded"); - close(m_inotifyFd); - m_inotifyFd = -1; + m_inotifyFd.reset(); return; } } -CConfigWatcher::~CConfigWatcher() { - if (m_inotifyFd >= 0) - close(m_inotifyFd); -} - -int CConfigWatcher::getInotifyFD() { +CFileDescriptor& CConfigWatcher::getInotifyFD() { return m_inotifyFd; } @@ -38,7 +35,7 @@ void CConfigWatcher::setWatchList(const std::vector& paths) { // cleanup old paths for (auto& watch : m_watches) { - inotify_rm_watch(m_inotifyFd, watch.wd); + inotify_rm_watch(m_inotifyFd.get(), watch.wd); } m_watches.clear(); @@ -46,7 +43,7 @@ void CConfigWatcher::setWatchList(const std::vector& paths) { // add new paths for (const auto& path : paths) { m_watches.emplace_back(SInotifyWatch{ - .wd = inotify_add_watch(m_inotifyFd, path.c_str(), IN_MODIFY), + .wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY), .file = path, }); } @@ -58,7 +55,7 @@ void CConfigWatcher::setOnChange(const std::function 0) { + while (read(m_inotifyFd.get(), &ev, sizeof(ev)) > 0) { const auto WD = std::ranges::find_if(m_watches.begin(), m_watches.end(), [wd = ev.wd](const auto& e) { return e.wd == wd; }); if (WD == m_watches.end()) { diff --git a/src/config/ConfigWatcher.hpp b/src/config/ConfigWatcher.hpp index c36ecd176..979456891 100644 --- a/src/config/ConfigWatcher.hpp +++ b/src/config/ConfigWatcher.hpp @@ -3,20 +3,21 @@ #include #include #include +#include class CConfigWatcher { public: CConfigWatcher(); - ~CConfigWatcher(); + ~CConfigWatcher() = default; struct SConfigWatchEvent { std::string file; }; - int getInotifyFD(); - void setWatchList(const std::vector& paths); - void setOnChange(const std::function& fn); - void onInotifyEvent(); + Hyprutils::OS::CFileDescriptor& getInotifyFD(); + void setWatchList(const std::vector& paths); + void setOnChange(const std::function& fn); + void onInotifyEvent(); private: struct SInotifyWatch { @@ -26,7 +27,7 @@ class CConfigWatcher { std::function m_watchCallback; std::vector m_watches; - int m_inotifyFd = -1; + Hyprutils::OS::CFileDescriptor m_inotifyFd; }; -inline UP g_pConfigWatcher = makeUnique(); \ No newline at end of file +inline UP g_pConfigWatcher = makeUnique(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 359428b1a..cd6451e22 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -25,6 +25,7 @@ #include using namespace Hyprutils::String; +using namespace Hyprutils::OS; #include #include "../config/ConfigDataValues.hpp" @@ -1680,8 +1681,6 @@ CHyprCtl::CHyprCtl() { CHyprCtl::~CHyprCtl() { if (m_eventSource) wl_event_source_remove(m_eventSource); - if (m_iSocketFD >= 0) - close(m_iSocketFD); if (!m_socketPath.empty()) unlink(m_socketPath.c_str()); } @@ -1840,10 +1839,13 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) return 0; + if (!g_pHyprCtl->m_iSocketFD.isValid()) + return 0; + sockaddr_in clientAddress; socklen_t clientSize = sizeof(clientAddress); - const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); + const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); std::array readBuffer; @@ -1900,9 +1902,9 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { } void CHyprCtl::startHyprCtlSocket() { - m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + m_iSocketFD = CFileDescriptor{socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)}; - if (m_iSocketFD < 0) { + if (!m_iSocketFD.isValid()) { Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); return; } @@ -1913,15 +1915,15 @@ void CHyprCtl::startHyprCtlSocket() { strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str()); - if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { + if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); return; } // 10 max queued. - listen(m_iSocketFD, 10); + listen(m_iSocketFD.get(), 10); Debug::log(LOG, "Hypr socket started at {}", m_socketPath); - m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr); + m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, hyprCtlFDTick, nullptr); } diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index eed8265c3..a95a5f934 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -4,6 +4,7 @@ #include "../helpers/MiscFunctions.hpp" #include "../desktop/Window.hpp" #include +#include // exposed for main.cpp std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); @@ -14,12 +15,12 @@ class CHyprCtl { CHyprCtl(); ~CHyprCtl(); - std::string makeDynamicCall(const std::string& input); - SP registerCommand(SHyprCtlCommand cmd); - void unregisterCommand(const SP& cmd); - std::string getReply(std::string); + std::string makeDynamicCall(const std::string& input); + SP registerCommand(SHyprCtlCommand cmd); + void unregisterCommand(const SP& cmd); + std::string getReply(std::string); - int m_iSocketFD = -1; + Hyprutils::OS::CFileDescriptor m_iSocketFD; struct { bool all = false; diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 4623fe84f..307d840b0 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -8,6 +8,8 @@ #include #include +using namespace Hyprutils::OS; + #define LED_COUNT 3 constexpr static std::array MODNAMES = { @@ -41,9 +43,6 @@ void IKeyboard::clearManuallyAllocd() { if (xkbKeymap) xkb_keymap_unref(xkbKeymap); - if (xkbKeymapFD >= 0) - close(xkbKeymapFD); - if (xkbSymState) xkb_state_unref(xkbSymState); @@ -51,7 +50,7 @@ void IKeyboard::clearManuallyAllocd() { xkbKeymap = nullptr; xkbState = nullptr; xkbStaticState = nullptr; - xkbKeymapFD = -1; + xkbKeymapFD.reset(); } void IKeyboard::setKeymap(const SStringRuleNames& rules) { @@ -147,31 +146,30 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { void IKeyboard::updateKeymapFD() { Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName); - if (xkbKeymapFD >= 0) - close(xkbKeymapFD); - xkbKeymapFD = -1; + if (xkbKeymapFD.isValid()) + xkbKeymapFD.reset(); auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1); xkbKeymapString = cKeymapStr; free(cKeymapStr); - int rw, ro; - if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro)) + CFileDescriptor rw, ro; + if (!allocateSHMFilePair(xkbKeymapString.length() + 1, rw, ro)) Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap"); else { - auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0); - close(rw); + auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw.get(), 0); + rw.reset(); if (keymapFDDest == MAP_FAILED) { Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap"); - close(ro); + ro.reset(); } else { memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length()); munmap(keymapFDDest, xkbKeymapString.length() + 1); - xkbKeymapFD = ro; + xkbKeymapFD = std::move(ro); } } - Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD); + Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD.get()); } void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index dce2127a2..aabf4cc21 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -6,6 +6,7 @@ #include #include +#include AQUAMARINE_FORWARD(IKeyboard); @@ -96,7 +97,7 @@ class IKeyboard : public IHID { std::string xkbFilePath = ""; std::string xkbKeymapString = ""; - int xkbKeymapFD = -1; + Hyprutils::OS::CFileDescriptor xkbKeymapFD; SStringRuleNames currentRules; int repeatRate = 0; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 5ebb0842c..f532617c2 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -836,50 +836,48 @@ bool envEnabled(const std::string& env) { return std::string(ENV) == "1"; } -std::pair openExclusiveShm() { +std::pair openExclusiveShm() { // Only absolute paths can be shared across different shm_open() calls std::string name = "/" + g_pTokenManager->getRandomUUID(); for (size_t i = 0; i < 69; ++i) { - int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd >= 0) - return {fd, name}; + CFileDescriptor fd{shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)}; + if (fd.isValid()) + return {std::move(fd), name}; } - return {-1, ""}; + return {{}, ""}; } -int allocateSHMFile(size_t len) { +CFileDescriptor allocateSHMFile(size_t len) { auto [fd, name] = openExclusiveShm(); - if (fd < 0) - return -1; + if (!fd.isValid()) + return {}; shm_unlink(name.c_str()); int ret; do { - ret = ftruncate(fd, len); + ret = ftruncate(fd.get(), len); } while (ret < 0 && errno == EINTR); if (ret < 0) { - close(fd); - return -1; + return {}; } - return fd; + return std::move(fd); } -bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { +bool allocateSHMFilePair(size_t size, CFileDescriptor& rw_fd_ptr, CFileDescriptor& ro_fd_ptr) { auto [fd, name] = openExclusiveShm(); - if (fd < 0) { + if (!fd.isValid()) { return false; } // CLOEXEC is guaranteed to be set by shm_open - int ro_fd = shm_open(name.c_str(), O_RDONLY, 0); - if (ro_fd < 0) { + CFileDescriptor ro_fd{shm_open(name.c_str(), O_RDONLY, 0)}; + if (!ro_fd.isValid()) { shm_unlink(name.c_str()); - close(fd); return false; } @@ -887,24 +885,20 @@ bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { // Make sure the file cannot be re-opened in read-write mode (e.g. via // "/proc/self/fd/" on Linux) - if (fchmod(fd, 0) != 0) { - close(fd); - close(ro_fd); + if (fchmod(fd.get(), 0) != 0) { return false; } int ret; do { - ret = ftruncate(fd, size); + ret = ftruncate(fd.get(), size); } while (ret < 0 && errno == EINTR); if (ret < 0) { - close(fd); - close(ro_fd); return false; } - *rw_fd_ptr = fd; - *ro_fd_ptr = ro_fd; + rw_fd_ptr = std::move(fd); + ro_fd_ptr = std::move(ro_fd); return true; } diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index d08242849..bd2886387 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../SharedDefs.hpp" #include "../macros.hpp" @@ -35,8 +36,8 @@ double normalizeAngleRad(double ang); std::vector getBacktrace(); void throwError(const std::string& err); bool envEnabled(const std::string& env); -int allocateSHMFile(size_t len); -bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); +Hyprutils::OS::CFileDescriptor allocateSHMFile(size_t len); +bool allocateSHMFilePair(size_t size, Hyprutils::OS::CFileDescriptor& rw_fd_ptr, Hyprutils::OS::CFileDescriptor& ro_fd_ptr); float stringToPercentage(const std::string& VALUE, const float REL); template diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 42acf4851..fc3de3aae 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -32,6 +32,7 @@ #include using namespace Hyprutils::String; using namespace Hyprutils::Utils; +using namespace Hyprutils::OS; static int ratHandler(void* data) { g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock()); @@ -1301,19 +1302,15 @@ bool CMonitor::attemptDirectScanout() { // wait for the explicit fence if present, and if kms explicit is allowed bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled; - int explicitWaitFD = -1; + CFileDescriptor explicitWaitFD; if (DOEXPLICIT) { explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint); - if (explicitWaitFD < 0) + if (!explicitWaitFD.isValid()) Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd"); } - DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0; + DOEXPLICIT = DOEXPLICIT && explicitWaitFD.isValid(); - auto cleanup = CScopeGuard([explicitWaitFD, this]() { - output->state->resetExplicitFences(); - if (explicitWaitFD >= 0) - close(explicitWaitFD); - }); + auto cleanup = CScopeGuard([this]() { output->state->resetExplicitFences(); }); timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -1323,8 +1320,8 @@ bool CMonitor::attemptDirectScanout() { output->state->resetExplicitFences(); if (DOEXPLICIT) { - Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD); - output->state->setExplicitInFence(explicitWaitFD); + Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD.get()); + output->state->setExplicitInFence(explicitWaitFD.get()); } bool ok = output->commit(); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 2b02c30a2..c67bccc52 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -16,6 +16,7 @@ #include "DamageRing.hpp" #include #include +#include // Enum for the different types of auto directions, e.g. auto-left, auto-up. enum eAutoDirs : uint8_t { diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp index 16b5bd92d..46b617bc6 100644 --- a/src/helpers/sync/SyncTimeline.cpp +++ b/src/helpers/sync/SyncTimeline.cpp @@ -4,6 +4,7 @@ #include #include +using namespace Hyprutils::OS; SP CSyncTimeline::create(int drmFD_) { auto timeline = SP(new CSyncTimeline); @@ -85,10 +86,9 @@ bool CSyncTimeline::addWaiter(const std::function& waiter, uint64_t poin auto w = makeShared(); w->fn = waiter; w->timeline = self; + w->eventFd = CFileDescriptor{eventfd(0, EFD_CLOEXEC)}; - int eventFD = eventfd(0, EFD_CLOEXEC); - - if (eventFD < 0) { + if (!w->eventFd.isValid()) { Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd"); return false; } @@ -97,19 +97,17 @@ bool CSyncTimeline::addWaiter(const std::function& waiter, uint64_t poin .handle = handle, .flags = flags, .point = point, - .fd = eventFD, + .fd = w->eventFd.get(), }; if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) { Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed"); - close(eventFD); return false; } - w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get()); + w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, w->eventFd.get(), WL_EVENT_READABLE, ::handleWaiterFD, w.get()); if (!w->source) { Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed"); - close(eventFD); return false; } @@ -126,32 +124,32 @@ void CSyncTimeline::removeWaiter(SWaiter* w) { std::erase_if(waiters, [w](const auto& e) { return e.get() == w; }); } -int CSyncTimeline::exportAsSyncFileFD(uint64_t src) { +CFileDescriptor CSyncTimeline::exportAsSyncFileFD(uint64_t src) { int sync = -1; uint32_t syncHandle = 0; if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed"); - return -1; + return {}; } if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed"); drmSyncobjDestroy(drmFD, syncHandle); - return -1; + return {}; } if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed"); drmSyncobjDestroy(drmFD, syncHandle); - return -1; + return {}; } drmSyncobjDestroy(drmFD, syncHandle); - return sync; + return CFileDescriptor{sync}; } -bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { +bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, CFileDescriptor& fd) { uint32_t syncHandle = 0; if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { @@ -159,7 +157,7 @@ bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { return false; } - if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) { + if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd.get())) { Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed"); drmSyncobjDestroy(drmFD, syncHandle); return false; diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp index 88ad4921e..ba65e004d 100644 --- a/src/helpers/sync/SyncTimeline.hpp +++ b/src/helpers/sync/SyncTimeline.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../memory/Memory.hpp" /* @@ -20,26 +21,27 @@ class CSyncTimeline { ~CSyncTimeline(); struct SWaiter { - std::function fn; - wl_event_source* source = nullptr; - WP timeline; + std::function fn; + wl_event_source* source = nullptr; + WP timeline; + Hyprutils::OS::CFileDescriptor eventFd; }; // check if the timeline point has been signaled // flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE // std::nullopt on fail - std::optional check(uint64_t point, uint32_t flags); + std::optional check(uint64_t point, uint32_t flags); - bool addWaiter(const std::function& waiter, uint64_t point, uint32_t flags); - void removeWaiter(SWaiter*); - int exportAsSyncFileFD(uint64_t src); - bool importFromSyncFileFD(uint64_t dst, int fd); - bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); - void signal(uint64_t point); + bool addWaiter(const std::function& waiter, uint64_t point, uint32_t flags); + void removeWaiter(SWaiter*); + Hyprutils::OS::CFileDescriptor exportAsSyncFileFD(uint64_t src); + bool importFromSyncFileFD(uint64_t dst, Hyprutils::OS::CFileDescriptor& fd); + bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); + void signal(uint64_t point); - int drmFD = -1; - uint32_t handle = 0; - WP self; + int drmFD = -1; + uint32_t handle = 0; + WP self; private: CSyncTimeline() = default; diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp index fc55b4725..6231f0bc6 100644 --- a/src/managers/EventManager.cpp +++ b/src/managers/EventManager.cpp @@ -9,9 +9,10 @@ #include #include #include +using namespace Hyprutils::OS; CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) { - if (m_iSocketFD < 0) { + if (!m_iSocketFD.isValid()) { Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work."); return; } @@ -25,31 +26,27 @@ CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_ strncpy(SERVERADDRESS.sun_path, PATH.c_str(), sizeof(SERVERADDRESS.sun_path) - 1); - if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { + if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { Debug::log(ERR, "Couldn't bind the Hyprland Socket 2. (3) IPC will not work."); return; } // 10 max queued. - if (listen(m_iSocketFD, 10) < 0) { + if (listen(m_iSocketFD.get(), 10) < 0) { Debug::log(ERR, "Couldn't listen on the Hyprland Socket 2. (4) IPC will not work."); return; } - m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, onClientEvent, nullptr); + m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, onClientEvent, nullptr); } CEventManager::~CEventManager() { for (const auto& client : m_vClients) { wl_event_source_remove(client.eventSource); - close(client.fd); } if (m_pEventSource != nullptr) wl_event_source_remove(m_pEventSource); - - if (m_iSocketFD >= 0) - close(m_iSocketFD); } int CEventManager::onServerEvent(int fd, uint32_t mask, void* data) { @@ -66,33 +63,31 @@ int CEventManager::onServerEvent(int fd, uint32_t mask) { wl_event_source_remove(m_pEventSource); m_pEventSource = nullptr; - close(fd); - m_iSocketFD = -1; + m_iSocketFD.reset(); return 0; } - sockaddr_in clientAddress; - socklen_t clientSize = sizeof(clientAddress); - const auto ACCEPTEDCONNECTION = accept4(m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK); - if (ACCEPTEDCONNECTION < 0) { + sockaddr_in clientAddress; + socklen_t clientSize = sizeof(clientAddress); + CFileDescriptor ACCEPTEDCONNECTION{accept4(m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK)}; + if (!ACCEPTEDCONNECTION.isValid()) { if (errno != EAGAIN) { Debug::log(ERR, "Socket2 failed receiving connection, errno: {}", errno); wl_event_source_remove(m_pEventSource); m_pEventSource = nullptr; - close(fd); - m_iSocketFD = -1; + m_iSocketFD.reset(); } return 0; } - Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION); + Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION.get()); // add to event loop so we can close it when we need to - auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, 0, onServerEvent, nullptr); + auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION.get(), 0, onServerEvent, nullptr); m_vClients.emplace_back(SClient{ - ACCEPTEDCONNECTION, + std::move(ACCEPTEDCONNECTION), {}, eventSource, }); @@ -113,7 +108,7 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) { // send all queued events while (!CLIENTIT->events.empty()) { const auto& event = CLIENTIT->events.front(); - if (write(CLIENTIT->fd, event->c_str(), event->length()) < 0) + if (write(CLIENTIT->fd.get(), event->c_str(), event->length()) < 0) break; CLIENTIT->events.erase(CLIENTIT->events.begin()); @@ -128,13 +123,12 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) { } std::vector::iterator CEventManager::findClientByFD(int fd) { - return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd == fd; }); + return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd.get() == fd; }); } std::vector::iterator CEventManager::removeClientByFD(int fd) { const auto CLIENTIT = findClientByFD(fd); wl_event_source_remove(CLIENTIT->eventSource); - close(fd); return m_vClients.erase(CLIENTIT); } @@ -157,11 +151,11 @@ void CEventManager::postEvent(const SHyprIPCEvent& event) { for (auto it = m_vClients.begin(); it != m_vClients.end();) { // try to send the event immediately if the queue is empty const auto QUEUESIZE = it->events.size(); - if (QUEUESIZE > 0 || write(it->fd, sharedEvent->c_str(), sharedEvent->length()) < 0) { + if (QUEUESIZE > 0 || write(it->fd.get(), sharedEvent->c_str(), sharedEvent->length()) < 0) { if (QUEUESIZE >= MAX_QUEUED_EVENTS) { // too many events queued, remove the client - Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd); - it = removeClientByFD(it->fd); + Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd.get()); + it = removeClientByFD(it->fd.get()); continue; } diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index 6b506d338..c8335d205 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -1,6 +1,6 @@ #pragma once #include - +#include #include "../defines.hpp" #include "../helpers/memory/Memory.hpp" @@ -26,19 +26,19 @@ class CEventManager { int onClientEvent(int fd, uint32_t mask); struct SClient { - int fd = -1; - std::vector> events; - wl_event_source* eventSource = nullptr; + Hyprutils::OS::CFileDescriptor fd; + std::vector> events; + wl_event_source* eventSource = nullptr; }; std::vector::iterator findClientByFD(int fd); std::vector::iterator removeClientByFD(int fd); private: - int m_iSocketFD = -1; - wl_event_source* m_pEventSource = nullptr; + Hyprutils::OS::CFileDescriptor m_iSocketFD; + wl_event_source* m_pEventSource = nullptr; - std::vector m_vClients; + std::vector m_vClients; }; inline UP g_pEventManager; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2cb77d217..247550aed 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -28,7 +28,9 @@ #include #include +#include using namespace Hyprutils::String; +using namespace Hyprutils::OS; #include #include @@ -853,19 +855,18 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) { const unsigned int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1; // vtnr is bugged for some reason. - unsigned int ttynum = 0; - int fd; - if ((fd = open("/dev/tty", O_RDONLY | O_NOCTTY)) >= 0) { + unsigned int ttynum = 0; + Hyprutils::OS::CFileDescriptor fd{open("/dev/tty", O_RDONLY | O_NOCTTY)}; + if (fd.isValid()) { #if defined(VT_GETSTATE) struct vt_stat st; - if (!ioctl(fd, VT_GETSTATE, &st)) + if (!ioctl(fd.get(), VT_GETSTATE, &st)) ttynum = st.v_active; #elif defined(VT_GETACTIVE) int vt; - if (!ioctl(fd, VT_GETACTIVE, &vt)) + if (!ioctl(fd.get(), VT_GETACTIVE, &vt)) ttynum = vt; #endif - close(fd); } if (ttynum == TTY) @@ -944,11 +945,11 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo Debug::log(LOG, "Unable to create pipe for fork"); } - pid_t child, grandchild; + CFileDescriptor pipeSock[2] = {CFileDescriptor{socket[0]}, CFileDescriptor{socket[1]}}; + + pid_t child, grandchild; child = fork(); if (child < 0) { - close(socket[0]); - close(socket[1]); Debug::log(LOG, "Fail to create the first fork"); return 0; } @@ -967,22 +968,16 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo setenv(e.first.c_str(), e.second.c_str(), 1); } setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); - close(socket[0]); - close(socket[1]); execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); // exit grandchild _exit(0); } - close(socket[0]); - write(socket[1], &grandchild, sizeof(grandchild)); - close(socket[1]); + write(pipeSock[1].get(), &grandchild, sizeof(grandchild)); // exit child _exit(0); } // run in parent - close(socket[1]); - read(socket[0], &grandchild, sizeof(grandchild)); - close(socket[0]); + read(pipeSock[0].get(), &grandchild, sizeof(grandchild)); // clear child and leave grandchild to init waitpid(child, nullptr, 0); if (grandchild < 0) { diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 4021c1717..83bdf4a0e 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -11,11 +11,12 @@ #include #include +using namespace Hyprutils::OS; #define TIMESPEC_NSEC_PER_SEC 1000000000L CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) { - m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + m_sTimers.timerfd = CFileDescriptor{timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC)}; m_sWayland.loop = wlEventLoop; m_sWayland.display = display; } @@ -31,8 +32,6 @@ CEventLoopManager::~CEventLoopManager() { wl_event_source_remove(m_sIdle.eventSource); if (m_configWatcherInotifySource) wl_event_source_remove(m_configWatcherInotifySource); - if (m_sTimers.timerfd >= 0) - close(m_sTimers.timerfd); } static int timerWrite(int fd, uint32_t mask, void* data) { @@ -52,10 +51,10 @@ static int configWatcherWrite(int fd, uint32_t mask, void* data) { } void CEventLoopManager::enterLoop() { - m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); + m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd.get(), WL_EVENT_READABLE, timerWrite, nullptr); - if (const auto FD = g_pConfigWatcher->getInotifyFD(); FD >= 0) - m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD, WL_EVENT_READABLE, configWatcherWrite, nullptr); + if (const auto& FD = g_pConfigWatcher->getInotifyFD(); FD.isValid()) + m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD.get(), WL_EVENT_READABLE, configWatcherWrite, nullptr); syncPollFDs(); m_sListeners.pollFDsChanged = g_pCompositor->m_pAqBackend->events.pollFDsChanged.registerListener([this](std::any d) { syncPollFDs(); }); @@ -120,7 +119,7 @@ void CEventLoopManager::nudgeTimers() { itimerspec ts = {.it_value = now}; - timerfd_settime(m_sTimers.timerfd, TFD_TIMER_ABSTIME, &ts, nullptr); + timerfd_settime(m_sTimers.timerfd.get(), TFD_TIMER_ABSTIME, &ts, nullptr); } void CEventLoopManager::doLater(const std::function& fn) { diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 95cc61093..ebeb21607 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -6,6 +6,7 @@ #include #include #include "helpers/signal/Signal.hpp" +#include #include "EventLoopTimer.hpp" @@ -54,7 +55,7 @@ class CEventLoopManager { struct { std::vector> timers; - int timerfd = -1; + Hyprutils::OS::CFileDescriptor timerfd; } m_sTimers; SIdleData m_sIdle; diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 6fdbaf4b9..e70f04415 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -4,6 +4,7 @@ #include "managers/eventLoop/EventLoopManager.hpp" #include #include +using namespace Hyprutils::OS; CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) { if UNLIKELY (!good()) @@ -185,15 +186,14 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resourc RESOURCE->parent = self; }); - int fd = ((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD(); - if (fd < 0) { + CFileDescriptor fd{((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD()}; + if (!fd.isValid()) { LOGM(ERR, "Failed to dup fd in lease"); return; } - LOGM(LOG, "Sending DRMFD {} to new lease device", fd); - resource->sendDrmFd(fd); - close(fd); + LOGM(LOG, "Sending DRMFD {} to new lease device", fd.get()); + resource->sendDrmFd(fd.get()); for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) { if (m) @@ -231,16 +231,15 @@ void CDRMLeaseDeviceResource::sendConnector(PHLMONITOR monitor) { } CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backend(drmBackend) { - auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); + auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); - auto fd = drm->getNonMasterFD(); + CFileDescriptor fd{drm->getNonMasterFD()}; - if (fd < 0) { + if (!fd.isValid()) { LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); return; } - close(fd); success = true; name = drm->gpuName; } diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp index ec1e73f20..c7849149d 100644 --- a/src/protocols/DRMLease.hpp +++ b/src/protocols/DRMLease.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "drm-lease-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include /* TODO: this protocol is not made for systems with multiple DRM nodes (e.g. multigpu) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index ce598385c..23dafbca8 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -6,6 +6,7 @@ #include "../Compositor.hpp" #include +using namespace Hyprutils::OS; CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if UNLIKELY (!good()) @@ -103,7 +104,7 @@ bool CDRMSyncobjSurfaceResource::good() { return resource->resource(); } -CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, int fd_) : fd(fd_), resource(resource_) { +CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, CFileDescriptor fd_) : fd(std::move(fd_)), resource(resource_) { if UNLIKELY (!good()) return; @@ -112,7 +113,7 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SPsetOnDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); resource->setDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); - timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd); + timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd.get()); if (!timeline) { resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Timeline failed importing"); @@ -120,11 +121,6 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP= 0) - close(fd); -} - SP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); return data ? data->self.lock() : nullptr; @@ -171,7 +167,7 @@ CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SPsetImportTimeline([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, int32_t fd) { - auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), fd); + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), CFileDescriptor{fd}); if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); return; diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index 42ecdb3e2..8677576f2 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -4,6 +4,7 @@ #include "WaylandProtocol.hpp" #include "linux-drm-syncobj-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CWLSurfaceResource; class CDRMSyncobjTimelineResource; @@ -32,14 +33,14 @@ class CDRMSyncobjSurfaceResource { class CDRMSyncobjTimelineResource { public: - CDRMSyncobjTimelineResource(SP resource_, int fd_); - ~CDRMSyncobjTimelineResource(); + CDRMSyncobjTimelineResource(SP resource_, Hyprutils::OS::CFileDescriptor fd_); + ~CDRMSyncobjTimelineResource() = default; static SP fromResource(wl_resource*); bool good(); WP self; - int fd = -1; + Hyprutils::OS::CFileDescriptor fd; SP timeline; private: diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index 71ee1c4a9..3da5afd62 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -2,6 +2,7 @@ #include #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" +using namespace Hyprutils::OS; CWLRDataOffer::CWLRDataOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -11,21 +12,20 @@ CWLRDataOffer::CWLRDataOffer(SP resource_, SPsetOnDestroy([this](CZwlrDataControlOfferV1* r) { PROTO::dataWlr->destroyResource(this); }); resource->setReceive([this](CZwlrDataControlOfferV1* r, const char* mime, int32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); - source->send(mime, fd); + source->send(mime, std::move(sendFd)); }); } @@ -77,15 +77,13 @@ std::vector CWLRDataSource::mimes() { return mimeTypes; } -void CWLRDataSource::send(const std::string& mime, uint32_t fd) { +void CWLRDataSource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLRDataSource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CWLRDataSource::accepted(const std::string& mime) { diff --git a/src/protocols/DataDeviceWlr.hpp b/src/protocols/DataDeviceWlr.hpp index 5eef163c0..7f14b320d 100644 --- a/src/protocols/DataDeviceWlr.hpp +++ b/src/protocols/DataDeviceWlr.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "wlr-data-control-unstable-v1.hpp" #include "types/DataDevice.hpp" +#include class CWLRDataControlManagerResource; class CWLRDataSource; @@ -38,7 +39,7 @@ class CWLRDataSource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 43ba9d416..0a383e2ec 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -4,6 +4,7 @@ #include "../helpers/Monitor.hpp" #include "../protocols/core/Output.hpp" #include "../render/Renderer.hpp" +using namespace Hyprutils::OS; CGammaControl::CGammaControl(SP resource_, wl_resource* output) : resource(resource_) { if UNLIKELY (!resource_->resource()) @@ -46,34 +47,33 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out resource->setOnDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); }); resource->setSetGamma([this](CZwlrGammaControlV1* gamma, int32_t fd) { + CFileDescriptor gammaFd{fd}; if UNLIKELY (!pMonitor) { LOGM(ERR, "setGamma for a dead monitor"); resource->sendFailed(); - close(fd); return; } LOGM(LOG, "setGamma for {}", pMonitor->szName); - int fdFlags = fcntl(fd, F_GETFL, 0); + // TODO: make CFileDescriptor getflags use F_GETFL + int fdFlags = fcntl(gammaFd.get(), F_GETFL, 0); if UNLIKELY (fdFlags < 0) { LOGM(ERR, "Failed to get fd flags"); resource->sendFailed(); - close(fd); return; } - if UNLIKELY (fcntl(fd, F_SETFL, fdFlags | O_NONBLOCK) < 0) { + // TODO: make CFileDescriptor setflags use F_SETFL + if UNLIKELY (fcntl(gammaFd.get(), F_SETFL, fdFlags | O_NONBLOCK) < 0) { LOGM(ERR, "Failed to set fd flags"); resource->sendFailed(); - close(fd); return; } - ssize_t readBytes = pread(fd, gammaTable.data(), gammaTable.size() * sizeof(uint16_t), 0); + ssize_t readBytes = pread(gammaFd.get(), gammaTable.data(), gammaTable.size() * sizeof(uint16_t), 0); if (readBytes < 0 || (size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) { LOGM(ERR, "Failed to read bytes"); - close(fd); if ((size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) { gamma->error(ZWLR_GAMMA_CONTROL_V1_ERROR_INVALID_GAMMA, "Gamma ramps size mismatch"); @@ -85,7 +85,6 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out } gammaTableSet = true; - close(fd); // translate the table to AQ format std::vector red, green, blue; diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 796cec06e..33121ecd8 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -33,25 +33,22 @@ void CInputMethodKeyboardGrabV2::sendKeyboardData(SP keyboard) { pLastKeyboard = keyboard; - int keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); - if UNLIKELY (keymapFD < 0) { + auto keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); + if UNLIKELY (!keymapFD.isValid()) { LOGM(ERR, "Failed to create a keymap file for keyboard grab"); return; } - void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); + void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD.get(), 0); if UNLIKELY (data == MAP_FAILED) { LOGM(ERR, "Failed to mmap a keymap file for keyboard grab"); - close(keymapFD); return; } memcpy(data, keyboard->xkbKeymapString.c_str(), keyboard->xkbKeymapString.length()); munmap(data, keyboard->xkbKeymapString.length() + 1); - resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->xkbKeymapString.length() + 1); - - close(keymapFD); + resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD.get(), keyboard->xkbKeymapString.length() + 1); sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group); diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index d3135da01..b7b915948 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -14,6 +14,8 @@ #include "../render/OpenGL.hpp" #include "../Compositor.hpp" +using namespace Hyprutils::OS; + static std::optional devIDFromFD(int fd) { struct stat stat; if (fstat(fd, &stat) != 0) @@ -77,29 +79,21 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry); - int fds[2] = {0}; - allocateSHMFilePair(tableSize, &fds[0], &fds[1]); + CFileDescriptor fds[2]; + allocateSHMFilePair(tableSize, fds[0], fds[1]); - auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); + auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0].get(), 0); if (arr == MAP_FAILED) { LOGM(ERR, "mmap failed"); - close(fds[0]); - close(fds[1]); return; } - close(fds[0]); - std::copy(formatsVec.begin(), formatsVec.end(), arr); munmap(arr, tableSize); - tableFD = fds[1]; -} - -CDMABUFFormatTable::~CDMABUFFormatTable() { - close(tableFD); + tableFD = std::move(fds[1]); } CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs) { @@ -234,18 +228,18 @@ void CLinuxDMABUFParamsResource::create(uint32_t id) { } bool CLinuxDMABUFParamsResource::commence() { - if (PROTO::linuxDma->mainDeviceFD < 0) + if (!PROTO::linuxDma->mainDeviceFD.isValid()) return true; for (int i = 0; i < attrs->planes; i++) { uint32_t handle = 0; - if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD, attrs->fds.at(i), &handle)) { + if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD.get(), attrs->fds.at(i), &handle)) { LOGM(ERR, "Failed to import dmabuf fd"); return false; } - if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD, handle)) { + if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD.get(), handle)) { LOGM(ERR, "Failed to close dmabuf handle"); return false; } @@ -303,7 +297,7 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SPsetDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); auto& formatTable = PROTO::linuxDma->formatTable; - resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize); + resource->sendFormatTable(formatTable->tableFD.get(), formatTable->tableSize); sendDefaultFeedback(); } @@ -472,9 +466,9 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const if (device->available_nodes & (1 << DRM_NODE_RENDER)) { const char* name = device->nodes[DRM_NODE_RENDER]; - mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); + mainDeviceFD = CFileDescriptor{open(name, O_RDWR | O_CLOEXEC)}; drmFreeDevice(&device); - if (mainDeviceFD < 0) { + if (!mainDeviceFD.isValid()) { LOGM(ERR, "failed to open drm dev, disabling linux dmabuf"); removeGlobal(); return; @@ -496,7 +490,7 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { auto newFormatTable = makeUnique(formatTable->rendererTranche, formatTable->monitorTranches); for (auto const& feedback : m_vFeedbacks) { - feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); + feedback->resource->sendFormatTable(newFormatTable->tableFD.get(), newFormatTable->tableSize); if (feedback->lastFeedbackWasScanout) { PHLMONITOR mon; auto HLSurface = CWLSurface::fromResource(feedback->surface); @@ -519,11 +513,6 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { formatTable = std::move(newFormatTable); } -CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { - if (mainDeviceFD >= 0) - close(mainDeviceFD); -} - void CLinuxDMABufV1Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 91cf3283f..6c9678787 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -9,6 +9,7 @@ #include "../helpers/Format.hpp" #include "../helpers/Monitor.hpp" #include +#include class CDMABuffer; class CWLSurfaceResource; @@ -48,9 +49,9 @@ struct SDMABUFTranche { class CDMABUFFormatTable { public: CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector> tranches); - ~CDMABUFFormatTable(); + ~CDMABUFFormatTable() = default; - int tableFD = -1; + Hyprutils::OS::CFileDescriptor tableFD; size_t tableSize = 0; SDMABUFTranche rendererTranche; std::vector> monitorTranches; @@ -107,7 +108,7 @@ class CLinuxDMABUFResource { class CLinuxDMABufV1Protocol : public IWaylandProtocol { public: CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name); - ~CLinuxDMABufV1Protocol(); + ~CLinuxDMABufV1Protocol() = default; virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); void updateScanoutTranche(SP surface, PHLMONITOR pMonitor); @@ -128,7 +129,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { UP formatTable; dev_t mainDevice; - int mainDeviceFD = -1; + Hyprutils::OS::CFileDescriptor mainDeviceFD; friend class CLinuxDMABUFResource; friend class CLinuxDMABUFFeedbackResource; diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index 567bfdd23..620f262e5 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -3,6 +3,7 @@ #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "../config/ConfigValue.hpp" +using namespace Hyprutils::OS; CPrimarySelectionOffer::CPrimarySelectionOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -12,21 +13,20 @@ CPrimarySelectionOffer::CPrimarySelectionOffer(SP r resource->setOnDestroy([this](CZwpPrimarySelectionOfferV1* r) { PROTO::primarySelection->destroyResource(this); }); resource->setReceive([this](CZwpPrimarySelectionOfferV1* r, const char* mime, int32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); - source->send(mime, fd); + source->send(mime, std::move(sendFd)); }); } @@ -78,15 +78,13 @@ std::vector CPrimarySelectionSource::mimes() { return mimeTypes; } -void CPrimarySelectionSource::send(const std::string& mime, uint32_t fd) { +void CPrimarySelectionSource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CPrimarySelectionSource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CPrimarySelectionSource::accepted(const std::string& mime) { diff --git a/src/protocols/PrimarySelection.hpp b/src/protocols/PrimarySelection.hpp index aeebe03c4..0ecc962b3 100644 --- a/src/protocols/PrimarySelection.hpp +++ b/src/protocols/PrimarySelection.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "primary-selection-unstable-v1.hpp" #include "types/DataDevice.hpp" +#include class CPrimarySelectionOffer; class CPrimarySelectionSource; @@ -38,7 +39,7 @@ class CPrimarySelectionSource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp index e5b3cf2ac..30fca2608 100644 --- a/src/protocols/SecurityContext.cpp +++ b/src/protocols/SecurityContext.cpp @@ -1,6 +1,7 @@ #include "SecurityContext.hpp" #include "../Compositor.hpp" #include +using namespace Hyprutils::OS; static int onListenFdEvent(int fd, uint32_t mask, void* data) { auto sc = (CSecurityContext*)data; @@ -14,8 +15,8 @@ static int onCloseFdEvent(int fd, uint32_t mask, void* data) { return 0; } -SP CSecurityContextSandboxedClient::create(int clientFD_) { - auto p = SP(new CSecurityContextSandboxedClient(clientFD_)); +SP CSecurityContextSandboxedClient::create(CFileDescriptor clientFD_) { + auto p = SP(new CSecurityContextSandboxedClient(std::move(clientFD_))); if (!p->client) return nullptr; return p; @@ -27,8 +28,8 @@ static void onSecurityContextClientDestroy(wl_listener* l, void* d) { client->onDestroy(); } -CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) : clientFD(clientFD_) { - client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD); +CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(CFileDescriptor clientFD_) : clientFD(std::move(clientFD_)) { + client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD.get()); if (!client) return; @@ -41,7 +42,6 @@ CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) CSecurityContextSandboxedClient::~CSecurityContextSandboxedClient() { wl_list_remove(&destroyListener.listener.link); wl_list_init(&destroyListener.listener.link); - close(clientFD); } void CSecurityContextSandboxedClient::onDestroy() { @@ -113,8 +113,8 @@ CSecurityContext::CSecurityContext(SP resource_, int liste LOGM(LOG, "security_context at 0x{:x} commits", (uintptr_t)this); - listenSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, listenFD, WL_EVENT_READABLE, ::onListenFdEvent, this); - closeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, closeFD, 0, ::onCloseFdEvent, this); + listenSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, listenFD.get(), WL_EVENT_READABLE, ::onListenFdEvent, this); + closeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, closeFD.get(), 0, ::onCloseFdEvent, this); if (!listenSource || !closeSource) { r->noMemory(); @@ -144,16 +144,15 @@ void CSecurityContext::onListen(uint32_t mask) { if (!(mask & WL_EVENT_READABLE)) return; - int clientFD = accept(listenFD, nullptr, nullptr); - if UNLIKELY (clientFD < 0) { + CFileDescriptor clientFD{accept(listenFD.get(), nullptr, nullptr)}; + if UNLIKELY (!clientFD.isValid()) { LOGM(ERR, "security_context at 0x{:x} couldn't accept", (uintptr_t)this); return; } - auto newClient = CSecurityContextSandboxedClient::create(clientFD); + auto newClient = CSecurityContextSandboxedClient::create(std::move(clientFD)); if UNLIKELY (!newClient) { LOGM(ERR, "security_context at 0x{:x} couldn't create a client", (uintptr_t)this); - close(clientFD); return; } diff --git a/src/protocols/SecurityContext.hpp b/src/protocols/SecurityContext.hpp index 2bec08d4d..56d4f7b41 100644 --- a/src/protocols/SecurityContext.hpp +++ b/src/protocols/SecurityContext.hpp @@ -4,19 +4,20 @@ #include #include "WaylandProtocol.hpp" #include "security-context-v1.hpp" +#include class CSecurityContext { public: CSecurityContext(SP resource_, int listenFD_, int closeFD_); ~CSecurityContext(); - bool good(); + bool good(); - std::string sandboxEngine, appID, instanceID; - int listenFD = -1, closeFD = -1; + std::string sandboxEngine, appID, instanceID; + Hyprutils::OS::CFileDescriptor listenFD, closeFD; - void onListen(uint32_t mask); - void onClose(uint32_t mask); + void onListen(uint32_t mask); + void onClose(uint32_t mask); private: SP resource; @@ -44,7 +45,7 @@ struct SCSecurityContextSandboxedClientDestroyWrapper { class CSecurityContextSandboxedClient { public: - static SP create(int clientFD); + static SP create(Hyprutils::OS::CFileDescriptor clientFD); ~CSecurityContextSandboxedClient(); void onDestroy(); @@ -52,10 +53,10 @@ class CSecurityContextSandboxedClient { SCSecurityContextSandboxedClientDestroyWrapper destroyListener; private: - CSecurityContextSandboxedClient(int clientFD_); + CSecurityContextSandboxedClient(Hyprutils::OS::CFileDescriptor clientFD_); - wl_client* client = nullptr; - int clientFD = -1; + wl_client* client = nullptr; + Hyprutils::OS::CFileDescriptor clientFD; friend class CSecurityContextProtocol; friend class CSecurityContext; diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 4fec57c05..00aca0411 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -1,6 +1,7 @@ #include "VirtualKeyboard.hpp" #include #include "../devices/IKeyboard.hpp" +using namespace Hyprutils::OS; CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) { if UNLIKELY (!good()) @@ -51,20 +52,19 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP }); resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) { - auto xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + auto xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + CFileDescriptor keymapFd{fd}; if UNLIKELY (!xkbContext) { LOGM(ERR, "xkbContext creation failed"); r->noMemory(); - close(fd); return; } - auto keymapData = mmap(nullptr, len, PROT_READ, MAP_PRIVATE, fd, 0); + auto keymapData = mmap(nullptr, len, PROT_READ, MAP_PRIVATE, keymapFd.get(), 0); if UNLIKELY (keymapData == MAP_FAILED) { LOGM(ERR, "keymapData alloc failed"); xkb_context_unref(xkbContext); r->noMemory(); - close(fd); return; } @@ -75,7 +75,6 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP LOGM(ERR, "xkbKeymap creation failed"); xkb_context_unref(xkbContext); r->noMemory(); - close(fd); return; } @@ -86,7 +85,6 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP xkb_keymap_unref(xkbKeymap); xkb_context_unref(xkbContext); - close(fd); }); name = "hl-virtual-keyboard"; diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp index 8157b2766..0a13003b3 100644 --- a/src/protocols/VirtualKeyboard.hpp +++ b/src/protocols/VirtualKeyboard.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "virtual-keyboard-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CVirtualKeyboardV1Resource { public: diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index e17b5612f..0931608a9 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -13,6 +13,7 @@ #include "../../managers/HookSystemManager.hpp" #include "../../helpers/Monitor.hpp" #include "../../render/Renderer.hpp" +using namespace Hyprutils::OS; CWLDataOfferResource::CWLDataOfferResource(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -39,15 +40,14 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPsetReceive([this](CWlDataOffer* r, const char* mime, uint32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } @@ -58,7 +58,7 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPaccepted(mime ? mime : ""); } - source->send(mime ? mime : "", fd); + source->send(mime ? mime : "", std::move(sendFd)); recvd = true; @@ -182,15 +182,13 @@ std::vector CWLDataSourceResource::mimes() { return mimeTypes; } -void CWLDataSourceResource::send(const std::string& mime, uint32_t fd) { +void CWLDataSourceResource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLDataSourceResource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CWLDataSourceResource::cancelled() { diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index d8bc2b9ca..dfea4a71e 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -16,6 +16,7 @@ #include "../../helpers/signal/Signal.hpp" #include "../../helpers/math/Math.hpp" #include "../types/DataDevice.hpp" +#include class CWLDataDeviceResource; class CWLDataDeviceManagerResource; @@ -63,7 +64,7 @@ class CWLDataSourceResource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual bool hasDnd(); diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index c6b2de056..1f07a15e0 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -321,35 +321,18 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) return; - std::string_view keymap; - int fd; - uint32_t size; - if (keyboard) { - keymap = keyboard->xkbKeymapString; - fd = keyboard->xkbKeymapFD; - size = keyboard->xkbKeymapString.length() + 1; - } else { - fd = open("/dev/null", O_RDONLY | O_CLOEXEC); - if (fd < 0) { - LOGM(ERR, "Failed to open /dev/null"); - return; - } - size = 0; - } + std::string_view keymap = keyboard->xkbKeymapString; + Hyprutils::OS::CFileDescriptor& fd = keyboard->xkbKeymapFD; + uint32_t size = keyboard->xkbKeymapString.length() + 1; - if (keymap == lastKeymap) { - if (!keyboard) - close(fd); + if (keymap == lastKeymap) return; - } + lastKeymap = keymap; const wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; - resource->sendKeymap(format, fd, size); - - if (!keyboard) - close(fd); + resource->sendKeymap(format, fd.get(), size); } void CWLKeyboardResource::sendEnter(SP surface) { diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 1649f82fc..e0e625604 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -7,6 +7,7 @@ #include "../types/WLBuffer.hpp" #include "../../helpers/Format.hpp" #include "../../render/Renderer.hpp" +using namespace Hyprutils::OS; CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) { if UNLIKELY (!pool_->pool->data) @@ -51,7 +52,7 @@ bool CWLSHMBuffer::isSynchronous() { Aquamarine::SSHMAttrs CWLSHMBuffer::shm() { Aquamarine::SSHMAttrs attrs; attrs.success = true; - attrs.fd = pool->fd; + attrs.fd = pool->fd.get(); attrs.format = NFormatUtils::shmToDRM(fmt); attrs.size = size; attrs.stride = stride; @@ -75,13 +76,12 @@ void CWLSHMBuffer::update(const CRegion& damage) { texture->update(NFormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, damage); } -CSHMPool::CSHMPool(int fd_, size_t size_) : fd(fd_), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) { +CSHMPool::CSHMPool(CFileDescriptor fd_, size_t size_) : fd(std::move(fd_)), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0)) { ; } CSHMPool::~CSHMPool() { munmap(data, size); - close(fd); } void CSHMPool::resize(size_t size_) { @@ -90,23 +90,23 @@ void CSHMPool::resize(size_t size_) { if (data) munmap(data, size); size = size_; - data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0); if UNLIKELY (data == MAP_FAILED) - LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd); + LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd.get()); } -static int shmIsSizeValid(int fd, size_t size) { +static int shmIsSizeValid(CFileDescriptor& fd, size_t size) { struct stat st; - if UNLIKELY (fstat(fd, &st) == -1) { - LOGM(ERR, "Couldn't get stat for fd {} of shm client", fd); + if UNLIKELY (fstat(fd.get(), &st) == -1) { + LOGM(ERR, "Couldn't get stat for fd {} of shm client", fd.get()); return 0; } return (size_t)st.st_size >= size; } -CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t size_) : resource(resource_) { +CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, CFileDescriptor fd_, size_t size_) : resource(resource_) { if UNLIKELY (!good()) return; @@ -115,7 +115,7 @@ CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t return; } - pool = makeShared(fd_, size_); + pool = makeShared(std::move(fd_), size_); resource->setDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); resource->setOnDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); @@ -176,7 +176,8 @@ CWLSHMResource::CWLSHMResource(SP resource_) : resource(resource_) { resource->setOnDestroy([this](CWlShm* r) { PROTO::shm->destroyResource(this); }); resource->setCreatePool([](CWlShm* r, uint32_t id, int32_t fd, int32_t size) { - const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared(makeShared(r->client(), r->version(), id), fd, size)); + CFileDescriptor poolFd{fd}; + const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared(makeShared(r->client(), r->version(), id), std::move(poolFd), size)); if UNLIKELY (!RESOURCE->good()) { r->noMemory(); diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index d7e81367c..fef821cb3 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -7,6 +7,8 @@ - wl_buffer with shm */ +#include +#include #include #include #include "../WaylandProtocol.hpp" @@ -18,14 +20,14 @@ class CWLSHMPoolResource; class CSHMPool { public: - CSHMPool(int fd, size_t size); + CSHMPool(Hyprutils::OS::CFileDescriptor fd, size_t size); ~CSHMPool(); - int fd = 0; - size_t size = 0; - void* data = nullptr; + Hyprutils::OS::CFileDescriptor fd; + size_t size = 0; + void* data = nullptr; - void resize(size_t size); + void resize(size_t size); }; class CWLSHMBuffer : public IHLBuffer { @@ -57,7 +59,7 @@ class CWLSHMBuffer : public IHLBuffer { class CWLSHMPoolResource { public: - CWLSHMPoolResource(SP resource_, int fd, size_t size); + CWLSHMPoolResource(SP resource_, Hyprutils::OS::CFileDescriptor fd, size_t size); bool good(); diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp index 62f10de23..cbb4b2718 100644 --- a/src/protocols/types/DataDevice.hpp +++ b/src/protocols/types/DataDevice.hpp @@ -7,6 +7,7 @@ #include #include "../../helpers/memory/Memory.hpp" #include "../../helpers/math/Math.hpp" +#include class CWLDataOfferResource; class CX11DataOffer; @@ -24,10 +25,10 @@ class IDataSource { IDataSource() = default; virtual ~IDataSource() = default; - virtual std::vector mimes() = 0; - virtual void send(const std::string& mime, uint32_t fd) = 0; - virtual void accepted(const std::string& mime) = 0; - virtual void cancelled() = 0; + virtual std::vector mimes() = 0; + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd) = 0; + virtual void accepted(const std::string& mime) = 0; + virtual void cancelled() = 0; virtual bool hasDnd(); virtual bool dndDone(); virtual void sendDndFinished(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 78b53c9bc..e4aadd63d 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -19,6 +19,7 @@ #include #include #include +using namespace Hyprutils::OS; const std::vector ASSET_PATHS = { #ifdef DATAROOTDIR @@ -301,11 +302,11 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() : m_iDRMFD(g_pCompositor->m_iDRMFD) { Debug::log(WARN, "EGL: EXT_platform_device or EGL_EXT_device_query not supported, using gbm"); if (EGLEXTENSIONS.contains("KHR_platform_gbm")) { success = true; - m_iGBMFD = openRenderNode(m_iDRMFD); - if (m_iGBMFD < 0) + m_iGBMFD = CFileDescriptor{openRenderNode(m_iDRMFD)}; + if (!m_iGBMFD.isValid()) RASSERT(false, "Couldn't open a gbm fd"); - m_pGbmDevice = gbm_create_device(m_iGBMFD); + m_pGbmDevice = gbm_create_device(m_iGBMFD.get()); if (!m_pGbmDevice) RASSERT(false, "Couldn't open a gbm device"); @@ -371,9 +372,6 @@ CHyprOpenGLImpl::~CHyprOpenGLImpl() { if (m_pGbmDevice) gbm_device_destroy(m_pGbmDevice); - - if (m_iGBMFD >= 0) - close(m_iGBMFD); } std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint format) { @@ -2954,29 +2952,28 @@ std::vector CHyprOpenGLImpl::getDRMFormats() { return drmFormats; } -SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { +SP CHyprOpenGLImpl::createEGLSync(CFileDescriptor fenceFD) { std::vector attribs; - int dupFd = -1; - if (fenceFD > 0) { - dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); - if (dupFd < 0) { + CFileDescriptor dupFd; + if (fenceFD.isValid()) { + dupFd = fenceFD.duplicate(); + if (!dupFd.isValid()) { Debug::log(ERR, "createEGLSync: dup failed"); return nullptr; } // reserve number of elements to avoid reallocations attribs.reserve(3); attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID); - attribs.push_back(dupFd); + attribs.push_back(dupFd.get()); attribs.push_back(EGL_NONE); } EGLSyncKHR sync = m_sProc.eglCreateSyncKHR(m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data()); if (sync == EGL_NO_SYNC_KHR) { Debug::log(ERR, "eglCreateSyncKHR failed"); - if (dupFd >= 0) - close(dupFd); return nullptr; - } + } else + dupFd.take(); // eglCreateSyncKHR only takes ownership on success // we need to flush otherwise we might not get a valid fd glFlush(); @@ -2989,19 +2986,18 @@ SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { auto eglsync = SP(new CEGLSync); eglsync->sync = sync; - eglsync->m_iFd = fd; + eglsync->m_iFd = CFileDescriptor{fd}; return eglsync; } bool CHyprOpenGLImpl::waitForTimelinePoint(SP timeline, uint64_t point) { - int fd = timeline->exportAsSyncFileFD(point); - if (fd < 0) { + auto fd = timeline->exportAsSyncFileFD(point); + if (!fd.isValid()) { Debug::log(ERR, "waitForTimelinePoint: failed to get a fd from explicit timeline"); return false; } - auto sync = g_pHyprOpenGL->createEGLSync(fd); - close(fd); + auto sync = g_pHyprOpenGL->createEGLSync(std::move(fd)); if (!sync) { Debug::log(ERR, "waitForTimelinePoint: failed to get an eglsync from explicit timeline"); return false; @@ -3082,12 +3078,9 @@ CEGLSync::~CEGLSync() { if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE) Debug::log(ERR, "eglDestroySyncKHR failed"); - - if (m_iFd >= 0) - close(m_iFd); } -int CEGLSync::fd() { +CFileDescriptor& CEGLSync::fd() { return m_iFd; } diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 1ebb01628..d7abdf639 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "../debug/TracyDefines.hpp" @@ -146,15 +147,15 @@ class CEGLSync { public: ~CEGLSync(); - EGLSyncKHR sync = nullptr; + EGLSyncKHR sync = nullptr; - int fd(); - bool wait(); + Hyprutils::OS::CFileDescriptor& fd(); + bool wait(); private: CEGLSync() = default; - int m_iFd = -1; + Hyprutils::OS::CFileDescriptor m_iFd; friend class CHyprOpenGLImpl; }; @@ -228,14 +229,14 @@ class CHyprOpenGLImpl { uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); std::vector getDRMFormats(); EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(int fenceFD); + SP createEGLSync(Hyprutils::OS::CFileDescriptor fenceFD); bool waitForTimelinePoint(SP timeline, uint64_t point); SCurrentRenderData m_RenderData; GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; + Hyprutils::OS::CFileDescriptor m_iGBMFD; gbm_device* m_pGbmDevice = nullptr; EGLContext m_pEglContext = nullptr; EGLDisplay m_pEglDisplay = nullptr; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 67d8b58b1..424457280 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -36,6 +36,7 @@ #include using namespace Hyprutils::Utils; +using namespace Hyprutils::OS; extern "C" { #include @@ -1462,10 +1463,10 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, Aquamar bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { // apply timelines for explicit sync // save inFD otherwise reset will reset it - auto inFD = pMonitor->output->state->state().explicitInFence; + CFileDescriptor inFD{pMonitor->output->state->state().explicitInFence}; pMonitor->output->state->resetExplicitFences(); - if (inFD >= 0) - pMonitor->output->state->setExplicitInFence(inFD); + if (inFD.isValid()) + pMonitor->output->state->setExplicitInFence(inFD.get()); static auto PHDR = CConfigValue("experimental:hdr"); @@ -1515,7 +1516,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { bool ok = pMonitor->state.commit(); if (!ok) { - if (inFD >= 0) { + if (inFD.isValid()) { Debug::log(TRACE, "Monitor state commit failed, retrying without a fence"); pMonitor->output->state->resetExplicitFences(); ok = pMonitor->state.commit(); @@ -1534,11 +1535,8 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { if (!explicitOptions.explicitEnabled) return ok; - if (inFD >= 0) - close(inFD); - Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size()); - auto sync = g_pHyprOpenGL->createEGLSync(-1); + auto sync = g_pHyprOpenGL->createEGLSync({}); if (!sync) Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed"); @@ -2272,7 +2270,7 @@ void CHyprRenderer::endRender() { auto explicitOptions = getExplicitSyncSettings(); if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { - auto sync = g_pHyprOpenGL->createEGLSync(-1); + auto sync = g_pHyprOpenGL->createEGLSync({}); if (!sync) { Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); return; @@ -2285,12 +2283,12 @@ void CHyprRenderer::endRender() { } auto fd = PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq); - if (fd <= 0) { + if (!fd.isValid()) { Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender"); return; } - PMONITOR->output->state->setExplicitInFence(fd); + PMONITOR->output->state->setExplicitInFence(fd.take()); } else { if (isNvidia() && *PNVIDIAANTIFLICKER) glFinish(); diff --git a/src/xwayland/Dnd.cpp b/src/xwayland/Dnd.cpp index d4ae37805..16d166ce2 100644 --- a/src/xwayland/Dnd.cpp +++ b/src/xwayland/Dnd.cpp @@ -7,6 +7,8 @@ #include "../managers/XWaylandManager.hpp" #include "../desktop/WLSurface.hpp" +using namespace Hyprutils::OS; + #ifndef NO_XWAYLAND static xcb_atom_t dndActionToAtom(uint32_t actions) { if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) @@ -172,7 +174,7 @@ std::vector CX11DataSource::mimes() { return mimeTypes; } -void CX11DataSource::send(const std::string& mime, uint32_t fd) { +void CX11DataSource::send(const std::string& mime, CFileDescriptor fd) { ; } diff --git a/src/xwayland/Dnd.hpp b/src/xwayland/Dnd.hpp index 8da60ddd4..fb0307963 100644 --- a/src/xwayland/Dnd.hpp +++ b/src/xwayland/Dnd.hpp @@ -2,6 +2,7 @@ #include "../protocols/types/DataDevice.hpp" #include +#include #define XDND_VERSION 5 @@ -35,7 +36,7 @@ class CX11DataSource : public IDataSource { ~CX11DataSource() = default; virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual bool hasDnd(); diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index d5dce3338..99bcdf62a 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -24,70 +24,41 @@ #include "../defines.hpp" #include "../Compositor.hpp" #include "../managers/CursorManager.hpp" +using namespace Hyprutils::OS; // Constants -constexpr int SOCKET_DIR_PERMISSIONS = 0755; -constexpr int SOCKET_BACKLOG = 1; -constexpr int MAX_SOCKET_RETRIES = 32; -constexpr int LOCK_FILE_MODE = 0444; +constexpr int SOCKET_DIR_PERMISSIONS = 0755; +constexpr int SOCKET_BACKLOG = 1; +constexpr int MAX_SOCKET_RETRIES = 32; +constexpr int LOCK_FILE_MODE = 0444; -static bool setCloseOnExec(int fd, bool cloexec) { - int flags = fcntl(fd, F_GETFD); - if (flags == -1) { - Debug::log(ERR, "fcntl failed"); - return false; - } - - if (cloexec) - flags = flags | FD_CLOEXEC; - else - flags = flags & ~FD_CLOEXEC; - - if (fcntl(fd, F_SETFD, flags) == -1) { - Debug::log(ERR, "fcntl failed"); - return false; - } - - return true; -} - -static void cleanUpSocket(int fd, const char* path) { - close(fd); - if (path[0]) - unlink(path); -} - -static inline void closeSocketSafely(int& fd) { - if (fd >= 0) - close(fd); -} - -static int createSocket(struct sockaddr_un* addr, size_t path_size) { - socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { +static CFileDescriptor createSocket(struct sockaddr_un* addr, size_t path_size) { + socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; + CFileDescriptor fd{socket(AF_UNIX, SOCK_STREAM, 0)}; + if (!fd.isValid()) { Debug::log(ERR, "Failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - return -1; + return {}; } - if (!setCloseOnExec(fd, true)) { - close(fd); - return -1; + if (!fd.setFlags(fd.getFlags() | FD_CLOEXEC)) { + return {}; } if (addr->sun_path[0]) unlink(addr->sun_path); - if (bind(fd, (struct sockaddr*)addr, size) < 0) { + if (bind(fd.get(), (struct sockaddr*)addr, size) < 0) { Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - cleanUpSocket(fd, addr->sun_path); - return -1; + if (addr->sun_path[0]) + unlink(addr->sun_path); + return {}; } - if (listen(fd, SOCKET_BACKLOG) < 0) { + if (listen(fd.get(), SOCKET_BACKLOG) < 0) { Debug::log(ERR, "Failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - cleanUpSocket(fd, addr->sun_path); - return -1; + if (addr->sun_path[0]) + unlink(addr->sun_path); + return {}; } return fd; @@ -141,7 +112,7 @@ static std::string getSocketPath(int display, bool isLinux) { return std::format("/tmp/.X11-unix/X{}_", display); } -static bool openSockets(std::array& sockets, int display) { +static bool openSockets(std::array& sockets, int display) { if (!ensureSocketDirExists()) return false; @@ -151,17 +122,16 @@ static bool openSockets(std::array& sockets, int display) { path = getSocketPath(display, false); strncpy(addr.sun_path, path.c_str(), path.length() + 1); - sockets[0] = createSocket(&addr, path.length()); - if (sockets[0] < 0) + sockets[0] = CFileDescriptor{createSocket(&addr, path.length())}; + if (!sockets[0].isValid()) return false; path = getSocketPath(display, true); strncpy(addr.sun_path, path.c_str(), path.length() + 1); - sockets[1] = createSocket(&addr, path.length()); - if (sockets[1] < 0) { - close(sockets[0]); - sockets[0] = -1; + sockets[1] = CFileDescriptor{createSocket(&addr, path.length())}; + if (!sockets[1].isValid()) { + sockets[0].reset(); return false; } @@ -174,7 +144,8 @@ static void startServer(void* data) { } static int xwaylandReady(int fd, uint32_t mask, void* data) { - return g_pXWayland->pServer->ready(fd, mask); + CFileDescriptor xwlFd{fd}; + return g_pXWayland->pServer->ready(std::move(xwlFd), mask); } static bool safeRemove(const std::string& path) { @@ -186,38 +157,34 @@ static bool safeRemove(const std::string& path) { bool CXWaylandServer::tryOpenSockets() { for (size_t i = 0; i <= MAX_SOCKET_RETRIES; ++i) { - std::string lockPath = std::format("/tmp/.X{}-lock", i); + std::string lockPath = std::format("/tmp/.X{}-lock", i); - int fd = open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE); - if (fd >= 0) { + CFileDescriptor fd{open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE)}; + if (fd.isValid()) { // we managed to open the lock if (!openSockets(xFDs, i)) { safeRemove(lockPath); - close(fd); continue; } const std::string pidStr = std::to_string(getpid()); - if (write(fd, pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { + if (write(fd.get(), pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { safeRemove(lockPath); - close(fd); continue; } - close(fd); display = i; displayName = std::format(":{}", display); break; } - fd = open(lockPath.c_str(), O_RDONLY | O_CLOEXEC); + fd = CFileDescriptor{open(lockPath.c_str(), O_RDONLY | O_CLOEXEC)}; - if (fd < 0) + if (!fd.isValid()) continue; char pidstr[12] = {0}; - read(fd, pidstr, sizeof(pidstr) - 1); - close(fd); + read(fd.get(), pidstr, sizeof(pidstr) - 1); int32_t pid = 0; try { @@ -249,9 +216,6 @@ CXWaylandServer::~CXWaylandServer() { if (display < 0) return; - closeSocketSafely(xFDs[0]); - closeSocketSafely(xFDs[1]); - std::string lockPath = std::format("/tmp/.X{}-lock", display); safeRemove(lockPath); @@ -277,21 +241,11 @@ void CXWaylandServer::die() { if (pipeSource) wl_event_source_remove(pipeSource); - if (pipeFd >= 0) - close(pipeFd); - - closeSocketSafely(waylandFDs[0]); - closeSocketSafely(waylandFDs[1]); - closeSocketSafely(xwmFDs[0]); - closeSocketSafely(xwmFDs[1]); - // possible crash. Better to leak a bit. //if (xwaylandClient) // wl_client_destroy(xwaylandClient); xwaylandClient = nullptr; - waylandFDs = {-1, -1}; - xwmFDs = {-1, -1}; } bool CXWaylandServer::create() { @@ -307,15 +261,17 @@ bool CXWaylandServer::create() { return true; } -void CXWaylandServer::runXWayland(int notifyFD) { - if (!setCloseOnExec(xFDs[0], false) || !setCloseOnExec(xFDs[1], false) || !setCloseOnExec(waylandFDs[1], false) || !setCloseOnExec(xwmFDs[1], false)) { +void CXWaylandServer::runXWayland(CFileDescriptor& notifyFD) { + if (!xFDs[0].setFlags(xFDs[0].getFlags() & ~FD_CLOEXEC) || !xFDs[1].setFlags(xFDs[1].getFlags() & ~FD_CLOEXEC) || + !waylandFDs[1].setFlags(waylandFDs[1].getFlags() & ~FD_CLOEXEC) || !xwmFDs[1].setFlags(xwmFDs[1].getFlags() & ~FD_CLOEXEC)) { Debug::log(ERR, "Failed to unset cloexec on fds"); _exit(EXIT_FAILURE); } - auto cmd = std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0], xFDs[1], notifyFD, xwmFDs[1]); + auto cmd = + std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0].get(), xFDs[1].get(), notifyFD.get(), xwmFDs[1].get()); - auto waylandSocket = std::format("{}", waylandFDs[1]); + auto waylandSocket = std::format("{}", waylandFDs[1].get()); setenv("WAYLAND_SOCKET", waylandSocket.c_str(), true); Debug::log(LOG, "Starting XWayland with \"{}\", bon voyage!", cmd); @@ -327,40 +283,46 @@ void CXWaylandServer::runXWayland(int notifyFD) { } bool CXWaylandServer::start() { - idleSource = nullptr; - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, waylandFDs.data()) != 0) { + idleSource = nullptr; + int wlPair[2] = {-1, -1}; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, wlPair) != 0) { Debug::log(ERR, "socketpair failed (1)"); die(); return false; } + waylandFDs[0] = CFileDescriptor{wlPair[0]}; + waylandFDs[1] = CFileDescriptor{wlPair[1]}; - if (!setCloseOnExec(waylandFDs[0], true) || !setCloseOnExec(waylandFDs[1], true)) { + if (!waylandFDs[0].setFlags(waylandFDs[0].getFlags() | FD_CLOEXEC) || !waylandFDs[1].setFlags(waylandFDs[1].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (1)"); die(); return false; } - if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmFDs.data()) != 0) { + int xwmPair[2] = {-1, -1}; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmPair) != 0) { Debug::log(ERR, "socketpair failed (2)"); die(); return false; } - if (!setCloseOnExec(xwmFDs[0], true) || !setCloseOnExec(xwmFDs[1], true)) { + xwmFDs[0] = CFileDescriptor{xwmPair[0]}; + xwmFDs[1] = CFileDescriptor{xwmPair[1]}; + + if (!xwmFDs[0].setFlags(xwmFDs[0].getFlags() | FD_CLOEXEC) || !xwmFDs[1].setFlags(xwmFDs[1].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (2)"); die(); return false; } - xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0]); + xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0].get()); if (!xwaylandClient) { Debug::log(ERR, "wl_client_create failed"); die(); return false; } - waylandFDs[0] = -1; + waylandFDs[0].take(); // does this leak? int notify[2] = {-1, -1}; if (pipe(notify) < 0) { @@ -369,22 +331,20 @@ bool CXWaylandServer::start() { return false; } - if (!setCloseOnExec(notify[0], true)) { + CFileDescriptor notifyFds[2] = {CFileDescriptor{notify[0]}, CFileDescriptor{notify[1]}}; + + if (!notifyFds[0].setFlags(notifyFds[0].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (3)"); - close(notify[0]); - close(notify[1]); die(); return false; } - pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notify[0], WL_EVENT_READABLE, ::xwaylandReady, nullptr); - pipeFd = notify[0]; + pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notifyFds[0].get(), WL_EVENT_READABLE, ::xwaylandReady, nullptr); + pipeFd = std::move(notifyFds[0]); serverPID = fork(); if (serverPID < 0) { Debug::log(ERR, "fork failed"); - close(notify[0]); - close(notify[1]); die(); return false; } else if (serverPID == 0) { @@ -393,25 +353,19 @@ bool CXWaylandServer::start() { Debug::log(ERR, "second fork failed"); _exit(1); } else if (pid == 0) - runXWayland(notify[1]); + runXWayland(notifyFds[1]); _exit(0); } - close(notify[1]); - close(waylandFDs[1]); - closeSocketSafely(xwmFDs[1]); - waylandFDs[1] = -1; - xwmFDs[1] = -1; - return true; } -int CXWaylandServer::ready(int fd, uint32_t mask) { +int CXWaylandServer::ready(CFileDescriptor fd, uint32_t mask) { if (mask & WL_EVENT_READABLE) { // xwayland writes twice char buf[64]; - ssize_t n = read(fd, buf, sizeof(buf)); + ssize_t n = read(fd.get(), buf, sizeof(buf)); if (n < 0 && errno != EINTR) { Debug::log(ERR, "Xwayland: read from displayFd failed"); mask = 0; @@ -436,7 +390,6 @@ int CXWaylandServer::ready(int fd, uint32_t mask) { Debug::log(LOG, "XWayland is ready"); - close(fd); wl_event_source_remove(pipeSource); pipeSource = nullptr; diff --git a/src/xwayland/Server.hpp b/src/xwayland/Server.hpp index 7a36a965f..ccbcf6ea1 100644 --- a/src/xwayland/Server.hpp +++ b/src/xwayland/Server.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "../helpers/signal/Signal.hpp" struct wl_event_source; @@ -19,7 +20,7 @@ class CXWaylandServer { bool start(); // called on ready - int ready(int fd, uint32_t mask); + int ready(Hyprutils::OS::CFileDescriptor fd, uint32_t mask); void die(); @@ -30,20 +31,20 @@ class CXWaylandServer { wl_client* xwaylandClient = nullptr; private: - bool tryOpenSockets(); - void runXWayland(int notifyFD); + bool tryOpenSockets(); + void runXWayland(Hyprutils::OS::CFileDescriptor& notifyFD); - pid_t serverPID = 0; + pid_t serverPID = 0; - std::string displayName; - int display = -1; - std::array xFDs = {-1, -1}; - std::array xFDReadEvents = {nullptr, nullptr}; - wl_event_source* idleSource = nullptr; - wl_event_source* pipeSource = nullptr; - int pipeFd = -1; - std::array xwmFDs = {-1, -1}; - std::array waylandFDs = {-1, -1}; + std::string displayName; + int display = -1; + std::array xFDs; + std::array xFDReadEvents = {nullptr, nullptr}; + wl_event_source* idleSource = nullptr; + wl_event_source* pipeSource = nullptr; + Hyprutils::OS::CFileDescriptor pipeFd; + std::array xwmFDs; + std::array waylandFDs; friend class CXWM; }; diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index 4b0c5a295..e6282dcbd 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -5,6 +5,7 @@ #include "XDataSource.hpp" #include +using namespace Hyprutils::OS; CXDataSource::CXDataSource(SXSelection& sel_) : selection(sel_) { xcb_get_property_cookie_t cookie = xcb_get_property(g_pXWayland->pWM->connection, @@ -47,7 +48,7 @@ std::vector CXDataSource::mimes() { return mimeTypes; } -void CXDataSource::send(const std::string& mime, uint32_t fd) { +void CXDataSource::send(const std::string& mime, CFileDescriptor fd) { xcb_atom_t mimeAtom = 0; if (mime == "text/plain") @@ -65,11 +66,10 @@ void CXDataSource::send(const std::string& mime, uint32_t fd) { if (!mimeAtom) { Debug::log(ERR, "[XDataSource] mime atom not found"); - close(fd); return; } - Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd); + Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd.get()); selection.transfer = makeUnique(selection); selection.transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection); @@ -81,8 +81,9 @@ void CXDataSource::send(const std::string& mime, uint32_t fd) { xcb_flush(g_pXWayland->pWM->connection); - fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK); - selection.transfer->wlFD = fd; + //TODO: make CFileDescriptor setflags take SETFL aswell + fcntl(fd.get(), F_SETFL, O_WRONLY | O_NONBLOCK); + selection.transfer->wlFD = std::move(fd); } void CXDataSource::accepted(const std::string& mime) { @@ -101,4 +102,4 @@ eDataSourceType CXDataSource::type() { return DATA_SOURCE_TYPE_X11; } -#endif \ No newline at end of file +#endif diff --git a/src/xwayland/XDataSource.hpp b/src/xwayland/XDataSource.hpp index c629aa2a9..a61ffcc90 100644 --- a/src/xwayland/XDataSource.hpp +++ b/src/xwayland/XDataSource.hpp @@ -1,6 +1,7 @@ #pragma once #include "../protocols/types/DataDevice.hpp" +#include struct SXSelection; @@ -9,7 +10,7 @@ class CXDataSource : public IDataSource { CXDataSource(SXSelection&); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); @@ -19,4 +20,4 @@ class CXDataSource : public IDataSource { SXSelection& selection; std::vector mimeTypes; // these two have shared idx std::vector mimeAtoms; // -}; \ No newline at end of file +}; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 6673105e7..81900c7b4 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -17,6 +17,7 @@ #include "../managers/SeatManager.hpp" #include "../protocols/XWaylandShell.hpp" #include "../protocols/core/Compositor.hpp" +using namespace Hyprutils::OS; #define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f #define INCR_CHUNK_SIZE (64 * 1024) @@ -883,7 +884,7 @@ void CXWM::getRenderFormat() { free(reply); } -CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) { +CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0].get()) { if (connection.hasError()) { Debug::log(ERR, "[xwm] Couldn't start, error {}", connection.hasError()); @@ -901,7 +902,7 @@ CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) { xcb_screen_iterator_t screen_iterator = xcb_setup_roots_iterator(xcb_get_setup(connection)); screen = screen_iterator.data; - eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, g_pXWayland->pServer->xwmFDs[0], WL_EVENT_READABLE, ::onX11Event, nullptr); + eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, g_pXWayland->pServer->xwmFDs[0].get(), WL_EVENT_READABLE, ::onX11Event, nullptr); wl_event_source_check(eventSource); gatherResources(); @@ -1180,13 +1181,12 @@ void CXWM::getTransferData(SXSelection& sel) { if (sel.transfer->propertyReply->type == HYPRATOMS["INCR"]) { Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); - close(sel.transfer->wlFD); sel.transfer.reset(); return; } else { sel.onWrite(); if (sel.transfer) - sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD, WL_EVENT_WRITABLE, ::writeDataSource, &sel); + sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD.get(), WL_EVENT_WRITABLE, ::writeDataSource, &sel); } } @@ -1361,13 +1361,13 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { // the wayland client might not expect a non-blocking fd // fcntl(p[1], F_SETFL, O_NONBLOCK); - transfer->wlFD = p[0]; + transfer->wlFD = CFileDescriptor{p[0]}; Debug::log(LOG, "[xwm] sending wayland selection to xwayland with mime {}, target {}, fds {} {}", mime, e->target, p[0], p[1]); - selection->send(mime, p[1]); + selection->send(mime, CFileDescriptor{p[1]}); - transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD, WL_EVENT_READABLE, ::readDataSource, this); + transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD.get(), WL_EVENT_READABLE, ::readDataSource, this); return true; } @@ -1376,10 +1376,9 @@ int SXSelection::onWrite() { char* property = (char*)xcb_get_property_value(transfer->propertyReply); int remainder = xcb_get_property_value_length(transfer->propertyReply) - transfer->propertyStart; - ssize_t len = write(transfer->wlFD, property + transfer->propertyStart, remainder); + ssize_t len = write(transfer->wlFD.get(), property + transfer->propertyStart, remainder); if (len == -1) { Debug::log(ERR, "[xwm] write died in transfer get"); - close(transfer->wlFD); transfer.reset(); return 0; } @@ -1389,7 +1388,6 @@ int SXSelection::onWrite() { Debug::log(LOG, "[xwm] wl client read partially: len {}", len); } else { Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); - close(transfer->wlFD); transfer.reset(); } @@ -1397,8 +1395,6 @@ int SXSelection::onWrite() { } SXTransfer::~SXTransfer() { - if (wlFD) - close(wlFD); if (eventSource) wl_event_source_remove(eventSource); if (incomingWindow) diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index dfaf33b91..73a02a861 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -10,6 +10,7 @@ #include #include #include +#include struct wl_event_source; class CXWaylandSurfaceResource; @@ -18,25 +19,25 @@ struct SXSelection; struct SXTransfer { ~SXTransfer(); - SXSelection& selection; - bool out = true; + SXSelection& selection; + bool out = true; - bool incremental = false; - bool flushOnDelete = false; - bool propertySet = false; + bool incremental = false; + bool flushOnDelete = false; + bool propertySet = false; - int wlFD = -1; - wl_event_source* eventSource = nullptr; + Hyprutils::OS::CFileDescriptor wlFD; + wl_event_source* eventSource = nullptr; - std::vector data; + std::vector data; - xcb_selection_request_event_t request; + xcb_selection_request_event_t request; - int propertyStart; - xcb_get_property_reply_t* propertyReply; - xcb_window_t incomingWindow; + int propertyStart; + xcb_get_property_reply_t* propertyReply; + xcb_window_t incomingWindow; - bool getIncomingSelectionProp(bool erase); + bool getIncomingSelectionProp(bool erase); }; struct SXSelection {