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

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: 
        !           125: #ifdef FD_CLOEXEC
        !           126:        fcntl(fd, F_SETFD, FD_CLOEXEC);
        !           127: #endif
        !           128: 
        !           129:        return fd;
        !           130: }
        !           131: 
        !           132: 
        !           133: /**
        !           134:  * open the errorlog
        !           135:  *
        !           136:  * we have 4 possibilities:
        !           137:  * - stderr (default)
        !           138:  * - syslog
        !           139:  * - logfile
        !           140:  * - pipe
        !           141:  *
        !           142:  * if the open failed, report to the user and die
        !           143:  *
        !           144:  */
        !           145: 
        !           146: int log_error_open(server *srv) {
        !           147: #ifdef HAVE_SYSLOG_H
        !           148:        /* perhaps someone wants to use syslog() */
        !           149:        openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
        !           150: #endif
        !           151: 
        !           152:        srv->errorlog_mode = ERRORLOG_FD;
        !           153:        srv->errorlog_fd = STDERR_FILENO;
        !           154: 
        !           155:        if (srv->srvconf.errorlog_use_syslog) {
        !           156:                srv->errorlog_mode = ERRORLOG_SYSLOG;
        !           157:        } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
        !           158:                const char *logfile = srv->srvconf.errorlog_file->ptr;
        !           159: 
        !           160:                if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) {
        !           161:                        return -1;
        !           162:                }
        !           163:                srv->errorlog_mode = (logfile[0] == '|') ? ERRORLOG_PIPE : ERRORLOG_FILE;
        !           164:        }
        !           165: 
        !           166:        log_error_write(srv, __FILE__, __LINE__, "s", "server started");
        !           167: 
        !           168:        if (srv->errorlog_mode == ERRORLOG_FD && !srv->srvconf.dont_daemonize) {
        !           169:                /* We can only log to stderr in dont-daemonize mode;
        !           170:                 * if we do daemonize and no errorlog file is specified, we log into /dev/null
        !           171:                 */
        !           172:                srv->errorlog_fd = -1;
        !           173:        }
        !           174: 
        !           175:        if (!buffer_is_empty(srv->srvconf.breakagelog_file)) {
        !           176:                int breakage_fd;
        !           177:                const char *logfile = srv->srvconf.breakagelog_file->ptr;
        !           178: 
        !           179:                if (srv->errorlog_mode == ERRORLOG_FD) {
        !           180:                        srv->errorlog_fd = dup(STDERR_FILENO);
        !           181: #ifdef FD_CLOEXEC
        !           182:                        fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
        !           183: #endif
        !           184:                }
        !           185: 
        !           186:                if (-1 == (breakage_fd = open_logfile_or_pipe(srv, logfile))) {
        !           187:                        return -1;
        !           188:                }
        !           189: 
        !           190:                if (STDERR_FILENO != breakage_fd) {
        !           191:                        dup2(breakage_fd, STDERR_FILENO);
        !           192:                        close(breakage_fd);
        !           193:                }
        !           194:        } else if (!srv->srvconf.dont_daemonize) {
        !           195:                /* move stderr to /dev/null */
        !           196:                openDevNull(STDERR_FILENO);
        !           197:        }
        !           198:        return 0;
        !           199: }
        !           200: 
        !           201: /**
        !           202:  * open the errorlog
        !           203:  *
        !           204:  * if the open failed, report to the user and die
        !           205:  * if no filename is given, use syslog instead
        !           206:  *
        !           207:  */
        !           208: 
        !           209: int log_error_cycle(server *srv) {
        !           210:        /* only cycle if the error log is a file */
        !           211: 
        !           212:        if (srv->errorlog_mode == ERRORLOG_FILE) {
        !           213:                const char *logfile = srv->srvconf.errorlog_file->ptr;
        !           214:                /* already check of opening time */
        !           215: 
        !           216:                int new_fd;
        !           217: 
        !           218:                if (-1 == (new_fd = open_logfile_or_pipe(srv, logfile))) {
        !           219:                        /* write to old log */
        !           220:                        log_error_write(srv, __FILE__, __LINE__, "SSSSS",
        !           221:                                        "cycling errorlog '", logfile,
        !           222:                                        "' failed: ", strerror(errno),
        !           223:                                        ", falling back to syslog()");
        !           224: 
        !           225:                        close(srv->errorlog_fd);
        !           226:                        srv->errorlog_fd = -1;
        !           227: #ifdef HAVE_SYSLOG_H
        !           228:                        srv->errorlog_mode = ERRORLOG_SYSLOG;
        !           229: #endif
        !           230:                } else {
        !           231:                        /* ok, new log is open, close the old one */
        !           232:                        close(srv->errorlog_fd);
        !           233:                        srv->errorlog_fd = new_fd;
        !           234: #ifdef FD_CLOEXEC
        !           235:                        /* close fd on exec (cgi) */
        !           236:                        fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
        !           237: #endif
        !           238:                }
        !           239:        }
        !           240: 
        !           241:        return 0;
        !           242: }
        !           243: 
        !           244: int log_error_close(server *srv) {
        !           245:        switch(srv->errorlog_mode) {
        !           246:        case ERRORLOG_PIPE:
        !           247:        case ERRORLOG_FILE:
        !           248:        case ERRORLOG_FD:
        !           249:                if (-1 != srv->errorlog_fd) {
        !           250:                        /* don't close STDERR */
        !           251:                        if (STDERR_FILENO != srv->errorlog_fd)
        !           252:                                close(srv->errorlog_fd);
        !           253:                        srv->errorlog_fd = -1;
        !           254:                }
        !           255:                break;
        !           256:        case ERRORLOG_SYSLOG:
        !           257: #ifdef HAVE_SYSLOG_H
        !           258:                closelog();
        !           259: #endif
        !           260:                break;
        !           261:        }
        !           262: 
        !           263:        return 0;
        !           264: }
        !           265: 
        !           266: /* lowercase: append space, uppercase: don't */
        !           267: static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
        !           268:        for(; *fmt; fmt++) {
        !           269:                int d;
        !           270:                char *s;
        !           271:                buffer *b;
        !           272:                off_t o;
        !           273: 
        !           274:                switch(*fmt) {
        !           275:                case 's':           /* string */
        !           276:                        s = va_arg(ap, char *);
        !           277:                        buffer_append_string(out, s);
        !           278:                        buffer_append_string_len(out, CONST_STR_LEN(" "));
        !           279:                        break;
        !           280:                case 'b':           /* buffer */
        !           281:                        b = va_arg(ap, buffer *);
        !           282:                        buffer_append_string_buffer(out, b);
        !           283:                        buffer_append_string_len(out, CONST_STR_LEN(" "));
        !           284:                        break;
        !           285:                case 'd':           /* int */
        !           286:                        d = va_arg(ap, int);
        !           287:                        buffer_append_long(out, d);
        !           288:                        buffer_append_string_len(out, CONST_STR_LEN(" "));
        !           289:                        break;
        !           290:                case 'o':           /* off_t */
        !           291:                        o = va_arg(ap, off_t);
        !           292:                        buffer_append_off_t(out, o);
        !           293:                        buffer_append_string_len(out, CONST_STR_LEN(" "));
        !           294:                        break;
        !           295:                case 'x':           /* int (hex) */
        !           296:                        d = va_arg(ap, int);
        !           297:                        buffer_append_string_len(out, CONST_STR_LEN("0x"));
        !           298:                        buffer_append_long_hex(out, d);
        !           299:                        buffer_append_string_len(out, CONST_STR_LEN(" "));
        !           300:                        break;
        !           301:                case 'S':           /* string */
        !           302:                        s = va_arg(ap, char *);
        !           303:                        buffer_append_string(out, s);
        !           304:                        break;
        !           305:                case 'B':           /* buffer */
        !           306:                        b = va_arg(ap, buffer *);
        !           307:                        buffer_append_string_buffer(out, b);
        !           308:                        break;
        !           309:                case 'D':           /* int */
        !           310:                        d = va_arg(ap, int);
        !           311:                        buffer_append_long(out, d);
        !           312:                        break;
        !           313:                case 'O':           /* off_t */
        !           314:                        o = va_arg(ap, off_t);
        !           315:                        buffer_append_off_t(out, o);
        !           316:                        break;
        !           317:                case 'X':           /* int (hex) */
        !           318:                        d = va_arg(ap, int);
        !           319:                        buffer_append_string_len(out, CONST_STR_LEN("0x"));
        !           320:                        buffer_append_long_hex(out, d);
        !           321:                        break;
        !           322:                case '(':
        !           323:                case ')':
        !           324:                case '<':
        !           325:                case '>':
        !           326:                case ',':
        !           327:                case ' ':
        !           328:                        buffer_append_string_len(out, fmt, 1);
        !           329:                        break;
        !           330:                }
        !           331:        }
        !           332: }
        !           333: 
        !           334: static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) {
        !           335:        switch(srv->errorlog_mode) {
        !           336:        case ERRORLOG_PIPE:
        !           337:        case ERRORLOG_FILE:
        !           338:        case ERRORLOG_FD:
        !           339:                if (-1 == srv->errorlog_fd) return -1;
        !           340:                /* cache the generated timestamp */
        !           341:                if (srv->cur_ts != srv->last_generated_debug_ts) {
        !           342:                        buffer_prepare_copy(srv->ts_debug_str, 255);
        !           343:                        strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
        !           344:                        srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
        !           345: 
        !           346:                        srv->last_generated_debug_ts = srv->cur_ts;
        !           347:                }
        !           348: 
        !           349:                buffer_copy_string_buffer(b, srv->ts_debug_str);
        !           350:                buffer_append_string_len(b, CONST_STR_LEN(": ("));
        !           351:                break;
        !           352:        case ERRORLOG_SYSLOG:
        !           353:                /* syslog is generating its own timestamps */
        !           354:                buffer_copy_string_len(b, CONST_STR_LEN("("));
        !           355:                break;
        !           356:        }
        !           357: 
        !           358:        buffer_append_string(b, filename);
        !           359:        buffer_append_string_len(b, CONST_STR_LEN("."));
        !           360:        buffer_append_long(b, line);
        !           361:        buffer_append_string_len(b, CONST_STR_LEN(") "));
        !           362: 
        !           363:        return 0;
        !           364: }
        !           365: 
        !           366: static void log_write(server *srv, buffer *b) {
        !           367:        switch(srv->errorlog_mode) {
        !           368:        case ERRORLOG_PIPE:
        !           369:        case ERRORLOG_FILE:
        !           370:        case ERRORLOG_FD:
        !           371:                buffer_append_string_len(b, CONST_STR_LEN("\n"));
        !           372:                write(srv->errorlog_fd, b->ptr, b->used - 1);
        !           373:                break;
        !           374:        case ERRORLOG_SYSLOG:
        !           375:                syslog(LOG_ERR, "%s", b->ptr);
        !           376:                break;
        !           377:        }
        !           378: }
        !           379: 
        !           380: int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
        !           381:        va_list ap;
        !           382: 
        !           383:        if (-1 == log_buffer_prepare(srv->errorlog_buf, srv, filename, line)) return 0;
        !           384: 
        !           385:        va_start(ap, fmt);
        !           386:        log_buffer_append_printf(srv->errorlog_buf, fmt, ap);
        !           387:        va_end(ap);
        !           388: 
        !           389:        log_write(srv, srv->errorlog_buf);
        !           390: 
        !           391:        return 0;
        !           392: }
        !           393: 
        !           394: int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
        !           395:        va_list ap;
        !           396:        size_t prefix_used;
        !           397:        buffer *b = srv->errorlog_buf;
        !           398:        char *pos, *end, *current_line;
        !           399: 
        !           400:        if (multiline->used < 2) return 0;
        !           401: 
        !           402:        if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0;
        !           403: 
        !           404:        va_start(ap, fmt);
        !           405:        log_buffer_append_printf(b, fmt, ap);
        !           406:        va_end(ap);
        !           407: 
        !           408:        prefix_used = b->used;
        !           409: 
        !           410:        current_line = pos = multiline->ptr;
        !           411:        end = multiline->ptr + multiline->used;
        !           412: 
        !           413:        for ( ; pos < end ; ++pos) {
        !           414:                switch (*pos) {
        !           415:                case '\n':
        !           416:                case '\r':
        !           417:                case '\0': /* handles end of string */
        !           418:                        if (current_line < pos) {
        !           419:                                /* truncate to prefix */
        !           420:                                b->used = prefix_used;
        !           421:                                b->ptr[b->used - 1] = '\0';
        !           422: 
        !           423:                                buffer_append_string_len(b, current_line, pos - current_line);
        !           424:                                log_write(srv, b);
        !           425:                        }
        !           426:                        current_line = pos + 1;
        !           427:                        break;
        !           428:                default:
        !           429:                        break;
        !           430:                }
        !           431:        }
        !           432: 
        !           433:        return 0;
        !           434: }

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