Back to index

php5  5.3.10
fpm_stdio.c
Go to the documentation of this file.
00001 
00002        /* $Id: fpm_stdio.c,v 1.22.2.2 2008/12/13 03:32:24 anight Exp $ */
00003        /* (c) 2007,2008 Andrei Nigmatulin */
00004 
00005 #include "fpm_config.h"
00006 
00007 #include <sys/types.h>
00008 #include <sys/stat.h>
00009 #include <string.h>
00010 #include <fcntl.h>
00011 #include <unistd.h>
00012 #include <errno.h>
00013 
00014 #include "php_syslog.h"
00015 
00016 #include "fpm.h"
00017 #include "fpm_children.h"
00018 #include "fpm_events.h"
00019 #include "fpm_sockets.h"
00020 #include "fpm_stdio.h"
00021 #include "zlog.h"
00022 
00023 static int fd_stdout[2];
00024 static int fd_stderr[2];
00025 
00026 int fpm_stdio_init_main() /* {{{ */
00027 {
00028        int fd = open("/dev/null", O_RDWR);
00029 
00030        if (0 > fd) {
00031               zlog(ZLOG_SYSERROR, "failed to init stdio: open(\"/dev/null\")");
00032               return -1;
00033        }
00034 
00035        if (0 > dup2(fd, STDIN_FILENO) || 0 > dup2(fd, STDOUT_FILENO)) {
00036               zlog(ZLOG_SYSERROR, "failed to init stdio: dup2()");
00037               return -1;
00038        }
00039        close(fd);
00040        return 0;
00041 }
00042 /* }}} */
00043 
00044 int fpm_stdio_init_final() /* {{{ */
00045 {
00046        if (fpm_global_config.daemonize) {
00047               /* prevent duping if logging to syslog */
00048               if (fpm_globals.error_log_fd > 0 && fpm_globals.error_log_fd != STDERR_FILENO) {
00049 
00050                      /* there might be messages to stderr from other parts of the code, we need to log them all */
00051                      if (0 > dup2(fpm_globals.error_log_fd, STDERR_FILENO)) {
00052                             zlog(ZLOG_SYSERROR, "failed to init stdio: dup2()");
00053                             return -1;
00054                      }
00055               }
00056        }
00057        zlog_set_launched();
00058        return 0;
00059 }
00060 /* }}} */
00061 
00062 int fpm_stdio_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
00063 {
00064 #ifdef HAVE_SYSLOG_H
00065        if (fpm_globals.error_log_fd == ZLOG_SYSLOG) {
00066               closelog(); /* ensure to close syslog not to interrupt with PHP syslog code */
00067        } else
00068 #endif
00069        if (fpm_globals.error_log_fd > 0) {
00070               close(fpm_globals.error_log_fd);
00071        }
00072        fpm_globals.error_log_fd = -1;
00073        zlog_set_fd(-1);
00074 
00075        if (wp->listening_socket != STDIN_FILENO) {
00076               if (0 > dup2(wp->listening_socket, STDIN_FILENO)) {
00077                      zlog(ZLOG_SYSERROR, "failed to init child stdio: dup2()");
00078                      return -1;
00079               }
00080        }
00081        return 0;
00082 }
00083 /* }}} */
00084 
00085 static void fpm_stdio_child_said(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
00086 {
00087        static const int max_buf_size = 1024;
00088        int fd = ev->fd;
00089        char buf[max_buf_size];
00090        struct fpm_child_s *child;
00091        int is_stdout;
00092        struct fpm_event_s *event;
00093        int fifo_in = 1, fifo_out = 1;
00094        int is_last_message = 0;
00095        int in_buf = 0;
00096        int res;
00097 
00098        if (!arg) {
00099               return;
00100        }
00101        child = (struct fpm_child_s *)arg;
00102        is_stdout = (fd == child->fd_stdout);
00103        if (is_stdout) {
00104               event = &child->ev_stdout;
00105        } else {
00106               event = &child->ev_stderr;
00107        }
00108 
00109        while (fifo_in || fifo_out) {
00110               if (fifo_in) {
00111                      res = read(fd, buf + in_buf, max_buf_size - 1 - in_buf);
00112                      if (res <= 0) { /* no data */
00113                             fifo_in = 0;
00114                             if (res < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
00115                                    /* just no more data ready */
00116                             } else { /* error or pipe is closed */
00117 
00118                                    if (res < 0) { /* error */
00119                                           zlog(ZLOG_SYSERROR, "unable to read what child say");
00120                                    }
00121 
00122                                    fpm_event_del(event);
00123                                    is_last_message = 1;
00124 
00125                                    if (is_stdout) {
00126                                           close(child->fd_stdout);
00127                                           child->fd_stdout = -1;
00128                                    } else {
00129                                           close(child->fd_stderr);
00130                                           child->fd_stderr = -1;
00131                                    }
00132                             }
00133                      } else {
00134                             in_buf += res;
00135                      }
00136               }
00137 
00138               if (fifo_out) {
00139                      if (in_buf == 0) {
00140                             fifo_out = 0;
00141                      } else {
00142                             char *nl;
00143                             int should_print = 0;
00144                             buf[in_buf] = '\0';
00145 
00146                             /* FIXME: there might be binary data */
00147 
00148                             /* we should print if no more space in the buffer */
00149                             if (in_buf == max_buf_size - 1) {
00150                                    should_print = 1;
00151                             }
00152 
00153                             /* we should print if no more data to come */
00154                             if (!fifo_in) {
00155                                    should_print = 1;
00156                             }
00157 
00158                             nl = strchr(buf, '\n');
00159                             if (nl || should_print) {
00160 
00161                                    if (nl) {
00162                                           *nl = '\0';
00163                                    }
00164 
00165                                    zlog(ZLOG_WARNING, "[pool %s] child %d said into %s: \"%s\"%s", child->wp->config->name,
00166                                      (int) child->pid, is_stdout ? "stdout" : "stderr", buf, is_last_message ? ", pipe is closed" : "");
00167 
00168                                    if (nl) {
00169                                           int out_buf = 1 + nl - buf;
00170                                           memmove(buf, buf + out_buf, in_buf - out_buf);
00171                                           in_buf -= out_buf;
00172                                    } else {
00173                                           in_buf = 0;
00174                                    }
00175                             }
00176                      }
00177               }
00178        }
00179 }
00180 /* }}} */
00181 
00182 int fpm_stdio_prepare_pipes(struct fpm_child_s *child) /* {{{ */
00183 {
00184        if (0 == child->wp->config->catch_workers_output) { /* not required */
00185               return 0;
00186        }
00187 
00188        if (0 > pipe(fd_stdout)) {
00189               zlog(ZLOG_SYSERROR, "failed to prepare the stdout pipe");
00190               return -1;
00191        }
00192 
00193        if (0 > pipe(fd_stderr)) {
00194               zlog(ZLOG_SYSERROR, "failed to prepare the stderr pipe");
00195               close(fd_stdout[0]);
00196               close(fd_stdout[1]);
00197               return -1;
00198        }
00199 
00200        if (0 > fd_set_blocked(fd_stdout[0], 0) || 0 > fd_set_blocked(fd_stderr[0], 0)) {
00201               zlog(ZLOG_SYSERROR, "failed to unblock pipes");
00202               close(fd_stdout[0]);
00203               close(fd_stdout[1]);
00204               close(fd_stderr[0]);
00205               close(fd_stderr[1]);
00206               return -1;
00207        }
00208        return 0;
00209 }
00210 /* }}} */
00211 
00212 int fpm_stdio_parent_use_pipes(struct fpm_child_s *child) /* {{{ */
00213 {
00214        if (0 == child->wp->config->catch_workers_output) { /* not required */
00215               return 0;
00216        }
00217 
00218        close(fd_stdout[1]);
00219        close(fd_stderr[1]);
00220 
00221        child->fd_stdout = fd_stdout[0];
00222        child->fd_stderr = fd_stderr[0];
00223 
00224        fpm_event_set(&child->ev_stdout, child->fd_stdout, FPM_EV_READ, fpm_stdio_child_said, child);
00225        fpm_event_add(&child->ev_stdout, 0);
00226 
00227        fpm_event_set(&child->ev_stderr, child->fd_stderr, FPM_EV_READ, fpm_stdio_child_said, child);
00228        fpm_event_add(&child->ev_stderr, 0);
00229        return 0;
00230 }
00231 /* }}} */
00232 
00233 int fpm_stdio_discard_pipes(struct fpm_child_s *child) /* {{{ */
00234 {
00235        if (0 == child->wp->config->catch_workers_output) { /* not required */
00236               return 0;
00237        }
00238 
00239        close(fd_stdout[1]);
00240        close(fd_stderr[1]);
00241 
00242        close(fd_stdout[0]);
00243        close(fd_stderr[0]);
00244        return 0;
00245 }
00246 /* }}} */
00247 
00248 void fpm_stdio_child_use_pipes(struct fpm_child_s *child) /* {{{ */
00249 {
00250        if (child->wp->config->catch_workers_output) {
00251               dup2(fd_stdout[1], STDOUT_FILENO);
00252               dup2(fd_stderr[1], STDERR_FILENO);
00253               close(fd_stdout[0]); close(fd_stdout[1]);
00254               close(fd_stderr[0]); close(fd_stderr[1]);
00255        } else {
00256               /* stdout of parent is always /dev/null */
00257               dup2(STDOUT_FILENO, STDERR_FILENO);
00258        }
00259 }
00260 /* }}} */
00261 
00262 int fpm_stdio_open_error_log(int reopen) /* {{{ */
00263 {
00264        int fd;
00265 
00266 #ifdef HAVE_SYSLOG_H
00267        if (!strcasecmp(fpm_global_config.error_log, "syslog")) {
00268               openlog(fpm_global_config.syslog_ident, LOG_PID | LOG_CONS, fpm_global_config.syslog_facility);
00269               fpm_globals.error_log_fd = ZLOG_SYSLOG;
00270               if (fpm_global_config.daemonize) {
00271                      zlog_set_fd(fpm_globals.error_log_fd);
00272               }
00273               return 0;
00274        }
00275 #endif
00276 
00277        fd = open(fpm_global_config.error_log, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
00278        if (0 > fd) {
00279               zlog(ZLOG_SYSERROR, "failed to open error_log (%s)", fpm_global_config.error_log);
00280               return -1;
00281        }
00282 
00283        if (reopen) {
00284               if (fpm_global_config.daemonize) {
00285                      dup2(fd, STDERR_FILENO);
00286               }
00287 
00288               dup2(fd, fpm_globals.error_log_fd);
00289               close(fd);
00290               fd = fpm_globals.error_log_fd; /* for FD_CLOSEXEC to work */
00291        } else {
00292               fpm_globals.error_log_fd = fd;
00293               if (fpm_global_config.daemonize) {
00294                      zlog_set_fd(fpm_globals.error_log_fd);
00295               }
00296        }
00297        fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
00298        return 0;
00299 }
00300 /* }}} */
00301