#include #include #include #include #include #include #include #include "version.h" #include "str.h" int use_syslog = 0; static FILE *logfp = 0; #ifdef HAVE_SYSLOG #include const int log_debug = LOG_DEBUG; const int log_info = LOG_INFO; const int log_warning = LOG_WARNING; const int log_fatal = LOG_CRIT; #else const int log_debug = -1; const int log_info = 0; const int log_warning = 1; const int log_fatal = 2; #endif static void log_pipe(const char *s) { int fds[2]; if (pipe(fds) == -1) { cfatal("Could not create pipe: %s"); } switch (fork()) { case -1: cfatal("Could not fork: %s"); break; case 0: close(0); close(1); close(2); dup2(fds[0], 0); execl("/bin/sh", "/bin/sh", "-c", s); exit(1); }; close(fds[0]); logfp = fdopen(fds[1], "w"); if (!logfp) { logfp = stderr; cfatal("Could not attach fd to logger: %s"); } } static void log_file(const char *s) { int fd; fd = open(s, O_CREAT|O_WRONLY|O_APPEND, 0666); if (fd == -1) { cfatal("Could not open `%s' for writing: %s", s); } logfp = fdopen(fd, "w"); if (!logfp) { logfp = stderr; cfatal("Could not attach fd to logger: %s"); } } void log_init(char *s) { int fd; use_syslog = 0; logfp = stderr; if (s && str_equali(s, "quiet")) { logfp = fopen("/dev/null", "w"); } else if (s && *s == '/') { log_file(s); } else if (s && *s == '|') { log_pipe(s+1); } else if (s && str_starti(s, "file:/")) { log_file(s+5); } else if (s && str_starti(s, "pipe:/")) { log_pipe(s+5); } else if (s && str_starti(s, "exec:/")) { log_pipe(s+5); } else if (s && str_starti(s, "prog:/")) { log_pipe(s+5); } else if (s && str_starti(s, "program:/")) { log_pipe(s+8); } else if (s && str_equali(s, "syslog")) { #ifdef HAVE_SYSLOG use_syslog = 1; openlog(PROGRAM, LOG_CONS | LOG_NDELAY #ifdef LOG_PERROR | LOG_PERROR #endif | LOG_PID, LOG_DAEMON); logfp = 0; #else use_syslog = 0; warning("You do not have syslog() support compiled in, defaulting to stderr"); #endif } } static void _log_helper(int lev, int clib_flag, const char *m, va_list ap) { str_t buf; char lbuf[32]; str_init(buf); while (*m) { if (*m == '%') { switch (m[1]) { case '%': str_addch(buf, '%'); break; case 's': if (clib_flag) {/* Clib */ clib_flag = 0; str_cat(buf, strerror(errno)); } else str_cat(buf, va_arg(ap, char *)); break; case 'd': sprintf(lbuf, "%d", va_arg(ap, int)); str_cat(buf, lbuf); break; case 'c': str_addch(buf, va_arg(ap, int)); break; default: fatal("unknown log() specifier %%%c", m[1]); }; m++; m++; } else { str_addch(buf, m[0]); m++; } } #ifdef HAVE_SYSLOG if (use_syslog) { fprintf(stderr, "level = %d: %s\n", lev, str(buf)); syslog(lev, "%s", str(buf)); } else #endif if (logfp) { fprintf(logfp, "%s %s: %s\n", PROGRAM, (lev == log_info ? "info" :lev == log_warning ? "warning" :lev == log_debug ? "debug" :"fatal"), str(buf)); fflush(logfp); } mem_free(str(buf)); } void inline status(const char *s, ...) { va_list ap; if (!logfp) return; va_start(ap, s); vfprintf(logfp, s, ap); fputc('\n', logfp); fflush(logfp); va_end(ap); } void inline log(int lev, const char *m, ...) { va_list ap; va_start(ap, m); _log_helper(lev, 0, m, ap); va_end(ap); } #define MAKE_LOGGING_FUNCTION(A,B) \ void inline A(const char *m, ...) \ { \ va_list ap; \ va_start(ap, m); \ _log_helper(log_ ## A, 0, m, ap); \ va_end(ap); B; \ } \ void inline c ## A(const char *m, ...) \ { \ va_list ap; \ va_start(ap, m); \ _log_helper(log_ ## A, 1, m, ap); \ va_end(ap); B; \ } MAKE_LOGGING_FUNCTION(fatal,exit(1)) MAKE_LOGGING_FUNCTION(warning,return) MAKE_LOGGING_FUNCTION(debug,return) #undef MAKE_LOGGING_FUNCTION