daemon.cpp 4.0 KB

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