#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "version.h"
#include "str.h"
int use_syslog = 0;
static FILE *logfp = 0;
#ifdef HAVE_SYSLOG
#include <syslog.h>
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
syntax highlighted by Code2HTML, v. 0.9.1