PageRenderTime 55ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/fpm/fpm_stdio.c

http://github.com/dreamcat4/php-fpm
C | 286 lines | 217 code | 61 blank | 8 comment | 56 complexity | 4b14f724d0823554fadfa41f066a131b MD5 | raw file
  1. /* $Id: fpm_stdio.c,v 1.22.2.2 2008/12/13 03:32:24 anight Exp $ */
  2. /* (c) 2007,2008 Andrei Nigmatulin */
  3. #include "fpm_config.h"
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <string.h>
  7. #include <fcntl.h>
  8. #include <unistd.h>
  9. #include <errno.h>
  10. #include "fpm.h"
  11. #include "fpm_children.h"
  12. #include "fpm_events.h"
  13. #include "fpm_sockets.h"
  14. #include "fpm_stdio.h"
  15. #include "zlog.h"
  16. static int fd_stdout[2];
  17. static int fd_stderr[2];
  18. int fpm_stdio_init_main()
  19. {
  20. int fd = open("/dev/null", O_RDWR);
  21. if (0 > fd) {
  22. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(\"/dev/null\") failed");
  23. return -1;
  24. }
  25. if (0 > dup2(fd, STDIN_FILENO) || 0 > dup2(fd, STDOUT_FILENO)) {
  26. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed");
  27. return -1;
  28. }
  29. close(fd);
  30. return 0;
  31. }
  32. int fpm_stdio_init_final()
  33. {
  34. if (fpm_global_config.daemonize) {
  35. if (fpm_globals.error_log_fd != STDERR_FILENO) {
  36. /* there might be messages to stderr from libevent, we need to log them all */
  37. if (0 > dup2(fpm_globals.error_log_fd, STDERR_FILENO)) {
  38. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed");
  39. return -1;
  40. }
  41. }
  42. zlog_set_level(fpm_globals.log_level);
  43. zlog_set_fd(fpm_globals.error_log_fd);
  44. }
  45. return 0;
  46. }
  47. int fpm_stdio_init_child(struct fpm_worker_pool_s *wp)
  48. {
  49. close(fpm_globals.error_log_fd);
  50. fpm_globals.error_log_fd = -1;
  51. zlog_set_fd(-1);
  52. if (wp->listening_socket != STDIN_FILENO) {
  53. if (0 > dup2(wp->listening_socket, STDIN_FILENO)) {
  54. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed");
  55. return -1;
  56. }
  57. }
  58. return 0;
  59. }
  60. static void fpm_stdio_child_said(int fd, short which, void *arg)
  61. {
  62. static const int max_buf_size = 1024;
  63. char buf[max_buf_size];
  64. struct fpm_child_s *child = arg;
  65. int is_stdout = fd == child->fd_stdout;
  66. struct event *ev = is_stdout ? &child->ev_stdout : &child->ev_stderr;
  67. int fifo_in = 1, fifo_out = 1;
  68. int is_last_message = 0;
  69. int in_buf = 0;
  70. int res;
  71. #if 0
  72. zlog(ZLOG_STUFF, ZLOG_DEBUG, "child %d said %s", (int) child->pid, is_stdout ? "stdout" : "stderr");
  73. #endif
  74. while (fifo_in || fifo_out) {
  75. if (fifo_in) {
  76. res = read(fd, buf + in_buf, max_buf_size - 1 - in_buf);
  77. if (res <= 0) { /* no data */
  78. fifo_in = 0;
  79. if (res < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
  80. /* just no more data ready */
  81. }
  82. else { /* error or pipe is closed */
  83. if (res < 0) { /* error */
  84. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "read() failed");
  85. }
  86. fpm_event_del(ev);
  87. is_last_message = 1;
  88. if (is_stdout) {
  89. close(child->fd_stdout);
  90. child->fd_stdout = -1;
  91. }
  92. else {
  93. close(child->fd_stderr);
  94. child->fd_stderr = -1;
  95. }
  96. #if 0
  97. if (in_buf == 0 && !fpm_globals.is_child) {
  98. zlog(ZLOG_STUFF, ZLOG_DEBUG, "child %d (pool %s) %s pipe is closed", (int) child->pid,
  99. child->wp->config->name, is_stdout ? "stdout" : "stderr");
  100. }
  101. #endif
  102. }
  103. }
  104. else {
  105. in_buf += res;
  106. }
  107. }
  108. if (fifo_out) {
  109. if (in_buf == 0) {
  110. fifo_out = 0;
  111. }
  112. else {
  113. char *nl;
  114. int should_print = 0;
  115. buf[in_buf] = '\0';
  116. /* FIXME: there might be binary data */
  117. /* we should print if no more space in the buffer */
  118. if (in_buf == max_buf_size - 1) {
  119. should_print = 1;
  120. }
  121. /* we should print if no more data to come */
  122. if (!fifo_in) {
  123. should_print = 1;
  124. }
  125. nl = strchr(buf, '\n');
  126. if (nl || should_print) {
  127. if (nl) {
  128. *nl = '\0';
  129. }
  130. zlog(ZLOG_STUFF, ZLOG_WARNING, "child %d (pool %s) said into %s: \"%s\"%s", (int) child->pid,
  131. child->wp->config->name, is_stdout ? "stdout" : "stderr", buf, is_last_message ? ", pipe is closed" : "");
  132. if (nl) {
  133. int out_buf = 1 + nl - buf;
  134. memmove(buf, buf + out_buf, in_buf - out_buf);
  135. in_buf -= out_buf;
  136. }
  137. else {
  138. in_buf = 0;
  139. }
  140. }
  141. }
  142. }
  143. }
  144. }
  145. int fpm_stdio_prepare_pipes(struct fpm_child_s *child)
  146. {
  147. if (0 == child->wp->config->catch_workers_output) { /* not required */
  148. return 0;
  149. }
  150. if (0 > pipe(fd_stdout)) {
  151. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pipe() failed");
  152. return -1;
  153. }
  154. if (0 > pipe(fd_stderr)) {
  155. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pipe() failed");
  156. close(fd_stdout[0]); close(fd_stdout[1]);
  157. return -1;
  158. }
  159. if (0 > fd_set_blocked(fd_stdout[0], 0) || 0 > fd_set_blocked(fd_stderr[0], 0)) {
  160. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fd_set_blocked() failed");
  161. close(fd_stdout[0]); close(fd_stdout[1]);
  162. close(fd_stderr[0]); close(fd_stderr[1]);
  163. return -1;
  164. }
  165. return 0;
  166. }
  167. int fpm_stdio_parent_use_pipes(struct fpm_child_s *child)
  168. {
  169. if (0 == child->wp->config->catch_workers_output) { /* not required */
  170. return 0;
  171. }
  172. close(fd_stdout[1]);
  173. close(fd_stderr[1]);
  174. child->fd_stdout = fd_stdout[0];
  175. child->fd_stderr = fd_stderr[0];
  176. fpm_event_add(child->fd_stdout, &child->ev_stdout, fpm_stdio_child_said, child);
  177. fpm_event_add(child->fd_stderr, &child->ev_stderr, fpm_stdio_child_said, child);
  178. return 0;
  179. }
  180. int fpm_stdio_discard_pipes(struct fpm_child_s *child)
  181. {
  182. if (0 == child->wp->config->catch_workers_output) { /* not required */
  183. return 0;
  184. }
  185. close(fd_stdout[1]);
  186. close(fd_stderr[1]);
  187. close(fd_stdout[0]);
  188. close(fd_stderr[0]);
  189. return 0;
  190. }
  191. void fpm_stdio_child_use_pipes(struct fpm_child_s *child)
  192. {
  193. if (child->wp->config->catch_workers_output) {
  194. dup2(fd_stdout[1], STDOUT_FILENO);
  195. dup2(fd_stderr[1], STDERR_FILENO);
  196. close(fd_stdout[0]); close(fd_stdout[1]);
  197. close(fd_stderr[0]); close(fd_stderr[1]);
  198. }
  199. else {
  200. /* stdout of parent is always /dev/null */
  201. dup2(STDOUT_FILENO, STDERR_FILENO);
  202. }
  203. }
  204. int fpm_stdio_open_error_log(int reopen)
  205. {
  206. int fd;
  207. fd = open(fpm_global_config.error_log, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
  208. if (0 > fd) {
  209. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(\"%s\") failed", fpm_global_config.error_log);
  210. return -1;
  211. }
  212. if (reopen) {
  213. if (fpm_global_config.daemonize) {
  214. dup2(fd, STDERR_FILENO);
  215. }
  216. dup2(fd, fpm_globals.error_log_fd);
  217. close(fd);
  218. fd = fpm_globals.error_log_fd; /* for FD_CLOSEXEC to work */
  219. }
  220. else {
  221. fpm_globals.error_log_fd = fd;
  222. }
  223. fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
  224. return 0;
  225. }