Annotation of embedaddon/lighttpd/src/log.c, revision 1.1.1.2

1.1       misho       1: #include "base.h"
                      2: #include "log.h"
                      3: #include "array.h"
                      4: 
                      5: #include <sys/types.h>
                      6: 
                      7: #include <errno.h>
                      8: #include <fcntl.h>
                      9: #include <time.h>
                     10: #include <unistd.h>
                     11: #include <string.h>
                     12: #include <stdlib.h>
                     13: 
                     14: #include <stdarg.h>
                     15: #include <stdio.h>
                     16: 
                     17: #ifdef HAVE_SYSLOG_H
                     18: # include <syslog.h>
                     19: #endif
                     20: 
                     21: #ifdef HAVE_VALGRIND_VALGRIND_H
                     22: # include <valgrind/valgrind.h>
                     23: #endif
                     24: 
                     25: #ifndef O_LARGEFILE
                     26: # define O_LARGEFILE 0
                     27: #endif
                     28: 
                     29: /* Close fd and _try_ to get a /dev/null for it instead.
                     30:  * close() alone may trigger some bugs when a
                     31:  * process opens another file and gets fd = STDOUT_FILENO or STDERR_FILENO
                     32:  * and later tries to just print on stdout/stderr
                     33:  *
                     34:  * Returns 0 on success and -1 on failure (fd gets closed in all cases)
                     35:  */
                     36: int openDevNull(int fd) {
                     37:        int tmpfd;
                     38:        close(fd);
                     39: #if defined(__WIN32)
                     40:        /* Cygwin should work with /dev/null */
                     41:        tmpfd = open("nul", O_RDWR);
                     42: #else
                     43:        tmpfd = open("/dev/null", O_RDWR);
                     44: #endif
                     45:        if (tmpfd != -1 && tmpfd != fd) {
                     46:                dup2(tmpfd, fd);
                     47:                close(tmpfd);
                     48:        }
                     49:        return (tmpfd != -1) ? 0 : -1;
                     50: }
                     51: 
                     52: int open_logfile_or_pipe(server *srv, const char* logfile) {
                     53:        int fd;
                     54: 
                     55:        if (logfile[0] == '|') {
                     56: #ifdef HAVE_FORK
                     57:                /* create write pipe and spawn process */
                     58: 
                     59:                int to_log_fds[2];
                     60: 
                     61:                if (pipe(to_log_fds)) {
                     62:                        log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
                     63:                        return -1;
                     64:                }
                     65: 
                     66:                /* fork, execve */
                     67:                switch (fork()) {
                     68:                case 0:
                     69:                        /* child */
                     70:                        close(STDIN_FILENO);
                     71: 
                     72:                        /* dup the filehandle to STDIN */
                     73:                        if (to_log_fds[0] != STDIN_FILENO) {
                     74:                                if (STDIN_FILENO != dup2(to_log_fds[0], STDIN_FILENO)) {
                     75:                                        log_error_write(srv, __FILE__, __LINE__, "ss",
                     76:                                                "dup2 failed: ", strerror(errno));
                     77:                                        exit(-1);
                     78:                                }
                     79:                                close(to_log_fds[0]);
                     80:                        }
                     81:                        close(to_log_fds[1]);
                     82: 
                     83: #ifndef FD_CLOEXEC
                     84:                        {
                     85:                                int i;
                     86:                                /* we don't need the client socket */
                     87:                                for (i = 3; i < 256; i++) {
                     88:                                        close(i);
                     89:                                }
                     90:                        }
                     91: #endif
                     92: 
                     93:                        /* close old stderr */
                     94:                        openDevNull(STDERR_FILENO);
                     95: 
                     96:                        /* exec the log-process (skip the | ) */
                     97:                        execl("/bin/sh", "sh", "-c", logfile + 1, NULL);
                     98:                        log_error_write(srv, __FILE__, __LINE__, "sss",
                     99:                                        "spawning log process failed: ", strerror(errno),
                    100:                                        logfile + 1);
                    101: 
                    102:                        exit(-1);
                    103:                        break;
                    104:                case -1:
                    105:                        /* error */
                    106:                        log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed: ", strerror(errno));
                    107:                        return -1;
                    108:                default:
                    109:                        close(to_log_fds[0]);
                    110:                        fd = to_log_fds[1];
                    111:                        break;
                    112:                }
                    113: 
                    114: #else
                    115:                return -1;
                    116: #endif
                    117:        } else if (-1 == (fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
                    118:                log_error_write(srv, __FILE__, __LINE__, "SSSS",
                    119:                                "opening errorlog '", logfile,
                    120:                                "' failed: ", strerror(errno));
                    121: 
                    122:                return -1;
                    123:        }
                    124: 
1.1.1.2 ! misho     125:        fd_close_on_exec(fd);
1.1       misho     126: 
                    127:        return fd;
                    128: }
                    129: 
                    130: 
                    131: /**
                    132:  * open the errorlog
                    133:  *
                    134:  * we have 4 possibilities:
                    135:  * - stderr (default)
                    136:  * - syslog
                    137:  * - logfile
                    138:  * - pipe
                    139:  *
                    140:  * if the open failed, report to the user and die
                    141:  *
                    142:  */
                    143: 
                    144: int log_error_open(server *srv) {
                    145: #ifdef HAVE_SYSLOG_H
                    146:        /* perhaps someone wants to use syslog() */
                    147:        openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
                    148: #endif
                    149: 
                    150:        srv->errorlog_mode = ERRORLOG_FD;
                    151:        srv->errorlog_fd = STDERR_FILENO;
                    152: 
                    153:        if (srv->srvconf.errorlog_use_syslog) {
                    154:                srv->errorlog_mode = ERRORLOG_SYSLOG;
                    155:        } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
                    156:                const char *logfile = srv->srvconf.errorlog_file->ptr;
                    157: 
                    158:                if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) {
                    159:                        return -1;
                    160:                }
                    161:                srv->errorlog_mode = (logfile[0] == '|') ? ERRORLOG_PIPE : ERRORLOG_FILE;
                    162:        }
                    163: 
                    164:        log_error_write(srv, __FILE__, __LINE__, "s", "server started");
                    165: 
                    166:        if (srv->errorlog_mode == ERRORLOG_FD && !srv->srvconf.dont_daemonize) {
                    167:                /* We can only log to stderr in dont-daemonize mode;
                    168:                 * if we do daemonize and no errorlog file is specified, we log into /dev/null
                    169:                 */
                    170:                srv->errorlog_fd = -1;
                    171:        }
                    172: 
                    173:        if (!buffer_is_empty(srv->srvconf.breakagelog_file)) {
                    174:                int breakage_fd;
                    175:                const char *logfile = srv->srvconf.breakagelog_file->ptr;
                    176: 
                    177:                if (srv->errorlog_mode == ERRORLOG_FD) {
                    178:                        srv->errorlog_fd = dup(STDERR_FILENO);
1.1.1.2 ! misho     179:                        fd_close_on_exec(srv->errorlog_fd);
1.1       misho     180:                }
                    181: 
                    182:                if (-1 == (breakage_fd = open_logfile_or_pipe(srv, logfile))) {
                    183:                        return -1;
                    184:                }
                    185: 
                    186:                if (STDERR_FILENO != breakage_fd) {
                    187:                        dup2(breakage_fd, STDERR_FILENO);
                    188:                        close(breakage_fd);
                    189:                }
                    190:        } else if (!srv->srvconf.dont_daemonize) {
                    191:                /* move stderr to /dev/null */
                    192:                openDevNull(STDERR_FILENO);
                    193:        }
                    194:        return 0;
                    195: }
                    196: 
                    197: /**
                    198:  * open the errorlog
                    199:  *
                    200:  * if the open failed, report to the user and die
                    201:  * if no filename is given, use syslog instead
                    202:  *
                    203:  */
                    204: 
                    205: int log_error_cycle(server *srv) {
                    206:        /* only cycle if the error log is a file */
                    207: 
                    208:        if (srv->errorlog_mode == ERRORLOG_FILE) {
                    209:                const char *logfile = srv->srvconf.errorlog_file->ptr;
                    210:                /* already check of opening time */
                    211: 
                    212:                int new_fd;
                    213: 
                    214:                if (-1 == (new_fd = open_logfile_or_pipe(srv, logfile))) {
                    215:                        /* write to old log */
                    216:                        log_error_write(srv, __FILE__, __LINE__, "SSSSS",
                    217:                                        "cycling errorlog '", logfile,
                    218:                                        "' failed: ", strerror(errno),
                    219:                                        ", falling back to syslog()");
                    220: 
                    221:                        close(srv->errorlog_fd);
                    222:                        srv->errorlog_fd = -1;
                    223: #ifdef HAVE_SYSLOG_H
                    224:                        srv->errorlog_mode = ERRORLOG_SYSLOG;
                    225: #endif
                    226:                } else {
                    227:                        /* ok, new log is open, close the old one */
                    228:                        close(srv->errorlog_fd);
                    229:                        srv->errorlog_fd = new_fd;
1.1.1.2 ! misho     230:                        fd_close_on_exec(srv->errorlog_fd);
1.1       misho     231:                }
                    232:        }
                    233: 
                    234:        return 0;
                    235: }
                    236: 
                    237: int log_error_close(server *srv) {
                    238:        switch(srv->errorlog_mode) {
                    239:        case ERRORLOG_PIPE:
                    240:        case ERRORLOG_FILE:
                    241:        case ERRORLOG_FD:
                    242:                if (-1 != srv->errorlog_fd) {
                    243:                        /* don't close STDERR */
                    244:                        if (STDERR_FILENO != srv->errorlog_fd)
                    245:                                close(srv->errorlog_fd);
                    246:                        srv->errorlog_fd = -1;
                    247:                }
                    248:                break;
                    249:        case ERRORLOG_SYSLOG:
                    250: #ifdef HAVE_SYSLOG_H
                    251:                closelog();
                    252: #endif
                    253:                break;
                    254:        }
                    255: 
                    256:        return 0;
                    257: }
                    258: 
                    259: /* lowercase: append space, uppercase: don't */
                    260: static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
                    261:        for(; *fmt; fmt++) {
                    262:                int d;
                    263:                char *s;
                    264:                buffer *b;
                    265:                off_t o;
                    266: 
                    267:                switch(*fmt) {
                    268:                case 's':           /* string */
                    269:                        s = va_arg(ap, char *);
                    270:                        buffer_append_string(out, s);
                    271:                        buffer_append_string_len(out, CONST_STR_LEN(" "));
                    272:                        break;
                    273:                case 'b':           /* buffer */
                    274:                        b = va_arg(ap, buffer *);
                    275:                        buffer_append_string_buffer(out, b);
                    276:                        buffer_append_string_len(out, CONST_STR_LEN(" "));
                    277:                        break;
                    278:                case 'd':           /* int */
                    279:                        d = va_arg(ap, int);
                    280:                        buffer_append_long(out, d);
                    281:                        buffer_append_string_len(out, CONST_STR_LEN(" "));
                    282:                        break;
                    283:                case 'o':           /* off_t */
                    284:                        o = va_arg(ap, off_t);
                    285:                        buffer_append_off_t(out, o);
                    286:                        buffer_append_string_len(out, CONST_STR_LEN(" "));
                    287:                        break;
                    288:                case 'x':           /* int (hex) */
                    289:                        d = va_arg(ap, int);
                    290:                        buffer_append_string_len(out, CONST_STR_LEN("0x"));
                    291:                        buffer_append_long_hex(out, d);
                    292:                        buffer_append_string_len(out, CONST_STR_LEN(" "));
                    293:                        break;
                    294:                case 'S':           /* string */
                    295:                        s = va_arg(ap, char *);
                    296:                        buffer_append_string(out, s);
                    297:                        break;
                    298:                case 'B':           /* buffer */
                    299:                        b = va_arg(ap, buffer *);
                    300:                        buffer_append_string_buffer(out, b);
                    301:                        break;
                    302:                case 'D':           /* int */
                    303:                        d = va_arg(ap, int);
                    304:                        buffer_append_long(out, d);
                    305:                        break;
                    306:                case 'O':           /* off_t */
                    307:                        o = va_arg(ap, off_t);
                    308:                        buffer_append_off_t(out, o);
                    309:                        break;
                    310:                case 'X':           /* int (hex) */
                    311:                        d = va_arg(ap, int);
                    312:                        buffer_append_string_len(out, CONST_STR_LEN("0x"));
                    313:                        buffer_append_long_hex(out, d);
                    314:                        break;
                    315:                case '(':
                    316:                case ')':
                    317:                case '<':
                    318:                case '>':
                    319:                case ',':
                    320:                case ' ':
                    321:                        buffer_append_string_len(out, fmt, 1);
                    322:                        break;
                    323:                }
                    324:        }
                    325: }
                    326: 
                    327: static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) {
                    328:        switch(srv->errorlog_mode) {
                    329:        case ERRORLOG_PIPE:
                    330:        case ERRORLOG_FILE:
                    331:        case ERRORLOG_FD:
                    332:                if (-1 == srv->errorlog_fd) return -1;
                    333:                /* cache the generated timestamp */
                    334:                if (srv->cur_ts != srv->last_generated_debug_ts) {
                    335:                        buffer_prepare_copy(srv->ts_debug_str, 255);
                    336:                        strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
                    337:                        srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
                    338: 
                    339:                        srv->last_generated_debug_ts = srv->cur_ts;
                    340:                }
                    341: 
                    342:                buffer_copy_string_buffer(b, srv->ts_debug_str);
                    343:                buffer_append_string_len(b, CONST_STR_LEN(": ("));
                    344:                break;
                    345:        case ERRORLOG_SYSLOG:
                    346:                /* syslog is generating its own timestamps */
                    347:                buffer_copy_string_len(b, CONST_STR_LEN("("));
                    348:                break;
                    349:        }
                    350: 
                    351:        buffer_append_string(b, filename);
                    352:        buffer_append_string_len(b, CONST_STR_LEN("."));
                    353:        buffer_append_long(b, line);
                    354:        buffer_append_string_len(b, CONST_STR_LEN(") "));
                    355: 
                    356:        return 0;
                    357: }
                    358: 
                    359: static void log_write(server *srv, buffer *b) {
                    360:        switch(srv->errorlog_mode) {
                    361:        case ERRORLOG_PIPE:
                    362:        case ERRORLOG_FILE:
                    363:        case ERRORLOG_FD:
                    364:                buffer_append_string_len(b, CONST_STR_LEN("\n"));
1.1.1.2 ! misho     365:                force_assert(b->used > 0);
1.1       misho     366:                write(srv->errorlog_fd, b->ptr, b->used - 1);
                    367:                break;
                    368:        case ERRORLOG_SYSLOG:
                    369:                syslog(LOG_ERR, "%s", b->ptr);
                    370:                break;
                    371:        }
                    372: }
                    373: 
                    374: int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
                    375:        va_list ap;
                    376: 
                    377:        if (-1 == log_buffer_prepare(srv->errorlog_buf, srv, filename, line)) return 0;
                    378: 
                    379:        va_start(ap, fmt);
                    380:        log_buffer_append_printf(srv->errorlog_buf, fmt, ap);
                    381:        va_end(ap);
                    382: 
                    383:        log_write(srv, srv->errorlog_buf);
                    384: 
                    385:        return 0;
                    386: }
                    387: 
                    388: int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
                    389:        va_list ap;
                    390:        size_t prefix_used;
                    391:        buffer *b = srv->errorlog_buf;
                    392:        char *pos, *end, *current_line;
                    393: 
                    394:        if (multiline->used < 2) return 0;
                    395: 
                    396:        if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0;
                    397: 
                    398:        va_start(ap, fmt);
                    399:        log_buffer_append_printf(b, fmt, ap);
                    400:        va_end(ap);
                    401: 
                    402:        prefix_used = b->used;
                    403: 
                    404:        current_line = pos = multiline->ptr;
                    405:        end = multiline->ptr + multiline->used;
                    406: 
                    407:        for ( ; pos < end ; ++pos) {
                    408:                switch (*pos) {
                    409:                case '\n':
                    410:                case '\r':
                    411:                case '\0': /* handles end of string */
                    412:                        if (current_line < pos) {
                    413:                                /* truncate to prefix */
                    414:                                b->used = prefix_used;
                    415:                                b->ptr[b->used - 1] = '\0';
                    416: 
                    417:                                buffer_append_string_len(b, current_line, pos - current_line);
                    418:                                log_write(srv, b);
                    419:                        }
                    420:                        current_line = pos + 1;
                    421:                        break;
                    422:                default:
                    423:                        break;
                    424:                }
                    425:        }
                    426: 
                    427:        return 0;
                    428: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>