From 9dac3902473c4e240a05430113aa9bd49af54d7d Mon Sep 17 00:00:00 2001 From: Anthony Birkett Date: Thu, 4 Jun 2015 14:13:07 +0100 Subject: Daemon support on Linux. Added null console log listener, avoid printf() when stdout is closed. --- Tools/MCADefrag/MCADefrag.cpp | 2 +- Tools/ProtoProxy/ProtoProxy.cpp | 2 +- src/Globals.h | 1 + src/LoggerListeners.cpp | 20 +++++++++++++++++- src/LoggerListeners.h | 2 +- src/Root.cpp | 2 +- src/main.cpp | 46 ++++++++++++++++++++++++++++++----------- 7 files changed, 58 insertions(+), 17 deletions(-) diff --git a/Tools/MCADefrag/MCADefrag.cpp b/Tools/MCADefrag/MCADefrag.cpp index 0d38a87f1..80c6f5be2 100644 --- a/Tools/MCADefrag/MCADefrag.cpp +++ b/Tools/MCADefrag/MCADefrag.cpp @@ -22,7 +22,7 @@ static const Byte g_Zeroes[4096] = {0}; int main(int argc, char ** argv) { - cLogger::cListener * consoleLogListener = MakeConsoleListener(); + cLogger::cListener * consoleLogListener = MakeConsoleListener(false); cLogger::cListener * fileLogListener = new cFileListener(); cLogger::GetInstance().AttachListener(consoleLogListener); cLogger::GetInstance().AttachListener(fileLogListener); diff --git a/Tools/ProtoProxy/ProtoProxy.cpp b/Tools/ProtoProxy/ProtoProxy.cpp index 3f427f83f..2d27d7556 100644 --- a/Tools/ProtoProxy/ProtoProxy.cpp +++ b/Tools/ProtoProxy/ProtoProxy.cpp @@ -16,7 +16,7 @@ int main(int argc, char ** argv) { // Initialize logging subsystem: cLogger::InitiateMultithreading(); - auto consoleLogListener = MakeConsoleListener(); + auto consoleLogListener = MakeConsoleListener(false); auto fileLogListener = new cFileListener(); cLogger::GetInstance().AttachListener(consoleLogListener); cLogger::GetInstance().AttachListener(fileLogListener); diff --git a/src/Globals.h b/src/Globals.h index e7b7fdcac..4c9091e85 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -221,6 +221,7 @@ template class SizeChecker; #include #include #include + #include #endif #if defined(ANDROID_NDK) diff --git a/src/LoggerListeners.cpp b/src/LoggerListeners.cpp index 31b12af1e..132751e8e 100644 --- a/src/LoggerListeners.cpp +++ b/src/LoggerListeners.cpp @@ -238,8 +238,26 @@ public: -cLogger::cListener * MakeConsoleListener(void) +// Listener for when stdout is closed, i.e. When running as a daemon. +class cNullConsoleListener + : public cLogger::cListener +{ + virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + { + } +}; + + + + + +cLogger::cListener * MakeConsoleListener(bool a_IsService) { + if (a_IsService) + { + return new cNullConsoleListener; + } + #ifdef _WIN32 // See whether we are writing to a console the default console attrib: bool ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); diff --git a/src/LoggerListeners.h b/src/LoggerListeners.h index c419aa75a..a7f9a35a5 100644 --- a/src/LoggerListeners.h +++ b/src/LoggerListeners.h @@ -25,7 +25,7 @@ private: -cLogger::cListener * MakeConsoleListener(); +cLogger::cListener * MakeConsoleListener(bool a_IsService); diff --git a/src/Root.cpp b/src/Root.cpp index 54e65b6da..8d344ee65 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -106,7 +106,7 @@ void cRoot::Start(std::unique_ptr overridesRepo) EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling #endif - cLogger::cListener * consoleLogListener = MakeConsoleListener(); + cLogger::cListener * consoleLogListener = MakeConsoleListener(m_RunAsService); cLogger::cListener * fileLogListener = new cFileListener(); cLogger::GetInstance().AttachListener(consoleLogListener); cLogger::GetInstance().AttachListener(fileLogListener); diff --git a/src/main.cpp b/src/main.cpp index 152339e12..2103f3356 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -250,7 +250,7 @@ void universalMain(std::unique_ptr overridesRepo) -#if defined(_WIN32) +#if defined(_WIN32) // Windows service support. //////////////////////////////////////////////////////////////////////////////// // serviceWorkerThread: Keep the service alive @@ -358,7 +358,7 @@ void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) serviceSetState(0, SERVICE_STOPPED, 0); } -#endif +#endif // Windows service support. @@ -378,7 +378,7 @@ std::unique_ptr parseArguments(int argc, char **argv) TCLAP::SwitchArg crashDumpFull ("", "crash-dump-full", "Crashdumps created by the server will contain full server memory", cmd); TCLAP::SwitchArg crashDumpGlobals("", "crash-dump-globals", "Crashdumps created by the server will contain the global variables' values", cmd); TCLAP::SwitchArg noBufArg ("", "no-output-buffering", "Disable output buffering", cmd); - TCLAP::SwitchArg runAsServiceArg ("d", "run-as-service", "Run as a service on Windows", cmd); + TCLAP::SwitchArg runAsServiceArg ("d", "service", "Run as a service on Windows, or daemon on UNIX like systems", cmd); cmd.parse(argc, argv); // Copy the parsed args' values into a settings repository: @@ -484,11 +484,11 @@ int main(int argc, char **argv) #endif auto argsRepo = parseArguments(argc, argv); - - #if defined(_WIN32) - // Attempt to run as a service - if (cRoot::m_RunAsService) - { + + // Attempt to run as a service + if (cRoot::m_RunAsService) + { + #if defined(_WIN32) // Windows service. SERVICE_TABLE_ENTRY ServiceTable[] = { { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain }, @@ -500,11 +500,33 @@ int main(int argc, char **argv) LOGERROR("Attempted, but failed, service startup."); return GetLastError(); } - } - else - #endif + #else // UNIX daemon. + pid_t pid = fork(); + + // fork() returns a negative value on error. + if (pid < 0) + { + LOGERROR("Could not fork process."); + return EXIT_FAILURE; + } + + // Check if we are the parent or child process. Parent stops here. + if (pid > 0) + { + return EXIT_SUCCESS; + } + + // Child process now goes quiet, running in the background. + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + universalMain(std::move(argsRepo)); + #endif + } + else { - // Not running as a Windows service, do normal startup + // Not running as a service, do normal startup universalMain(std::move(argsRepo)); } -- cgit v1.2.3