diff options
Diffstat (limited to 'lib/log.c')
-rw-r--r-- | lib/log.c | 658 |
1 files changed, 547 insertions, 111 deletions
@@ -34,6 +34,25 @@ #ifdef HAVE_UCONTEXT_H #include <ucontext.h> #endif +#include "qpthreads.h" + +#ifdef NDEBUG +#define LOCK qpt_mutex_lock(vty_mutex); +#define UNLOCK qpt_mutex_unlock(vty_mutex); +#else +#define LOCK qpt_mutex_lock(vty_mutex);++vty_lock_count; +#define UNLOCK --vty_lock_count;qpt_mutex_unlock(vty_mutex); +#define ASSERTLOCKED if(vty_lock_count==0 && !vty_lock_asserted){vty_lock_asserted=1;assert(0);} +#endif + +/* log is protected by the same mutext as vty, see comments in vty.c */ + +/* prototypes */ +static int uzlog_reset_file (struct zlog *zl); +static void zlog_abort (const char *mess) __attribute__ ((noreturn)); +static void vzlog (struct zlog *zl, int priority, const char *format, va_list args); +static void uzlog_backtrace(int priority); +static void uvzlog (struct zlog *zl, int priority, const char *format, va_list args); static int logfile_fd = -1; /* Used in signal handler. */ @@ -66,14 +85,23 @@ const char *zlog_priority[] = "debugging", NULL, }; - - /* For time string format. */ size_t quagga_timestamp(int timestamp_precision, char *buf, size_t buflen) { + size_t result; + LOCK + result = uquagga_timestamp(timestamp_precision, buf, buflen); + UNLOCK + return result; +} + +/* unprotected version for when mutex already held */ +size_t +uquagga_timestamp(int timestamp_precision, char *buf, size_t buflen) +{ static struct { time_t last; size_t len; @@ -81,6 +109,8 @@ quagga_timestamp(int timestamp_precision, char *buf, size_t buflen) } cache; struct timeval clock; + size_t result = 0; + /* would it be sufficient to use global 'recent_time' here? I fear not... */ gettimeofday(&clock, NULL); @@ -122,14 +152,19 @@ quagga_timestamp(int timestamp_precision, char *buf, size_t buflen) } while (--prec > 0); *p = '.'; - return cache.len+1+timestamp_precision; + result = cache.len+1+timestamp_precision; } - buf[cache.len] = '\0'; - return cache.len; + else + { + buf[cache.len] = '\0'; + result = cache.len; + } + } else { + if (buflen > 0) + buf[0] = '\0'; } - if (buflen > 0) - buf[0] = '\0'; - return 0; + + return result; } /* Utility routine for current time printing. */ @@ -138,20 +173,30 @@ time_print(FILE *fp, struct timestamp_control *ctl) { if (!ctl->already_rendered) { - ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); + ctl->len = uquagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); ctl->already_rendered = 1; } fprintf(fp, "%s ", ctl->buf); } - /* va_list version of zlog. */ static void vzlog (struct zlog *zl, int priority, const char *format, va_list args) { + LOCK + uvzlog(zl, priority, format, args); + UNLOCK +} + +/* va_list version of zlog. Unprotected assumes mutex already held*/ +static void +uvzlog (struct zlog *zl, int priority, const char *format, va_list args) +{ struct timestamp_control tsctl; tsctl.already_rendered = 0; + ASSERTLOCKED + /* If zlog is not specified, use default one. */ if (zl == NULL) zl = zlog_default; @@ -165,55 +210,58 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args) vfprintf (stderr, format, args); fprintf (stderr, "\n"); fflush (stderr); - - /* In this case we return at here. */ - return; } - tsctl.precision = zl->timestamp_precision; - - /* Syslog output */ - if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG]) + else { - va_list ac; - va_copy(ac, args); - vsyslog (priority|zlog_default->facility, format, ac); - va_end(ac); - } + tsctl.precision = zl->timestamp_precision; - /* File output. */ - if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) - { - va_list ac; - time_print (zl->fp, &tsctl); - if (zl->record_priority) - fprintf (zl->fp, "%s: ", zlog_priority[priority]); - fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]); - va_copy(ac, args); - vfprintf (zl->fp, format, ac); - va_end(ac); - fprintf (zl->fp, "\n"); - fflush (zl->fp); - } + /* Syslog output */ + if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG]) + { + va_list ac; + va_copy(ac, args); + vsyslog (priority|zlog_default->facility, format, ac); + va_end(ac); + } - /* stdout output. */ - if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) - { - va_list ac; - time_print (stdout, &tsctl); - if (zl->record_priority) - fprintf (stdout, "%s: ", zlog_priority[priority]); - fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]); - va_copy(ac, args); - vfprintf (stdout, format, ac); - va_end(ac); - fprintf (stdout, "\n"); - fflush (stdout); - } + /* File output. */ + if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) + { + va_list ac; + time_print (zl->fp, &tsctl); + if (zl->record_priority) + fprintf (zl->fp, "%s: ", zlog_priority[priority]); + fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]); + va_copy(ac, args); + vfprintf (zl->fp, format, ac); + va_end(ac); + fprintf (zl->fp, "\n"); + fflush (zl->fp); + } - /* Terminal monitor. */ - if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) - vty_log ((zl->record_priority ? zlog_priority[priority] : NULL), - zlog_proto_names[zl->protocol], format, &tsctl, args); + /* stdout output. */ + if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) + { + va_list ac; + time_print (stdout, &tsctl); + if (zl->record_priority) + fprintf (stdout, "%s: ", zlog_priority[priority]); + fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]); + va_copy(ac, args); + vfprintf (stdout, format, ac); + va_end(ac); + fprintf (stdout, "\n"); + fflush (stdout); + } + + /* Terminal monitor. */ + if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) + { + const char *priority_name = (zl->record_priority ? zlog_priority[priority] : NULL); + const char *proto_name = zlog_proto_names[zl->protocol]; + vty_log (priority_name, proto_name, format, &tsctl, args); + } + } } static char * @@ -518,8 +566,16 @@ zlog_backtrace_sigsafe(int priority, void *program_counter) void zlog_backtrace(int priority) { + LOCK + zlog_backtrace(priority); + UNLOCK +} + +static void +uzlog_backtrace(int priority) +{ #ifndef HAVE_GLIBC_BACKTRACE - zlog(NULL, priority, "No backtrace available on this platform."); + uzlog(NULL, priority, "No backtrace available on this platform."); #else void *array[20]; int size, i; @@ -528,27 +584,38 @@ zlog_backtrace(int priority) if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) || ((size_t)size > sizeof(array)/sizeof(array[0]))) { - zlog_err("Cannot get backtrace, returned invalid # of frames %d " + uzlog(NULL, LOG_ERR, "Cannot get backtrace, returned invalid # of frames %d " "(valid range is between 1 and %lu)", size, (unsigned long)(sizeof(array)/sizeof(array[0]))); return; } - zlog(NULL, priority, "Backtrace for %d stack frames:", size); + uzlog(NULL, priority, "Backtrace for %d stack frames:", size); if (!(strings = backtrace_symbols(array, size))) { - zlog_err("Cannot get backtrace symbols (out of memory?)"); + uzlog(NULL, LOG_ERR, "Cannot get backtrace symbols (out of memory?)"); for (i = 0; i < size; i++) - zlog(NULL, priority, "[bt %d] %p",i,array[i]); + uzlog(NULL, priority, "[bt %d] %p",i,array[i]); } else { for (i = 0; i < size; i++) - zlog(NULL, priority, "[bt %d] %s",i,strings[i]); + uzlog(NULL, priority, "[bt %d] %s",i,strings[i]); free(strings); } #endif /* HAVE_GLIBC_BACKTRACE */ } +/* unlocked version */ +void +uzlog (struct zlog *zl, int priority, const char *format, ...) +{ + va_list args; + + va_start(args, format); + uvzlog (zl, priority, format, args); + va_end (args); +} + void zlog (struct zlog *zl, int priority, const char *format, ...) { @@ -605,16 +672,69 @@ PLOG_FUNC(plog_debug, LOG_DEBUG) void _zlog_assert_failed (const char *assertion, const char *file, - unsigned int line, const char *function) + unsigned int line, const char *function) +{ + const static size_t buff_size = 1024; + char buff[buff_size]; + snprintf(buff, buff_size, + "Assertion `%s' failed in file %s, line %u, function %s", + assertion, file, line, (function ? function : "?")); + zlog_abort(buff); +} + +/* Abort with message */ +void +_zlog_abort_mess (const char *mess, const char *file, + unsigned int line, const char *function) +{ + const static size_t buff_size = 1024; + char buff[buff_size]; + snprintf(buff, buff_size, "%s, in file %s, line %u, function %s", + mess, file, line, (function ? function : "?")); + zlog_abort(buff); +} + +/* Abort with message and errno and strerror() thereof */ +void +_zlog_abort_errno (const char *mess, const char *file, + unsigned int line, const char *function) +{ + _zlog_abort_err(mess, errno, file, line, function); +} + +/* Abort with message and given error and strerror() thereof */ +void +_zlog_abort_err (const char *mess, int err, const char *file, + unsigned int line, const char *function) +{ + const static size_t buff_size = 1024; + char buff[buff_size]; + char err_mess[buff_size]; + strerror_r(err, err_mess, buff_size); + snprintf(buff, buff_size, + "%s, in file %s, line %u, function %s, error %d \"%s\"", + mess, file, line, (function ? function : "?"), + err, err_mess); + zlog_abort(buff); +} + + +static void +zlog_abort (const char *mess) { +#ifndef NDEBUG + /* don't work about being unlocked */ + vty_lock_asserted = 1; +#endif + /* Force fallback file logging? */ if (zlog_default && !zlog_default->fp && ((logfile_fd = open_crashlog()) >= 0) && ((zlog_default->fp = fdopen(logfile_fd, "w")) != NULL)) zlog_default->maxlvl[ZLOG_DEST_FILE] = LOG_ERR; - zlog(NULL, LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s", - assertion,file,line,(function ? function : "?")); - zlog_backtrace(LOG_CRIT); + + uzlog(NULL, LOG_CRIT, "%s", mess); + uzlog_backtrace(LOG_CRIT); abort(); } @@ -648,22 +768,33 @@ openzlog (const char *progname, zlog_proto_t protocol, void closezlog (struct zlog *zl) { + LOCK + closelog(); if (zl->fp != NULL) fclose (zl->fp); XFREE (MTYPE_ZLOG, zl); + + UNLOCK } /* Called from command.c. */ void zlog_set_level (struct zlog *zl, zlog_dest_t dest, int log_level) { + LOCK + if (zl == NULL) zl = zlog_default; - zl->maxlvl[dest] = log_level; + if (zl != NULL) + { + zl->maxlvl[dest] = log_level; + } + + UNLOCK } int @@ -671,46 +802,68 @@ zlog_set_file (struct zlog *zl, const char *filename, int log_level) { FILE *fp; mode_t oldumask; + int result = 1; + + LOCK /* There is opend file. */ - zlog_reset_file (zl); + uzlog_reset_file (zl); /* Set default zl. */ if (zl == NULL) zl = zlog_default; - /* Open file. */ - oldumask = umask (0777 & ~LOGFILE_MASK); - fp = fopen (filename, "a"); - umask(oldumask); - if (fp == NULL) - return 0; - - /* Set flags. */ - zl->filename = strdup (filename); - zl->maxlvl[ZLOG_DEST_FILE] = log_level; - zl->fp = fp; - logfile_fd = fileno(fp); + if (zl != NULL) + { + /* Open file. */ + oldumask = umask (0777 & ~LOGFILE_MASK); + fp = fopen (filename, "a"); + umask(oldumask); + if (fp == NULL) + result = 0; + else + { + /* Set flags. */ + zl->filename = strdup (filename); + zl->maxlvl[ZLOG_DEST_FILE] = log_level; + zl->fp = fp; + logfile_fd = fileno(fp); + } + } - return 1; + UNLOCK + return result; } /* Reset opend file. */ int zlog_reset_file (struct zlog *zl) { + int result; + LOCK + result = uzlog_reset_file(zl); + UNLOCK + return result; +} + +static int +uzlog_reset_file (struct zlog *zl) + { if (zl == NULL) zl = zlog_default; - if (zl->fp) - fclose (zl->fp); - zl->fp = NULL; - logfile_fd = -1; - zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED; - - if (zl->filename) - free (zl->filename); - zl->filename = NULL; + if (zl != NULL) + { + if (zl->fp) + fclose (zl->fp); + zl->fp = NULL; + logfile_fd = -1; + zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED; + + if (zl->filename) + free (zl->filename); + zl->filename = NULL; + } return 1; } @@ -720,39 +873,318 @@ int zlog_rotate (struct zlog *zl) { int level; + int result = 1; + + LOCK if (zl == NULL) zl = zlog_default; - if (zl->fp) - fclose (zl->fp); - zl->fp = NULL; - logfile_fd = -1; - level = zl->maxlvl[ZLOG_DEST_FILE]; - zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED; + if (zl != NULL) + { + if (zl->fp) + fclose (zl->fp); + zl->fp = NULL; + logfile_fd = -1; + level = zl->maxlvl[ZLOG_DEST_FILE]; + zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED; + + if (zl->filename) + { + mode_t oldumask; + int save_errno; + + oldumask = umask (0777 & ~LOGFILE_MASK); + zl->fp = fopen (zl->filename, "a"); + save_errno = errno; + umask(oldumask); + if (zl->fp == NULL) + { + /* can't call logging while locked */ + char *fname = strdup(zl->filename); + uzlog(NULL, LOG_ERR, "Log rotate failed: cannot open file %s for append: %s", + fname, safe_strerror(save_errno)); + free(fname); + result = -1; + } + else + { + logfile_fd = fileno(zl->fp); + zl->maxlvl[ZLOG_DEST_FILE] = level; + } + } + } + UNLOCK + return result; +} + +int +zlog_get_default_lvl (struct zlog *zl) +{ + int result = LOG_DEBUG; + + LOCK - if (zl->filename) + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) { - mode_t oldumask; - int save_errno; + result = zl->default_lvl; + } - oldumask = umask (0777 & ~LOGFILE_MASK); - zl->fp = fopen (zl->filename, "a"); - save_errno = errno; - umask(oldumask); - if (zl->fp == NULL) - { - zlog_err("Log rotate failed: cannot open file %s for append: %s", - zl->filename, safe_strerror(save_errno)); - return -1; - } - logfile_fd = fileno(zl->fp); - zl->maxlvl[ZLOG_DEST_FILE] = level; + UNLOCK + return result; +} + +void +zlog_set_default_lvl (struct zlog *zl, int level) +{ + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + zl->default_lvl = level; } - return 1; + UNLOCK } - + +/* Set logging level and default for all destinations */ +void +zlog_set_default_lvl_dest (struct zlog *zl, int level) +{ + int i; + + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + zl->default_lvl = level; + + for (i = 0; i < ZLOG_NUM_DESTS; i++) + if (zl->maxlvl[i] != ZLOG_DISABLED) + zl->maxlvl[i] = level; + } + + UNLOCK +} + +int +zlog_get_maxlvl (struct zlog *zl, zlog_dest_t dest) +{ + int result = ZLOG_DISABLED; + + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + result = zl->maxlvl[dest]; + } + + UNLOCK + return result; +} + +int +zlog_get_facility (struct zlog *zl) +{ + int result = LOG_DAEMON; + + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + result = zl->facility; + } + + UNLOCK + return result; +} + +void +zlog_set_facility (struct zlog *zl, int facility) +{ + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + zl->facility = facility; + } + + UNLOCK +} + +int +zlog_get_record_priority (struct zlog *zl) +{ + int result = 0; + + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + result = zl->record_priority; + } + + UNLOCK + return result; +} + +void +zlog_set_record_priority (struct zlog *zl, int record_priority) +{ + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + zl->record_priority = record_priority; + } + UNLOCK +} + +int +zlog_get_timestamp_precision (struct zlog *zl) +{ + int result = 0; + + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + result = zl->timestamp_precision; + } + UNLOCK + return result; +} + +void +zlog_set_timestamp_precision (struct zlog *zl, int timestamp_precision) +{ + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + zl->timestamp_precision = timestamp_precision; + } + + UNLOCK +} + +/* returns name of ZLOG_NONE if no zlog given and no default set */ +const char * +zlog_get_proto_name (struct zlog *zl) +{ + const char * result; + LOCK + result = uzlog_get_proto_name(zl); + UNLOCK + return result; +} + +/* unprotected version, assumes mutex held */ +const char * +uzlog_get_proto_name (struct zlog *zl) +{ + zlog_proto_t protocol = ZLOG_NONE; + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + protocol = zl->protocol; + } + + return zlog_proto_names[protocol]; +} + +/* caller must free result */ +char * +zlog_get_filename (struct zlog *zl) +{ + char * result = NULL; + + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL && zl->filename != NULL) + { + result = strdup(zl->filename); + } + + UNLOCK + return result; +} + +const char * +zlog_get_ident (struct zlog *zl) +{ + const char * result = NULL; + + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + result = zl->ident; + } + + UNLOCK + return result; +} + +/* logging to a file? */ +int +zlog_is_file (struct zlog *zl) +{ + int result = 0; + + LOCK + + if (zl == NULL) + zl = zlog_default; + + if (zl != NULL) + { + result = (zl->fp != NULL); + } + + UNLOCK; + return result; +} + /* Message lookup function. */ const char * lookup (const struct message *mes, int key) @@ -928,3 +1360,7 @@ proto_name2num(const char *s) return -1; } #undef RTSIZE + +#undef LOCK +#undef UNLOCK +#undef ASSERTLOCKED |