* Daemonize(). On error, this function logs by itself and exits (i.e. does not return). * * Implementation note: We're only supposed to call exit() in one of the forked processes. * The other process calls _exit(). This prevents issues with exit handlers like atexit(). */
| 67 | * The other process calls _exit(). This prevents issues with exit handlers like atexit(). |
| 68 | */ |
| 69 | static void Daemonize() noexcept |
| 70 | { |
| 71 | #ifndef _WIN32 |
| 72 | try { |
| 73 | Application::UninitializeBase(); |
| 74 | } catch (const std::exception& ex) { |
| 75 | Log(LogCritical, "cli") |
| 76 | << "Failed to stop thread pool before daemonizing, unexpected error: " << DiagnosticInformation(ex); |
| 77 | exit(EXIT_FAILURE); |
| 78 | } |
| 79 | |
| 80 | pid_t pid = fork(); |
| 81 | if (pid == -1) { |
| 82 | Log(LogCritical, "cli") |
| 83 | << "fork() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; |
| 84 | exit(EXIT_FAILURE); |
| 85 | } |
| 86 | |
| 87 | if (pid) { |
| 88 | // systemd requires that the pidfile of the daemon is written before the forking |
| 89 | // process terminates. So wait till either the forked daemon has written a pidfile or died. |
| 90 | |
| 91 | int status; |
| 92 | int ret; |
| 93 | pid_t readpid; |
| 94 | do { |
| 95 | Utility::Sleep(0.1); |
| 96 | |
| 97 | readpid = Application::ReadPidFile(Configuration::PidPath); |
| 98 | ret = waitpid(pid, &status, WNOHANG); |
| 99 | } while (readpid != pid && ret == 0); |
| 100 | |
| 101 | if (ret == pid) { |
| 102 | Log(LogCritical, "cli", "The daemon could not be started. See log output for details."); |
| 103 | _exit(EXIT_FAILURE); |
| 104 | } else if (ret == -1) { |
| 105 | Log(LogCritical, "cli") |
| 106 | << "waitpid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; |
| 107 | _exit(EXIT_FAILURE); |
| 108 | } |
| 109 | |
| 110 | _exit(EXIT_SUCCESS); |
| 111 | } |
| 112 | |
| 113 | Log(LogDebug, "Daemonize()") |
| 114 | << "Child process with PID " << Utility::GetPid() << " continues; re-initializing base."; |
| 115 | |
| 116 | // Detach from controlling terminal |
| 117 | pid_t sid = setsid(); |
| 118 | if (sid == -1) { |
| 119 | Log(LogCritical, "cli") |
| 120 | << "setsid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; |
| 121 | exit(EXIT_FAILURE); |
| 122 | } |
| 123 | |
| 124 | try { |
| 125 | Application::InitializeBase(); |
| 126 | } catch (const std::exception& ex) { |