#include #include #include #if defined(_win_) #include #else #include #include #include #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); }