File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / log.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:20:06 2014 UTC (10 years ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_35p0, v1_4_35, HEAD
lighttpd 1.4.35

    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: 	fd_close_on_exec(fd);
  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);
  179: 			fd_close_on_exec(srv->errorlog_fd);
  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;
  230: 			fd_close_on_exec(srv->errorlog_fd);
  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"));
  365: 		force_assert(b->used > 0);
  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>