diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/daemon.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/daemon.cpp')
-rw-r--r-- | util/system/daemon.cpp | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/util/system/daemon.cpp b/util/system/daemon.cpp new file mode 100644 index 0000000000..130e6c8f45 --- /dev/null +++ b/util/system/daemon.cpp @@ -0,0 +1,168 @@ +#include <util/generic/yexception.h> + +#include <cerrno> +#include <cstdlib> +#include <util/system/info.h> + +#if defined(_win_) + #include <io.h> +#else + #include <sys/wait.h> + #include <unistd.h> + #include <fcntl.h> +#endif + +#include "daemon.h" + +#ifdef _unix_ +using namespace NDaemonMaker; + +static bool Fork(EParent parent) { + pid_t pid = fork(); + + if (pid > 0) { + int status = 0; + while (waitpid(pid, &status, 0) < 0 && errno == EINTR) { + } + if (parent == callExitFromParent) { + _exit(0); + } else { + return true; + } + } else if (pid < 0) { + ythrow TSystemError() << "Cannot fork"; + } + + if (setsid() < 0) { + ythrow TSystemError() << "Cannot setsid"; + } + + pid = fork(); + + if (pid > 0) { + _exit(0); + } else if (pid < 0) { + ythrow TSystemError() << "Cannot second fork"; + } + return false; +} + +#endif + +static void CloseFromToExcept(int from, int to, const int* except) { + (void)from; + (void)to; + (void)except; + +#ifdef _unix_ + int mfd = NSystemInfo::MaxOpenFiles(); + for (int s = from; s < mfd && (to == -1 || s < to); s++) { + for (const int* ex = except; *ex >= 0; ++ex) { + if (s == *ex) { + goto dontclose; + } + } + while (close(s) == -1) { + if (errno == EBADF) { + break; + } + if (errno != EINTR) { + ythrow TSystemError() << "close(" << s << ") failed"; + } + } + dontclose:; + } +#endif /* _unix_ */ +} + +bool NDaemonMaker::MakeMeDaemon(ECloseDescriptors cd, EStdIoDescriptors iod, EChDir chd, EParent parent) { + (void)cd; + (void)iod; + (void)chd; + +#ifdef _unix_ + if (Fork(parent)) { + return true; + } + + if (chd == chdirRoot) { + if (chdir("/")) { + ythrow TSystemError() << "chdir(\"/\") failed"; + } + } + + int fd[4] = {-1, -1, -1, -1}; + switch (iod) { + case openYandexStd: + fd[0] = open("yandex.stdin", O_RDONLY); + if (fd[0] < 0) { + ythrow TSystemError() << "Cannot open 'yandex.stdin'"; + } + fd[1] = open("yandex.stdout", O_WRONLY | O_APPEND | O_CREAT, 660); + if (fd[1] < 0) { + ythrow TSystemError() << "Cannot open 'yandex.stdout'"; + } + fd[2] = open("yandex.stderr", O_WRONLY | O_APPEND | O_CREAT, 660); + if (fd[2] < 0) { + ythrow TSystemError() << "Cannot open 'yandex.stderr'"; + } + break; + case openDevNull: + fd[0] = open("/dev/null", O_RDWR, 0); + break; + case openNone: + break; + default: + ythrow yexception() << "Unknown open descriptors mode: " << (int)iod; + } + + const int except[4] = { + fd[0], + fd[1], + fd[2], + -1}; + if (closeAll == cd) { + CloseFromToExcept(0, -1, except); + } else if (closeStdIoOnly == cd) { + CloseFromToExcept(0, 3, except); + } else { + ythrow yexception() << "Unknown close descriptors mode: " << (int)cd; + } + + switch (iod) { + case openYandexStd: + /* Assuming that open(2) acquires fds in order. */ + dup2(fd[0], STDIN_FILENO); + if (fd[0] > 2) { + close(fd[0]); + } + dup2(fd[1], STDOUT_FILENO); + if (fd[1] > 2) { + close(fd[1]); + } + dup2(fd[2], STDERR_FILENO); + if (fd[2] > 2) { + close(fd[2]); + } + break; + case openDevNull: + dup2(fd[0], STDIN_FILENO); + dup2(fd[0], STDOUT_FILENO); + dup2(fd[0], STDERR_FILENO); + if (fd[0] > 2) { + close(fd[0]); + } + break; + default: + break; + } + return false; +#else + return true; +#endif +} + +void NDaemonMaker::CloseFrom(int fd) { + static const int except[1] = {-1}; + CloseFromToExcept(fd, -1, except); +} |