Index: trunk/src/log.c =================================================================== --- trunk/src/log.c (revision 1473) +++ trunk/src/log.c (working copy) @@ -39,10 +39,11 @@ /** * open the errorlog * - * we have 3 possibilities: + * we have 4 possibilities: * - stderr (default) * - syslog * - logfile + * - pipe * * if the open failed, report to the user and die * @@ -55,7 +56,7 @@ /* the errorlog */ int fd; - enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode; + enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG, ERRORLOG_PIPE } mode; buffer *buf; time_t cached_ts; @@ -86,6 +87,7 @@ TRACE("%s", "server stopped"); switch(err->mode) { + case ERRORLOG_PIPE: /* fall through */ case ERRORLOG_FILE: close(err->fd); break; @@ -122,18 +124,78 @@ if (use_syslog) { err->mode = ERRORLOG_SYSLOG; } else if (!buffer_is_empty(file)) { - if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) { - log_error_write(NULL, __FILE__, __LINE__, "SBSS", - "opening errorlog '", file, - "' failed: ", strerror(errno)); + if (*(char *)file->ptr == '|') { +#ifdef HAVE_FORK + /* create write pipe and spawn process */ + int to_log_fds[2]; + pid_t pid; + + if (pipe(to_log_fds)) { + log_error_write(NULL, __FILE__, __LINE__, "ss", + "pipe failed: ", strerror(errno)); + return -1; + } + + /* fork, execve */ + switch (pid = fork()) { + case 0: + /* child */ + + close(STDIN_FILENO); + dup2(to_log_fds[0], STDIN_FILENO); + close(to_log_fds[0]); + /* not needed */ + close(to_log_fds[1]); + + /* we don't need the client socket */ + for (fd = 3; fd < 256; fd++) { + close(fd); + } + + /* exec the log-process (skip the | ) + * + */ + + execl("/bin/sh", "sh", "-c", file->ptr + 1, NULL); + + log_error_write(NULL, __FILE__, __LINE__, "ssb", + "spawning log-process failed: ", + strerror(errno), file->ptr + 1); + + exit(-1); + break; + case -1: + /* error */ + log_error_write(NULL, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno)); + break; + default: + close(to_log_fds[0]); + + err->fd = to_log_fds[1]; + + break; + } + err->mode = ERRORLOG_PIPE; +#else + log_error_write(NULL, __FILE__, __LINE__, "SBS", + "opening errorlog '", file,"' impossible"); return -1; +#endif + } else { + if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) { + log_error_write(NULL, __FILE__, __LINE__, "SBSS", + "opening errorlog '", file, + "' failed: ", strerror(errno)); + + return -1; + } + err->mode = ERRORLOG_FILE; } #ifdef FD_CLOEXEC /* close fd on exec (cgi) */ fcntl(err->fd, F_SETFD, FD_CLOEXEC); #endif - err->mode = ERRORLOG_FILE; } TRACE("%s", "server started"); @@ -163,7 +225,7 @@ */ int log_error_cycle(void) { - /* only cycle if we are not in syslog-mode */ + /* only cycle if the error log is a file */ errorlog *err = myconfig; @@ -206,6 +268,7 @@ UNUSED(srv); switch(err->mode) { + case ERRORLOG_PIPE: /* fall through */ case ERRORLOG_FILE: case ERRORLOG_STDERR: /* cache the generated timestamp */ @@ -290,6 +353,7 @@ va_end(ap); switch(err->mode) { + case ERRORLOG_PIPE: /* fall through */ case ERRORLOG_FILE: BUFFER_APPEND_STRING_CONST(err->buf, "\n"); write(err->fd, err->buf->ptr, err->buf->used - 1); @@ -322,6 +386,7 @@ /* write b */ switch(err->mode) { + case ERRORLOG_PIPE: /* fall through */ case ERRORLOG_FILE: buffer_append_string(b, "\r\n"); write(err->fd, b->ptr, b->used - 1);