daemon.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #include <util/generic/yexception.h>
  2. #include <cerrno>
  3. #include <cstdlib>
  4. #include <util/system/info.h>
  5. #if defined(_win_)
  6. #include <io.h>
  7. #else
  8. #include <sys/wait.h>
  9. #include <unistd.h>
  10. #include <fcntl.h>
  11. #endif
  12. #include "daemon.h"
  13. #ifdef _unix_
  14. using namespace NDaemonMaker;
  15. static bool Fork(EParent parent) {
  16. pid_t pid = fork();
  17. if (pid > 0) {
  18. int status = 0;
  19. while (waitpid(pid, &status, 0) < 0 && errno == EINTR) {
  20. }
  21. if (parent == callExitFromParent) {
  22. _exit(0);
  23. } else {
  24. return true;
  25. }
  26. } else if (pid < 0) {
  27. ythrow TSystemError() << "Cannot fork";
  28. }
  29. if (setsid() < 0) {
  30. ythrow TSystemError() << "Cannot setsid";
  31. }
  32. pid = fork();
  33. if (pid > 0) {
  34. _exit(0);
  35. } else if (pid < 0) {
  36. ythrow TSystemError() << "Cannot second fork";
  37. }
  38. return false;
  39. }
  40. #endif
  41. static void CloseFromToExcept(int from, int to, const int* except) {
  42. (void)from;
  43. (void)to;
  44. (void)except;
  45. #ifdef _unix_
  46. int mfd = NSystemInfo::MaxOpenFiles();
  47. for (int s = from; s < mfd && (to == -1 || s < to); s++) {
  48. for (const int* ex = except; *ex >= 0; ++ex) {
  49. if (s == *ex) {
  50. goto dontclose;
  51. }
  52. }
  53. while (close(s) == -1) {
  54. if (errno == EBADF) {
  55. break;
  56. }
  57. if (errno != EINTR) {
  58. ythrow TSystemError() << "close(" << s << ") failed";
  59. }
  60. }
  61. dontclose:;
  62. }
  63. #endif /* _unix_ */
  64. }
  65. bool NDaemonMaker::MakeMeDaemon(ECloseDescriptors cd, EStdIoDescriptors iod, EChDir chd, EParent parent) {
  66. (void)cd;
  67. (void)iod;
  68. (void)chd;
  69. #ifdef _unix_
  70. if (Fork(parent)) {
  71. return true;
  72. }
  73. if (chd == chdirRoot) {
  74. if (chdir("/")) {
  75. ythrow TSystemError() << "chdir(\"/\") failed";
  76. }
  77. }
  78. int fd[4] = {-1, -1, -1, -1};
  79. switch (iod) {
  80. case openYandexStd:
  81. fd[0] = open("yandex.stdin", O_RDONLY);
  82. if (fd[0] < 0) {
  83. ythrow TSystemError() << "Cannot open 'yandex.stdin'";
  84. }
  85. fd[1] = open("yandex.stdout", O_WRONLY | O_APPEND | O_CREAT, 660);
  86. if (fd[1] < 0) {
  87. ythrow TSystemError() << "Cannot open 'yandex.stdout'";
  88. }
  89. fd[2] = open("yandex.stderr", O_WRONLY | O_APPEND | O_CREAT, 660);
  90. if (fd[2] < 0) {
  91. ythrow TSystemError() << "Cannot open 'yandex.stderr'";
  92. }
  93. break;
  94. case openDevNull:
  95. fd[0] = open("/dev/null", O_RDWR, 0);
  96. break;
  97. case openNone:
  98. break;
  99. default:
  100. ythrow yexception() << "Unknown open descriptors mode: " << (int)iod;
  101. }
  102. const int except[4] = {
  103. fd[0],
  104. fd[1],
  105. fd[2],
  106. -1};
  107. if (closeAll == cd) {
  108. CloseFromToExcept(0, -1, except);
  109. } else if (closeStdIoOnly == cd) {
  110. CloseFromToExcept(0, 3, except);
  111. } else {
  112. ythrow yexception() << "Unknown close descriptors mode: " << (int)cd;
  113. }
  114. switch (iod) {
  115. case openYandexStd:
  116. /* Assuming that open(2) acquires fds in order. */
  117. dup2(fd[0], STDIN_FILENO);
  118. if (fd[0] > 2) {
  119. close(fd[0]);
  120. }
  121. dup2(fd[1], STDOUT_FILENO);
  122. if (fd[1] > 2) {
  123. close(fd[1]);
  124. }
  125. dup2(fd[2], STDERR_FILENO);
  126. if (fd[2] > 2) {
  127. close(fd[2]);
  128. }
  129. break;
  130. case openDevNull:
  131. dup2(fd[0], STDIN_FILENO);
  132. dup2(fd[0], STDOUT_FILENO);
  133. dup2(fd[0], STDERR_FILENO);
  134. if (fd[0] > 2) {
  135. close(fd[0]);
  136. }
  137. break;
  138. default:
  139. break;
  140. }
  141. return false;
  142. #else
  143. return true;
  144. #endif
  145. }
  146. void NDaemonMaker::CloseFrom(int fd) {
  147. static const int except[1] = {-1};
  148. CloseFromToExcept(fd, -1, except);
  149. }