diff --git a/coolwsd.xml.in b/coolwsd.xml.in index c90136fc9a..4b6f7c8a90 100644 --- a/coolwsd.xml.in +++ b/coolwsd.xml.in @@ -269,6 +269,8 @@ + false + diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 04213c3f66..046b18fe29 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -162,6 +162,12 @@ using Poco::Net::PartHandler; #endif #endif +#ifdef __linux__ +#if !MOBILEAPP +#include +#endif +#endif + using namespace COOLProtocol; using Poco::DirectoryIterator; @@ -1001,6 +1007,109 @@ private: /// And also cleans up and balances the correct number of children. static std::unique_ptr PrisonerPoll; +#ifdef __linux__ +#if !MOBILEAPP +class InotifySocket : public Socket +{ +public: + InotifySocket(): + Socket(inotify_init1(IN_NONBLOCK)) + , m_stopOnConfigChange(true) + { + if (getFD() == -1) + { + LOG_WRN("Inotify - Failed to start a watcher for the configuration, disabling " + "stop_on_config_change"); + m_stopOnConfigChange = false; + return; + } + + watch(COOLWSD_CONFIGDIR); + } + + /// Check for file changes, stop the server if we find any + void handlePoll(SocketDisposition &disposition, std::chrono::steady_clock::time_point now, int events) override; + + int getPollEvents(std::chrono::steady_clock::time_point /* now */, + int64_t & /* timeoutMaxMicroS */) override + { + return POLLIN; + } + + bool watch(std::string configFile); + +private: + bool m_stopOnConfigChange; + int m_watchedCount = 0; +}; + +bool InotifySocket::watch(const std::string configFile) +{ + LOG_TRC("Inotify - Attempting to watch " << configFile << ", in addition to current " + << m_watchedCount << " watched files"); + + if (getFD() == -1) + { + LOG_WRN("Inotify - Trying to watch config file " << configFile + << " without an inotify file descriptor"); + return false; + } + + int watchedStatus; + watchedStatus = inotify_add_watch(getFD(), configFile.c_str(), IN_MODIFY); + + if (watchedStatus == -1) + LOG_WRN("Inotify - Failed to watch config file " << configFile); + else + m_watchedCount++; + + return watchedStatus != -1; +} + +void InotifySocket::handlePoll(SocketDisposition & /* disposition */, std::chrono::steady_clock::time_point /* now */, int /* events */) +{ + LOG_TRC("InotifyPoll - woken up. Reload on config change: " + << m_stopOnConfigChange << ", Watching " << m_watchedCount << " files"); + if (!m_stopOnConfigChange) + return; + + char buf[4096]; + const struct inotify_event* event; + ssize_t len; + + LOG_TRC("InotifyPoll - Checking for config changes..."); + + while (true) + { + len = read(getFD(), buf, sizeof(buf)); + + if (len == -1 && errno != EAGAIN) + { + // Some read error, EAGAIN is when there is no data so let's not warn for it + LOG_WRN("InotifyPoll - Read error " << std::strerror(errno) + << " when trying to get events"); + } + else if (len == -1) + { + LOG_TRC("InotifyPoll - Got to end of data when reading inotify"); + } + + if (len <= 0) + break; + + for (char* ptr = buf; ptr < buf + len; ptr += sizeof(struct inotify_event) + event->len) + { + event = (const struct inotify_event*)ptr; + + LOG_WRN("InotifyPoll - Config file " << event->name << " was modified, stopping COOLWSD"); + SigUtil::requestShutdown(); + } + } +} + +#endif // if !MOBILEAPP +#endif // #ifdef __linux__ + /// The Web Server instance with the accept socket poll thread. class COOLWSDServer; static std::unique_ptr Server; @@ -2034,6 +2143,7 @@ void COOLWSD::innerInitialize(Application& self) { "ssl.sts.max_age", "31536000" }, { "ssl.key_file_path", COOLWSD_CONFIGDIR "/key.pem" }, { "ssl.termination", "true" }, + { "stop_on_config_change", "false" }, { "storage.filesystem[@allow]", "false" }, // "storage.ssl.enable" - deliberately not set; for back-compat { "storage.wopi.max_file_size", "0" }, @@ -5809,6 +5919,13 @@ int COOLWSD::innerMain() const auto startStamp = std::chrono::steady_clock::now(); #if !MOBILEAPP auto stampFetch = startStamp - (fetchUpdateCheck - std::chrono::milliseconds(60000)); + +#ifdef __linux__ + if (getConfigValue("stop_on_config_change", false)) { + std::shared_ptr inotifySocket = std::make_shared(); + mainWait.insertNewSocket(inotifySocket); + } +#endif #endif while (!SigUtil::getShutdownRequestFlag())