home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 April / PCO0499.ISO / filesbbs / os2 / apach134.arj / APACH134.ZIP / src / main / http_log.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-01  |  19.3 KB  |  742 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission. For written permission, please contact
  24.  *    apache@apache.org.
  25.  *
  26.  * 5. Products derived from this software may not be called "Apache"
  27.  *    nor may "Apache" appear in their names without prior written
  28.  *    permission of the Apache Group.
  29.  *
  30.  * 6. Redistributions of any form whatsoever must retain the following
  31.  *    acknowledgment:
  32.  *    "This product includes software developed by the Apache Group
  33.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  36.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Group and was originally based
  51.  * on public domain software written at the National Center for
  52.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  53.  * For more information on the Apache Group and the Apache HTTP server
  54.  * project, please see <http://www.apache.org/>.
  55.  *
  56.  */
  57.  
  58. /*
  59.  * http_log.c: Dealing with the logs and errors
  60.  * 
  61.  * Rob McCool
  62.  * 
  63.  */
  64.  
  65.  
  66. #define CORE_PRIVATE
  67. #include "httpd.h"
  68. #include "http_conf_globals.h"
  69. #include "http_config.h"
  70. #include "http_core.h"
  71. #include "http_log.h"
  72. #include "http_main.h"
  73.  
  74. #include <stdarg.h>
  75.  
  76. typedef struct {
  77.     char    *t_name;
  78.     int    t_val;
  79. } TRANS;
  80.  
  81. #ifdef HAVE_SYSLOG
  82.  
  83. static const TRANS facilities[] = {
  84.     {"auth",    LOG_AUTH},
  85. #ifdef LOG_AUTHPRIV
  86.     {"authpriv",LOG_AUTHPRIV},
  87. #endif
  88. #ifdef LOG_CRON
  89.     {"cron",     LOG_CRON},
  90. #endif
  91. #ifdef LOG_DAEMON
  92.     {"daemon",    LOG_DAEMON},
  93. #endif
  94. #ifdef LOG_FTP
  95.     {"ftp",    LOG_FTP},
  96. #endif
  97. #ifdef LOG_KERN
  98.     {"kern",    LOG_KERN},
  99. #endif
  100. #ifdef LOG_LPR
  101.     {"lpr",    LOG_LPR},
  102. #endif
  103. #ifdef LOG_MAIL
  104.     {"mail",    LOG_MAIL},
  105. #endif
  106. #ifdef LOG_NEWS
  107.     {"news",    LOG_NEWS},
  108. #endif
  109. #ifdef LOG_SYSLOG
  110.     {"syslog",    LOG_SYSLOG},
  111. #endif
  112. #ifdef LOG_USER
  113.     {"user",    LOG_USER},
  114. #endif
  115. #ifdef LOG_UUCP
  116.     {"uucp",    LOG_UUCP},
  117. #endif
  118. #ifdef LOG_LOCAL0
  119.     {"local0",    LOG_LOCAL0},
  120. #endif
  121. #ifdef LOG_LOCAL1
  122.     {"local1",    LOG_LOCAL1},
  123. #endif
  124. #ifdef LOG_LOCAL2
  125.     {"local2",    LOG_LOCAL2},
  126. #endif
  127. #ifdef LOG_LOCAL3
  128.     {"local3",    LOG_LOCAL3},
  129. #endif
  130. #ifdef LOG_LOCAL4
  131.     {"local4",    LOG_LOCAL4},
  132. #endif
  133. #ifdef LOG_LOCAL5
  134.     {"local5",    LOG_LOCAL5},
  135. #endif
  136. #ifdef LOG_LOCAL6
  137.     {"local6",    LOG_LOCAL6},
  138. #endif
  139. #ifdef LOG_LOCAL7
  140.     {"local7",    LOG_LOCAL7},
  141. #endif
  142.     {NULL,        -1},
  143. };
  144. #endif
  145.  
  146. static const TRANS priorities[] = {
  147.     {"emerg",    APLOG_EMERG},
  148.     {"alert",    APLOG_ALERT},
  149.     {"crit",    APLOG_CRIT},
  150.     {"error",    APLOG_ERR},
  151.     {"warn",    APLOG_WARNING},
  152.     {"notice",    APLOG_NOTICE},
  153.     {"info",    APLOG_INFO},
  154.     {"debug",    APLOG_DEBUG},
  155.     {NULL,    -1},
  156. };
  157.  
  158. static int error_log_child(void *cmd, child_info *pinfo)
  159. {
  160.     /* Child process code for 'ErrorLog "|..."';
  161.      * may want a common framework for this, since I expect it will
  162.      * be common for other foo-loggers to want this sort of thing...
  163.      */
  164.     int child_pid = 0;
  165.  
  166.     ap_cleanup_for_exec();
  167. #ifdef SIGHUP
  168.     /* No concept of a child process on Win32 */
  169.     signal(SIGHUP, SIG_IGN);
  170. #endif /* ndef SIGHUP */
  171. #if defined(WIN32)
  172.     child_pid = spawnl(_P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
  173.     return(child_pid);
  174. #elif defined(OS2)
  175.     /* For OS/2 we need to use a '/' */
  176.     execl(SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
  177. #else    
  178.     execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
  179. #endif    
  180.     exit(1);
  181.     /* NOT REACHED */
  182.     return(child_pid);
  183. }
  184.  
  185. static void open_error_log(server_rec *s, pool *p)
  186. {
  187.     char *fname;
  188.  
  189.     if (*s->error_fname == '|') {
  190.     FILE *dummy;
  191.  
  192.     if (!ap_spawn_child(p, error_log_child, (void *)(s->error_fname+1),
  193.                 kill_after_timeout, &dummy, NULL, NULL)) {
  194.         perror("ap_spawn_child");
  195.         fprintf(stderr, "Couldn't fork child for ErrorLog process\n");
  196.         exit(1);
  197.     }
  198.  
  199.     s->error_log = dummy;
  200.     }
  201.  
  202. #ifdef HAVE_SYSLOG
  203.     else if (!strncasecmp(s->error_fname, "syslog", 6)) {
  204.     if ((fname = strchr(s->error_fname, ':'))) {
  205.         const TRANS *fac;
  206.  
  207.         fname++;
  208.         for (fac = facilities; fac->t_name; fac++) {
  209.         if (!strcasecmp(fname, fac->t_name)) {
  210.             openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID,
  211.                 fac->t_val);
  212.             s->error_log = NULL;
  213.             return;
  214.         }
  215.         }
  216.     }
  217.     else
  218.         openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID, LOG_LOCAL7);
  219.  
  220.     s->error_log = NULL;
  221.     }
  222. #endif
  223.     else {
  224.     fname = ap_server_root_relative(p, s->error_fname);
  225.         if (!(s->error_log = ap_pfopen(p, fname, "a"))) {
  226.             perror("fopen");
  227.             fprintf(stderr, "%s: could not open error log file %s.\n",
  228.             ap_server_argv0, fname);
  229.             exit(1);
  230.     }
  231.     }
  232. }
  233.  
  234. void ap_open_logs(server_rec *s_main, pool *p)
  235. {
  236.     server_rec *virt, *q;
  237.     int replace_stderr;
  238.  
  239.     open_error_log(s_main, p);
  240.  
  241.     replace_stderr = 1;
  242.     if (s_main->error_log) {
  243.     /* replace stderr with this new log */
  244.     fflush(stderr);
  245.     if (dup2(fileno(s_main->error_log), STDERR_FILENO) == -1) {
  246.         ap_log_error(APLOG_MARK, APLOG_CRIT, s_main,
  247.         "unable to replace stderr with error_log");
  248.     } else {
  249.         replace_stderr = 0;
  250.     }
  251.     }
  252.     /* note that stderr may still need to be replaced with something
  253.      * because it points to the old error log, or back to the tty
  254.      * of the submitter.
  255.      */
  256.     if (replace_stderr && freopen("/dev/null", "w", stderr) == NULL) {
  257.     ap_log_error(APLOG_MARK, APLOG_CRIT, s_main,
  258.         "unable to replace stderr with /dev/null");
  259.     }
  260.  
  261.     for (virt = s_main->next; virt; virt = virt->next) {
  262.     if (virt->error_fname)
  263.     {
  264.         for (q=s_main; q != virt; q = q->next)
  265.         if (q->error_fname != NULL &&
  266.             strcmp(q->error_fname, virt->error_fname) == 0)
  267.             break;
  268.         if (q == virt)
  269.         open_error_log(virt, p);
  270.         else 
  271.         virt->error_log = q->error_log;
  272.     }
  273.     else
  274.         virt->error_log = s_main->error_log;
  275.     }
  276. }
  277.  
  278. API_EXPORT(void) ap_error_log2stderr(server_rec *s) {
  279.     if (   s->error_log != NULL
  280.         && fileno(s->error_log) != STDERR_FILENO)
  281.         dup2(fileno(s->error_log), STDERR_FILENO);
  282. }
  283.  
  284. static void log_error_core(const char *file, int line, int level,
  285.                const server_rec *s, const request_rec *r,
  286.                const char *fmt, va_list args)
  287. {
  288.     char errstr[MAX_STRING_LEN];
  289.     size_t len;
  290.     int save_errno = errno;
  291.     FILE *logf;
  292.  
  293.     if (s == NULL) {
  294.     /*
  295.      * If we are doing stderr logging (startup), don't log messages that are
  296.      * above the default server log level unless it is a startup/shutdown
  297.      * notice
  298.      */
  299.     if (((level & APLOG_LEVELMASK) != APLOG_NOTICE) &&
  300.         ((level & APLOG_LEVELMASK) > DEFAULT_LOGLEVEL))
  301.         return;
  302.     logf = stderr;
  303.     }
  304.     else if (s->error_log) {
  305.     /*
  306.      * If we are doing normal logging, don't log messages that are
  307.      * above the server log level unless it is a startup/shutdown notice
  308.      */
  309.     if (((level & APLOG_LEVELMASK) != APLOG_NOTICE) &&
  310.         ((level & APLOG_LEVELMASK) > s->loglevel))
  311.         return;
  312.     logf = s->error_log;
  313.     }
  314.     else {
  315.     /*
  316.      * If we are doing syslog logging, don't log messages that are
  317.      * above the server log level (including a startup/shutdown notice)
  318.      */
  319.     if ((level & APLOG_LEVELMASK) > s->loglevel)
  320.         return;
  321.     logf = NULL;
  322.     }
  323.  
  324.     if (logf) {
  325.     len = ap_snprintf(errstr, sizeof(errstr), "%s: [%s] ",
  326.               ap_server_argv0, ap_get_time());
  327.     } else {
  328.     len = 0;
  329.     }
  330.  
  331.     len += ap_snprintf(errstr + len, sizeof(errstr) - len,
  332.         "[%s] ", priorities[level & APLOG_LEVELMASK].t_name);
  333.  
  334.     if (file && (level & APLOG_LEVELMASK) == APLOG_DEBUG) {
  335. #ifdef _OSD_POSIX
  336.     char tmp[256];
  337.     char *e = strrchr(file, '/');
  338.  
  339.     /* In OSD/POSIX, the compiler returns for __FILE__
  340.      * a string like: __FILE__="*POSIX(/usr/include/stdio.h)"
  341.      * (it even returns an absolute path for sources in
  342.      * the current directory). Here we try to strip this
  343.      * down to the basename.
  344.      */
  345.     if (e != NULL && e[1] != '\0') {
  346.         ap_snprintf(tmp, sizeof(tmp), "%s", &e[1]);
  347.         e = &tmp[strlen(tmp)-1];
  348.         if (*e == ')')
  349.         *e = '\0';
  350.         file = tmp;
  351.     }
  352. #endif /*_OSD_POSIX*/
  353.     len += ap_snprintf(errstr + len, sizeof(errstr) - len,
  354.         "%s(%d): ", file, line);
  355.     }
  356.     if (r) {
  357.     /* XXX: TODO: add a method of selecting whether logged client
  358.      * addresses are in dotted quad or resolved form... dotted
  359.      * quad is the most secure, which is why I'm implementing it
  360.      * first. -djg
  361.      */
  362.     len += ap_snprintf(errstr + len, sizeof(errstr) - len,
  363.         "[client %s] ", r->connection->remote_ip);
  364.     }
  365.     if (!(level & APLOG_NOERRNO)
  366.     && (save_errno != 0)
  367. #ifdef WIN32
  368.     && !(level & APLOG_WIN32ERROR)
  369. #endif
  370.     ) {
  371.     len += ap_snprintf(errstr + len, sizeof(errstr) - len,
  372.         "(%d)%s: ", save_errno, strerror(save_errno));
  373.     }
  374. #ifdef WIN32
  375.     if (level & APLOG_WIN32ERROR) {
  376.     int nChars;
  377.     int nErrorCode;
  378.  
  379.     nErrorCode = GetLastError();
  380.     len += ap_snprintf(errstr + len, sizeof(errstr) - len,
  381.         "(%d)", nErrorCode);
  382.  
  383.     nChars = FormatMessage( 
  384.         FORMAT_MESSAGE_FROM_SYSTEM,
  385.         NULL,
  386.         nErrorCode,
  387.         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  388.         (LPTSTR) errstr + len,
  389.         sizeof(errstr) - len,
  390.         NULL 
  391.     );
  392.     len += nChars;
  393.     if (nChars == 0) {
  394.         /* Um, error occurred, but we can't recurse to log it again
  395.          * (and it would probably only fail anyway), so lets just
  396.          * log the numeric value.
  397.          */
  398.         nErrorCode = GetLastError();
  399.         len += ap_snprintf(errstr + len, sizeof(errstr) - len,
  400.                    "(FormatMessage failed with code %d): ",
  401.                    nErrorCode);
  402.     }
  403.     else {
  404.         /* FormatMessage put the message in the buffer, but it may
  405.          * have appended a newline (\r\n). So remove it and use
  406.          * ": " instead like the Unix errors. The error may also
  407.          * end with a . before the return - if so, trash it.
  408.          */
  409.         if (len > 1 && errstr[len-2] == '\r' && errstr[len-1] == '\n') {
  410.         if (len > 2 && errstr[len-3] == '.')
  411.             len--;
  412.         errstr[len-2] = ':';
  413.         errstr[len-1] = ' ';
  414.         }
  415.     }
  416.     }
  417. #endif
  418.  
  419.     len += ap_vsnprintf(errstr + len, sizeof(errstr) - len, fmt, args);
  420.  
  421.     /* NULL if we are logging to syslog */
  422.     if (logf) {
  423.     fputs(errstr, logf);
  424.     fputc('\n', logf);
  425.     fflush(logf);
  426.     }
  427. #ifdef HAVE_SYSLOG
  428.     else {
  429.     syslog(level & APLOG_LEVELMASK, "%s", errstr);
  430.     }
  431. #endif
  432. }
  433.     
  434. API_EXPORT(void) ap_log_error(const char *file, int line, int level,
  435.                   const server_rec *s, const char *fmt, ...)
  436. {
  437.     va_list args;
  438.  
  439.     va_start(args, fmt);
  440.     log_error_core(file, line, level, s, NULL, fmt, args);
  441.     va_end(args);
  442. }
  443.  
  444. API_EXPORT(void) ap_log_rerror(const char *file, int line, int level,
  445.                    const request_rec *r, const char *fmt, ...)
  446. {
  447.     va_list args;
  448.  
  449.     va_start(args, fmt);
  450.     log_error_core(file, line, level, r->server, r, fmt, args);
  451.     /*
  452.      * IF the error level is 'warning' or more severe,
  453.      * AND there isn't already error text associated with this request,
  454.      * THEN make the message text available to ErrorDocument and
  455.      * other error processors.  This can be disabled by stuffing
  456.      * something, even an empty string, into the "error-notes" cell
  457.      * before calling this routine.
  458.      */
  459.     if (((level & APLOG_LEVELMASK) <= APLOG_WARNING)
  460.     && (ap_table_get(r->notes, "error-notes") == NULL)) {
  461.     ap_table_setn(r->notes, "error-notes",
  462.               ap_pvsprintf(r->pool, fmt, args));
  463.     }
  464.     va_end(args);
  465. }
  466.  
  467. void ap_log_pid(pool *p, char *fname)
  468. {
  469.     FILE *pid_file;
  470.     struct stat finfo;
  471.     static pid_t saved_pid = -1;
  472.     pid_t mypid;
  473.  
  474.     if (!fname) 
  475.     return;
  476.  
  477.     fname = ap_server_root_relative(p, fname);
  478.     mypid = getpid();
  479.     if (mypid != saved_pid && stat(fname, &finfo) == 0) {
  480.       /* USR1 and HUP call this on each restart.
  481.        * Only warn on first time through for this pid.
  482.        *
  483.        * XXX: Could just write first time through too, although
  484.        *      that may screw up scripts written to do something
  485.        *      based on the last modification time of the pid file.
  486.        */
  487.       ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
  488.            ap_psprintf(p,
  489.                    "pid file %s overwritten -- Unclean shutdown of previous Apache run?",
  490.                    fname)
  491.            );
  492.     }
  493.  
  494.     if(!(pid_file = fopen(fname, "w"))) {
  495.     perror("fopen");
  496.         fprintf(stderr, "%s: could not log pid to file %s\n",
  497.         ap_server_argv0, fname);
  498.         exit(1);
  499.     }
  500.     fprintf(pid_file, "%ld\n", (long)mypid);
  501.     fclose(pid_file);
  502.     saved_pid = mypid;
  503. }
  504.  
  505. API_EXPORT(void) ap_log_error_old(const char *err, server_rec *s)
  506. {
  507.     ap_log_error(APLOG_MARK, APLOG_ERR, s, "%s", err);
  508. }
  509.  
  510. API_EXPORT(void) ap_log_unixerr(const char *routine, const char *file,
  511.                   const char *msg, server_rec *s)
  512. {
  513.     ap_log_error(file, 0, APLOG_ERR, s, "%s", msg);
  514. }
  515.  
  516. API_EXPORT(void) ap_log_printf(const server_rec *s, const char *fmt, ...)
  517. {
  518.     va_list args;
  519.     
  520.     va_start(args, fmt);
  521.     log_error_core(APLOG_MARK, APLOG_ERR, s, NULL, fmt, args);
  522.     va_end(args);
  523. }
  524.  
  525. API_EXPORT(void) ap_log_reason(const char *reason, const char *file, request_rec *r) 
  526. {
  527.     ap_log_error(APLOG_MARK, APLOG_ERR, r->server,
  528.         "access to %s failed for %s, reason: %s",
  529.         file,
  530.         ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME),
  531.         reason);
  532. }
  533.  
  534. API_EXPORT(void) ap_log_assert(const char *szExp, const char *szFile, int nLine)
  535. {
  536.     fprintf(stderr, "[%s] file %s, line %d, assertion \"%s\" failed\n",
  537.         ap_get_time(), szFile, nLine, szExp);
  538. #ifndef WIN32
  539.     /* unix assert does an abort leading to a core dump */
  540.     abort();
  541. #else
  542.     exit(1);
  543. #endif
  544. }
  545.  
  546. /* piped log support */
  547.  
  548. #ifndef NO_RELIABLE_PIPED_LOGS
  549. /* forward declaration */
  550. static void piped_log_maintenance(int reason, void *data, ap_wait_t status);
  551.  
  552. static int piped_log_spawn(piped_log *pl)
  553. {
  554.     int pid;
  555.  
  556.     ap_block_alarms();
  557.     pid = fork();
  558.     if (pid == 0) {
  559.     /* XXX: this needs porting to OS2 and WIN32 */
  560.     /* XXX: need to check what open fds the logger is actually passed,
  561.      * XXX: and CGIs for that matter ... cleanup_for_exec *should*
  562.      * XXX: close all the relevant stuff, but hey, it could be broken. */
  563.     RAISE_SIGSTOP(PIPED_LOG_SPAWN);
  564.     /* we're now in the child */
  565.     close(STDIN_FILENO);
  566.     dup2(pl->fds[0], STDIN_FILENO);
  567.  
  568.     ap_cleanup_for_exec();
  569.     signal(SIGCHLD, SIG_DFL);    /* for HPUX */
  570.     signal(SIGHUP, SIG_IGN);
  571.     execl(SHELL_PATH, SHELL_PATH, "-c", pl->program, NULL);
  572.     fprintf(stderr,
  573.         "piped_log_spawn: unable to exec %s -c '%s': %s\n",
  574.         SHELL_PATH, pl->program, strerror (errno));
  575.     exit(1);
  576.     }
  577.     if (pid == -1) {
  578.     fprintf(stderr,
  579.         "piped_log_spawn: unable to fork(): %s\n", strerror (errno));
  580.     ap_unblock_alarms();
  581.     return -1;
  582.     }
  583.     ap_unblock_alarms();
  584.     pl->pid = pid;
  585.     ap_register_other_child(pid, piped_log_maintenance, pl, pl->fds[1]);
  586.     return 0;
  587. }
  588.  
  589.  
  590. static void piped_log_maintenance(int reason, void *data, ap_wait_t status)
  591. {
  592.     piped_log *pl = data;
  593.  
  594.     switch (reason) {
  595.     case OC_REASON_DEATH:
  596.     case OC_REASON_LOST:
  597.     pl->pid = -1;
  598.     ap_unregister_other_child(pl);
  599.     if (pl->program == NULL) {
  600.         /* during a restart */
  601.         break;
  602.     }
  603.     if (piped_log_spawn(pl) == -1) {
  604.         /* what can we do?  This could be the error log we're having
  605.          * problems opening up... */
  606.         fprintf(stderr,
  607.         "piped_log_maintenance: unable to respawn '%s': %s\n",
  608.         pl->program, strerror(errno));
  609.     }
  610.     break;
  611.     
  612.     case OC_REASON_UNWRITABLE:
  613.     if (pl->pid != -1) {
  614.         kill(pl->pid, SIGTERM);
  615.     }
  616.     break;
  617.     
  618.     case OC_REASON_RESTART:
  619.     pl->program = NULL;
  620.     if (pl->pid != -1) {
  621.         kill(pl->pid, SIGTERM);
  622.     }
  623.     break;
  624.  
  625.     case OC_REASON_UNREGISTER:
  626.     break;
  627.     }
  628. }
  629.  
  630.  
  631. static void piped_log_cleanup(void *data)
  632. {
  633.     piped_log *pl = data;
  634.  
  635.     if (pl->pid != -1) {
  636.     kill(pl->pid, SIGTERM);
  637.     }
  638.     ap_unregister_other_child(pl);
  639.     close(pl->fds[0]);
  640.     close(pl->fds[1]);
  641. }
  642.  
  643.  
  644. static void piped_log_cleanup_for_exec(void *data)
  645. {
  646.     piped_log *pl = data;
  647.  
  648.     close(pl->fds[0]);
  649.     close(pl->fds[1]);
  650. }
  651.  
  652.  
  653. API_EXPORT(piped_log *) ap_open_piped_log(pool *p, const char *program)
  654. {
  655.     piped_log *pl;
  656.  
  657.     pl = ap_palloc(p, sizeof (*pl));
  658.     pl->p = p;
  659.     pl->program = ap_pstrdup(p, program);
  660.     pl->pid = -1;
  661.     ap_block_alarms ();
  662.     if (pipe(pl->fds) == -1) {
  663.     int save_errno = errno;
  664.     ap_unblock_alarms();
  665.     errno = save_errno;
  666.     return NULL;
  667.     }
  668.     ap_register_cleanup(p, pl, piped_log_cleanup, piped_log_cleanup_for_exec);
  669.     if (piped_log_spawn(pl) == -1) {
  670.     int save_errno = errno;
  671.     ap_kill_cleanup(p, pl, piped_log_cleanup);
  672.     close(pl->fds[0]);
  673.     close(pl->fds[1]);
  674.     ap_unblock_alarms();
  675.     errno = save_errno;
  676.     return NULL;
  677.     }
  678.     ap_unblock_alarms();
  679.     return pl;
  680. }
  681.  
  682. API_EXPORT(void) ap_close_piped_log(piped_log *pl)
  683. {
  684.     ap_block_alarms();
  685.     piped_log_cleanup(pl);
  686.     ap_kill_cleanup(pl->p, pl, piped_log_cleanup);
  687.     ap_unblock_alarms();
  688. }
  689.  
  690. #else
  691. static int piped_log_child(void *cmd, child_info *pinfo)
  692. {
  693.     /* Child process code for 'TransferLog "|..."';
  694.      * may want a common framework for this, since I expect it will
  695.      * be common for other foo-loggers to want this sort of thing...
  696.      */
  697.     int child_pid = 1;
  698.  
  699.     ap_cleanup_for_exec();
  700. #ifdef SIGHUP
  701.     signal(SIGHUP, SIG_IGN);
  702. #endif
  703. #if defined(WIN32)
  704.     child_pid = spawnl(_P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
  705.     return(child_pid);
  706. #elif defined(OS2)
  707.     /* For OS/2 we need to use a '/' */
  708.     execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
  709. #else
  710.     execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
  711. #endif
  712.     perror("exec");
  713.     fprintf(stderr, "Exec of shell for logging failed!!!\n");
  714.     return(child_pid);
  715. }
  716.  
  717.  
  718. API_EXPORT(piped_log *) ap_open_piped_log(pool *p, const char *program)
  719. {
  720.     piped_log *pl;
  721.     FILE *dummy;
  722.  
  723.     if (!ap_spawn_child(p, piped_log_child, (void *)program,
  724.             kill_after_timeout, &dummy, NULL, NULL)) {
  725.     perror("ap_spawn_child");
  726.     fprintf(stderr, "Couldn't fork child for piped log process\n");
  727.     exit (1);
  728.     }
  729.     pl = ap_palloc(p, sizeof (*pl));
  730.     pl->p = p;
  731.     pl->write_f = dummy;
  732.  
  733.     return pl;
  734. }
  735.  
  736.  
  737. API_EXPORT(void) ap_close_piped_log(piped_log *pl)
  738. {
  739.     ap_pfclose(pl->p, pl->write_f);
  740. }
  741. #endif
  742.