/* * log.c: * * Copyright (c) 2008 James McKenzie , * All rights reserved. * */ static char rcsid[] = "$Id$"; /* * $Log$ * Revision 1.18 2012/06/22 10:22:24 james * *** empty log message *** * * Revision 1.17 2011/02/04 16:14:16 james * *** empty log message *** * * Revision 1.16 2010/07/27 14:49:35 james * add support for byte logging * * Revision 1.15 2010/07/16 11:04:10 james * ignore tedious return values * * Revision 1.14 2008/03/11 17:56:04 james * *** empty log message *** * * Revision 1.13 2008/03/11 16:56:29 james * *** empty log message *** * * Revision 1.12 2008/03/10 11:49:33 james * *** empty log message *** * * Revision 1.11 2008/03/07 13:16:02 james * *** empty log message *** * * Revision 1.10 2008/03/07 12:37:04 james * *** empty log message *** * * Revision 1.9 2008/03/03 06:20:14 james * *** empty log message *** * * Revision 1.8 2008/03/03 06:04:42 james * *** empty log message *** * * Revision 1.7 2008/03/03 06:04:18 james * *** empty log message *** * * Revision 1.6 2008/03/02 10:37:56 james * *** empty log message *** * * Revision 1.5 2008/02/27 01:31:14 james * *** empty log message *** * * Revision 1.4 2008/02/27 00:54:16 james * *** empty log message *** * * Revision 1.3 2008/02/23 11:48:37 james * *** empty log message *** * * Revision 1.2 2008/02/22 14:51:54 james * *** empty log message *** * * Revision 1.1 2008/02/14 12:14:50 james * *** empty log message *** * */ #include "project.h" #include typedef struct { LOG_SIGNATURE; int do_close; int rotate; FILE *fp; char *filename; int needs_newline; } File_Log; typedef struct { LOG_SIGNATURE; char buf[256]; unsigned ptr; int priority; } Syslog_Log; static Log *loggers = NULL; static void sighup (int dummy) { Log *l; for (l = loggers; l; l = l->next) { if (l->sighup) l->sighup (l); } } void log_register_handlers (void) { struct sigaction sa = { {0} }; sa.sa_handler = sighup; sa.sa_flags = SA_RESTART; sigaction (SIGHUP, &sa, NULL); } void log_add (Log * l) { log_register_handlers (); l->next = loggers; loggers = l; } void log_remove (Log * l) { Log **ptr = &loggers; /* Take out of sighup list */ while (*ptr && (*ptr != l)) ptr = &((*ptr)->next); if (*ptr) *ptr = l->next; } static void flog_newline (Log * _l, int force) { File_Log *l = (File_Log *) _l; if (force || !l->needs_newline) return; l->needs_newline = 0; fputc ('\n', l->fp); fflush (l->fp); } static void flog_sighup (Log * _l) { File_Log *l = (File_Log *) _l; if (!l->fp) return; log_f (_l, ""); fclose (l->fp); l->fp = fopen (l->filename, "a+"); log_f (_l, ""); } static void flog_emit_stamp (Log * _l) { File_Log *l = (File_Log *) _l; struct timeval tv = { 0 }; struct tm *tm; time_t t; #if 0 static const char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; #endif static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; if (!l->fp) return; flog_newline (_l, 0); gettimeofday (&tv, NULL); t = tv.tv_sec; tm = localtime (&t); fprintf (l->fp, "%s %2d %02d:%02d:%02d.%06d ", months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int) tv.tv_usec); } static void flog_check_rotate (Log * _l) { File_Log *l = (File_Log *) _l; if (l->rotate && rotate_check (l->filename)) { fclose (l->fp); rotate (l->filename); l->fp = fopen (l->filename, "a+"); } } static void flog_log_bytes (Log * _l, void *_buf, int len) { File_Log *l = (File_Log *) _l; uint8_t *buf = (uint8_t *) _buf; if (!l->fp) return; while (len--) { if (*buf == '\n') { flog_newline (_l, 1); flog_check_rotate (_l); flog_emit_stamp (_l); } else { l->needs_newline++; fputc (*buf, l->fp); } buf++; } } static void flog_log (Log * _l, char *buf) { File_Log *l = (File_Log *) _l; if (!l->fp) return; flog_emit_stamp (_l); fputs (buf, l->fp); fputc ('\n', l->fp); fflush (l->fp); flog_check_rotate (_l); } static void flog_close (Log * _l) { File_Log *l = (File_Log *) _l; if (l->fp && l->do_close) fclose (l->fp); if (l->filename) free (l->filename); free (l); } Log * file_log_new (char *fn, int rotate) { File_Log *l; int dc = 1; l = xmalloc (sizeof (File_Log)); if (fn && strcmp (fn, "-")) { l->fp = fopen (fn, "a+"); if (!l->fp) { free (l); return NULL; } l->sighup = flog_sighup; } else { l->fp = stderr; dc = 0; } l->log = flog_log; l->log_bytes = flog_log_bytes; l->close = flog_close; l->do_close = dc; l->rotate = rotate; l->filename = strdup (fn); l->needs_newline = 0; fput_cp (l->fp, 0xffef); log_add ((Log *) l); return (Log *) l; } static void slog_log_bytes (Log * _l, void *_buf, int len) { Syslog_Log *l = (Syslog_Log *) _l; uint8_t *buf = (uint8_t *) _buf; while (len--) { if (*buf == '\n') { l->buf[l->ptr]=0; syslog(l->priority,"%s",l->buf); l->ptr=0; } else { l->buf[l->ptr++]=*buf; } if (l->ptr==(sizeof(l->buf)-1)) { l->buf[l->ptr]=0; syslog(l->priority,"%s",l->buf); l->ptr=0; } buf++; } } static void slog_log (Log * _l, char *buf) { Syslog_Log *l = (Syslog_Log *) _l; syslog(l->priority,"%s",buf); } static void slog_close (Log * _l) { free (_l); } Log * syslog_log_new (int pri) { Syslog_Log *l; l = xmalloc (sizeof (Syslog_Log)); l->log = slog_log; l->log_bytes = slog_log_bytes; l->close= slog_close; l->priority = pri; l->ptr=0; log_add ((Log *) l); return (Log *) l; } void log_f (Log * log, char *fmt, ...) { int n; static char *buf; va_list ap; static int size; if (!log) return; if (!size) { size = 128; buf = malloc (size); } if (!buf) return; while (1) { va_start (ap, fmt); n = vsnprintf (buf, size, fmt, ap); va_end (ap); if (n > -1 && n < size) { log->log (log, buf); return; } if (n > -1) /* glibc 2.1 */ size = n + 1; else /* glibc 2.0 */ size *= 2; /* twice the old size */ buf = xrealloc (buf, size); if (!buf) return; } }