From 0bdeb5e58d8fdf8b0f30461a388768112b0e080c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 6 May 2017 06:40:17 +0200 Subject: lib: rewrite zlog lock-free & TLS-buffered This is a full rewrite of the "back end" logging code. It now uses a lock-free list to iterate over logging targets, and the targets themselves are as lock-free as possible. (syslog() may have a hidden internal mutex in the C library; the file/fd targets use a single write() call which should ensure atomicity kernel-side.) Note that some functionality is lost in this patch: - Solaris printstack() backtraces are ditched (unlikely to come back) - the `log-filter` machinery is gone (re-added in followup commit) - `terminal monitor` is temporarily stubbed out. The old code had a race condition with VTYs going away. It'll likely come back rewritten and with vtysh support. - The `zebra_ext_log` hook is gone. Instead, it's now much easier to add a "proper" logging target. v2: TLS buffer to get some actual performance Signed-off-by: David Lamparter --- lib/log.c | 703 +++----------------------------------------------------------- 1 file changed, 24 insertions(+), 679 deletions(-) (limited to 'lib/log.c') diff --git a/lib/log.c b/lib/log.c index b3be5216aa..9b0f5b3d85 100644 --- a/lib/log.c +++ b/lib/log.c @@ -25,7 +25,6 @@ #include "zclient.h" #include "log.h" -#include "log_int.h" #include "memory.h" #include "command.h" #include "lib_errors.h" @@ -33,154 +32,12 @@ #include "printfrr.h" #include "frr_pthread.h" -#ifndef SUNOS_5 -#include -#endif -/* for printstack on solaris */ -#ifdef HAVE_UCONTEXT_H -#include -#endif - #ifdef HAVE_LIBUNWIND #define UNW_LOCAL_ONLY #include #include #endif -DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging") - -/* hook for external logging */ -DEFINE_HOOK(zebra_ext_log, (int priority, const char *format, va_list args), - (priority, format, args)); - -static int logfile_fd = -1; /* Used in signal handler. */ - -struct zlog *zlog_default = NULL; -bool zlog_startup_stderr = true; - -/* lock protecting zlog_default for mt-safe zlog */ -static pthread_mutex_t loglock = PTHREAD_MUTEX_INITIALIZER; - -const char *zlog_priority[] = { - "emergencies", "alerts", "critical", "errors", "warnings", - "notifications", "informational", "debugging", NULL, -}; - -static char zlog_filters[ZLOG_FILTERS_MAX][ZLOG_FILTER_LENGTH_MAX + 1]; -static uint8_t zlog_filter_count; - -/* - * look for a match on the filter in the current filters, loglock must be held - */ -static int zlog_filter_lookup(const char *lookup) -{ - for (int i = 0; i < zlog_filter_count; i++) { - if (strncmp(lookup, zlog_filters[i], sizeof(zlog_filters[0])) - == 0) - return i; - } - return -1; -} - -void zlog_filter_clear(void) -{ - frr_with_mutex(&loglock) { - zlog_filter_count = 0; - } -} - -int zlog_filter_add(const char *filter) -{ - frr_with_mutex(&loglock) { - if (zlog_filter_count >= ZLOG_FILTERS_MAX) - return 1; - - if (zlog_filter_lookup(filter) != -1) - /* Filter already present */ - return -1; - - strlcpy(zlog_filters[zlog_filter_count], filter, - sizeof(zlog_filters[0])); - - if (zlog_filters[zlog_filter_count][0] == '\0') - /* Filter was either empty or didn't get copied - * correctly - */ - return -1; - - zlog_filter_count++; - } - return 0; -} - -int zlog_filter_del(const char *filter) -{ - frr_with_mutex(&loglock) { - int found_idx = zlog_filter_lookup(filter); - int last_idx = zlog_filter_count - 1; - - if (found_idx == -1) - /* Didn't find the filter to delete */ - return -1; - - /* Adjust the filter array */ - memmove(zlog_filters[found_idx], zlog_filters[found_idx + 1], - (last_idx - found_idx) * sizeof(zlog_filters[0])); - - zlog_filter_count--; - } - return 0; -} - -/* Dump all filters to buffer, delimited by new line */ -int zlog_filter_dump(char *buf, size_t max_size) -{ - int len = 0; - - frr_with_mutex(&loglock) { - for (int i = 0; i < zlog_filter_count; i++) { - int ret; - ret = snprintf(buf + len, max_size - len, " %s\n", - zlog_filters[i]); - len += ret; - if ((ret < 0) || ((size_t)len >= max_size)) - return -1; - } - } - - return len; -} - -/* - * write_wrapper - * - * glibc has declared that the return value from write *must* not be - * ignored. - * gcc see's this problem and issues a warning for the line. - * - * Why is this a big deal you say? Because both of them are right - * and if you have -Werror enabled then all calls to write - * generate a build error and the build stops. - * - * clang has helpfully allowed this construct: - * (void)write(...) - * to tell the compiler yeah I know it has a return value - * I don't care about it at this time. - * gcc doesn't have this ability. - * - * This code was written such that it didn't care about the - * return value from write. At this time do I want - * to go through and fix and test this code for correctness. - * So just wrapper the bad behavior and move on. - */ -static void write_wrapper(int fd, const void *buf, size_t count) -{ - if (write(fd, buf, count) <= 0) - return; - - return; -} - /** * Looks up a message in a message list by key. * @@ -264,274 +121,12 @@ size_t quagga_timestamp(int timestamp_precision, char *buf, size_t buflen) return 0; } -static inline void timestamp_control_render(struct timestamp_control *ctl) -{ - if (!ctl->already_rendered) { - ctl->len = quagga_timestamp(ctl->precision, ctl->buf, - sizeof(ctl->buf)); - ctl->already_rendered = 1; - } -} - -/* Utility routine for current time printing. */ -static void time_print(FILE *fp, struct timestamp_control *ctl) -{ - timestamp_control_render(ctl); - fprintf(fp, "%s ", ctl->buf); -} - -static int time_print_buf(char *buf, int len, int max_size, - struct timestamp_control *ctl) -{ - timestamp_control_render(ctl); - - if (ctl->len + 1 >= (unsigned long)max_size) - return -1; - - return snprintf(buf + len, max_size - len, "%s ", ctl->buf); -} - -static void vzlog_file(struct zlog *zl, struct timestamp_control *tsctl, - const char *proto_str, int record_priority, int priority, - FILE *fp, const char *msg) -{ - time_print(fp, tsctl); - if (record_priority) - fprintf(fp, "%s: ", zlog_priority[priority]); - - fprintf(fp, "%s%s\n", proto_str, msg); - fflush(fp); -} - -/* Search a buf for the filter strings, loglock must be held */ -static int search_buf(const char *buf) -{ - char *found = NULL; - - for (int i = 0; i < zlog_filter_count; i++) { - found = strstr(buf, zlog_filters[i]); - if (found != NULL) - return 0; - } - - return -1; -} - -/* Filter out a log */ -static int vzlog_filter(struct zlog *zl, struct timestamp_control *tsctl, - const char *proto_str, int priority, const char *msg) -{ - int len = 0; - int ret = 0; - char buf[1024] = ""; - - ret = time_print_buf(buf, len, sizeof(buf), tsctl); - - len += ret; - if ((ret < 0) || ((size_t)len >= sizeof(buf))) - goto search; - - if (zl && zl->record_priority) - snprintf(buf + len, sizeof(buf) - len, "%s: %s: %s", - zlog_priority[priority], proto_str, msg); - else - snprintf(buf + len, sizeof(buf) - len, "%s: %s", proto_str, - msg); - -search: - return search_buf(buf); -} - -/* va_list version of zlog. */ -void vzlog(int priority, const char *format, va_list args) -{ - frr_mutex_lock_autounlock(&loglock); - - char proto_str[32] = ""; - int original_errno = errno; - struct timestamp_control tsctl = {}; - tsctl.already_rendered = 0; - struct zlog *zl = zlog_default; - char buf[256], *msg; - - if (zl == NULL) { - tsctl.precision = 0; - } else { - tsctl.precision = zl->timestamp_precision; - if (zl->instance) - sprintf(proto_str, "%s[%d]: ", zl->protoname, - zl->instance); - else - sprintf(proto_str, "%s: ", zl->protoname); - } - - msg = vasnprintfrr(MTYPE_TMP, buf, sizeof(buf), format, args); - - /* If it doesn't match on a filter, do nothing with the debug log */ - if ((priority == LOG_DEBUG) && zlog_filter_count - && vzlog_filter(zl, &tsctl, proto_str, priority, msg)) - goto out; - - /* call external hook */ - hook_call(zebra_ext_log, priority, format, args); - - /* When zlog_default is also NULL, use stderr for logging. */ - if (zl == NULL) { - time_print(stderr, &tsctl); - fprintf(stderr, "%s: %s\n", "unknown", msg); - fflush(stderr); - goto out; - } - - /* Syslog output */ - if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG]) - syslog(priority | zlog_default->facility, "%s", msg); - - /* File output. */ - if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) - vzlog_file(zl, &tsctl, proto_str, zl->record_priority, priority, - zl->fp, msg); - - /* fixed-config logging to stderr while we're stating up & haven't - * daemonized / reached mainloop yet - * - * note the "else" on stdout output -- we don't want to print the same - * message to both stderr and stdout. */ - if (zlog_startup_stderr && priority <= LOG_WARNING) - vzlog_file(zl, &tsctl, proto_str, 1, priority, stderr, msg); - else if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) - vzlog_file(zl, &tsctl, proto_str, zl->record_priority, priority, - stdout, msg); - - /* Terminal monitor. */ - if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) - vty_log((zl->record_priority ? zlog_priority[priority] : NULL), - proto_str, msg, &tsctl); - -out: - if (msg != buf) - XFREE(MTYPE_TMP, msg); - errno = original_errno; -} - -int vzlog_test(int priority) -{ - frr_mutex_lock_autounlock(&loglock); - - struct zlog *zl = zlog_default; - - /* When zlog_default is also NULL, use stderr for logging. */ - if (zl == NULL) - return 1; - /* Syslog output */ - else if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG]) - return 1; - /* File output. */ - else if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) - return 1; - /* stdout output. */ - else if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) - return 1; - /* Terminal monitor. */ - else if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) - return 1; - - return 0; -} - /* * crash handling * * NB: only AS-Safe (async-signal) functions can be used here! */ -/* Needs to be enhanced to support Solaris. */ -static int syslog_connect(void) -{ -#ifdef SUNOS_5 - return -1; -#else - int fd; - struct sockaddr_un addr; - - if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) - return -1; - addr.sun_family = AF_UNIX; -#ifdef _PATH_LOG -#define SYSLOG_SOCKET_PATH _PATH_LOG -#else -#define SYSLOG_SOCKET_PATH "/dev/log" -#endif - strlcpy(addr.sun_path, SYSLOG_SOCKET_PATH, sizeof(addr.sun_path)); -#undef SYSLOG_SOCKET_PATH - if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - close(fd); - return -1; - } - return fd; -#endif -} - -static void syslog_sigsafe(int priority, const char *msg, size_t msglen) -{ - static int syslog_fd = -1; - char buf[sizeof("<1234567890>ripngd[1234567890]: ") + msglen + 50]; - struct fbuf fb = { .buf = buf, .pos = buf, .len = sizeof(buf) }; - - if ((syslog_fd < 0) && ((syslog_fd = syslog_connect()) < 0)) - return; - - /* forget about the timestamp, too difficult in a signal handler */ - bprintfrr(&fb, "<%d>%s", priority, zlog_default->ident); - if (zlog_default->syslog_options & LOG_PID) - bprintfrr(&fb, "[%ld]", (long)getpid()); - bprintfrr(&fb, ": %s", msg); - write_wrapper(syslog_fd, fb.buf, fb.pos - fb.buf); -} - -static int open_crashlog(void) -{ - char crashlog_buf[PATH_MAX]; - const char *crashlog_default = "/var/tmp/frr.crashlog", *crashlog; - - if (!zlog_default || !zlog_default->ident) - crashlog = crashlog_default; - else { - snprintfrr(crashlog_buf, sizeof(crashlog_buf), - "/var/tmp/frr.%s.crashlog", zlog_default->ident); - crashlog = crashlog_buf; - } - return open(crashlog, O_WRONLY | O_CREAT | O_EXCL, LOGFILE_MASK); -} - -/* N.B. implicit priority is most severe */ -#define PRI LOG_CRIT - -static void crash_write(struct fbuf *fb, char *msgstart) -{ - if (fb->pos == fb->buf) - return; - if (!msgstart) - msgstart = fb->buf; - - /* If no file logging configured, try to write to fallback log file. */ - if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0)) - write(logfile_fd, fb->buf, fb->pos - fb->buf); - if (!zlog_default) - write(STDERR_FILENO, fb->buf, fb->pos - fb->buf); - else { - if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT]) - write(STDOUT_FILENO, fb->buf, fb->pos - fb->buf); - /* Remove trailing '\n' for monitor and syslog */ - fb->pos--; - if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) - vty_log_fixed(fb->buf, fb->pos - fb->buf); - if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) - syslog_sigsafe(PRI | zlog_default->facility, msgstart, - fb->pos - msgstart); - } -} - /* Note: the goal here is to use only async-signal-safe functions. */ void zlog_signal(int signo, const char *action, void *siginfo_v, void *program_counter) @@ -540,14 +135,9 @@ void zlog_signal(int signo, const char *action, void *siginfo_v, time_t now; char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...") + 100]; - char *msgstart; struct fbuf fb = { .buf = buf, .pos = buf, .len = sizeof(buf) }; time(&now); - if (zlog_default) - bprintfrr(&fb, "%s: ", zlog_default->protoname); - - msgstart = fb.pos; bprintfrr(&fb, "Received signal %d at %lld", signo, (long long)now); if (program_counter) @@ -559,9 +149,9 @@ void zlog_signal(int signo, const char *action, void *siginfo_v, (ptrdiff_t)siginfo->si_addr); bprintfrr(&fb, "; %s\n", action); - crash_write(&fb, msgstart); + zlog_sigsafe(fb.buf, fb.pos - fb.buf); - zlog_backtrace_sigsafe(PRI, program_counter); + zlog_backtrace_sigsafe(LOG_CRIT, program_counter); fb.pos = buf; @@ -574,7 +164,7 @@ void zlog_signal(int signo, const char *action, void *siginfo_v, bprintfrr(&fb, "in thread %s scheduled from %s:%d\n", tc->funcname, tc->schedfrom, tc->schedfrom_line); - crash_write(&fb, NULL); + zlog_sigsafe(fb.buf, fb.pos - fb.buf); } /* Log a backtrace using only async-signal-safe functions. @@ -609,85 +199,35 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter) bprintfrr(&fb, " %s (mapped at %p)", dlinfo.dli_fname, dlinfo.dli_fbase); bprintfrr(&fb, "\n"); - crash_write(&fb, NULL); + zlog_sigsafe(fb.buf, fb.pos - fb.buf); } -#elif defined(HAVE_GLIBC_BACKTRACE) || defined(HAVE_PRINTSTACK) - static const char pclabel[] = "Program counter: "; +#elif defined(HAVE_GLIBC_BACKTRACE) void *array[64]; - int size; + int size, i; char buf[128]; struct fbuf fb = { .buf = buf, .pos = buf, .len = sizeof(buf) }; char **bt = NULL; -#ifdef HAVE_GLIBC_BACKTRACE size = backtrace(array, array_size(array)); if (size <= 0 || (size_t)size > array_size(array)) return; -#define DUMP(FD) \ - { \ - if (program_counter) { \ - write_wrapper(FD, pclabel, sizeof(pclabel) - 1); \ - backtrace_symbols_fd(&program_counter, 1, FD); \ - } \ - write_wrapper(FD, fb.buf, fb.pos - fb.buf); \ - backtrace_symbols_fd(array, size, FD); \ - } -#elif defined(HAVE_PRINTSTACK) - size = 0; - -#define DUMP(FD) \ - { \ - if (program_counter) \ - write_wrapper((FD), pclabel, sizeof(pclabel) - 1); \ - write_wrapper((FD), fb.buf, fb.pos - fb.buf); \ - printstack((FD)); \ - } -#endif /* HAVE_GLIBC_BACKTRACE, HAVE_PRINTSTACK */ + bprintfrr(&fb, "Backtrace for %d stack frames:", size); + zlog_sigsafe(fb.pos, fb.buf - fb.pos); - bprintfrr(&fb, "Backtrace for %d stack frames:\n", size); + bt = backtrace_symbols(array, size); - if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0)) - DUMP(logfile_fd) - if (!zlog_default) - DUMP(STDERR_FILENO) - else { - if (priority <= zlog_default->maxlvl[ZLOG_DEST_STDOUT]) - DUMP(STDOUT_FILENO) - /* Remove trailing '\n' for monitor and syslog */ - fb.pos--; - if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) - vty_log_fixed(fb.buf, fb.pos - fb.buf); - if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) - syslog_sigsafe(priority | zlog_default->facility, - fb.buf, fb.pos - fb.buf); - { - int i; -#ifdef HAVE_GLIBC_BACKTRACE - bt = backtrace_symbols(array, size); -#endif - /* Just print the function addresses. */ - for (i = 0; i < size; i++) { - fb.pos = buf; - if (bt) - bprintfrr(&fb, "%s", bt[i]); - else - bprintfrr(&fb, "[bt %d] 0x%tx", i, - (ptrdiff_t)(array[i])); - if (priority - <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) - vty_log_fixed(fb.buf, fb.pos - fb.buf); - if (priority - <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) - syslog_sigsafe(priority - | zlog_default->facility, - fb.buf, fb.pos - fb.buf); - } - if (bt) - free(bt); - } + for (i = 0; i < size; i++) { + fb.pos = buf; + if (bt) + bprintfrr(&fb, "%s", bt[i]); + else + bprintfrr(&fb, "[bt %d] 0x%tx", i, + (ptrdiff_t)(array[i])); + zlog_sigsafe(fb.buf, fb.pos - fb.buf); } -#undef DUMP + if (bt) + free(bt); #endif /* HAVE_STRACK_TRACE */ } @@ -754,36 +294,6 @@ void zlog_backtrace(int priority) #endif } -void zlog(int priority, const char *format, ...) -{ - va_list args; - - va_start(args, format); - vzlog(priority, format, args); - va_end(args); -} - -#define ZLOG_FUNC(FUNCNAME, PRIORITY) \ - void FUNCNAME(const char *format, ...) \ - { \ - va_list args; \ - va_start(args, format); \ - vzlog(PRIORITY, format, args); \ - va_end(args); \ - } - -ZLOG_FUNC(zlog_err, LOG_ERR) - -ZLOG_FUNC(zlog_warn, LOG_WARNING) - -ZLOG_FUNC(zlog_info, LOG_INFO) - -ZLOG_FUNC(zlog_notice, LOG_NOTICE) - -ZLOG_FUNC(zlog_debug, LOG_DEBUG) - -#undef ZLOG_FUNC - void zlog_thread_info(int log_level) { struct thread *tc; @@ -801,11 +311,6 @@ void zlog_thread_info(int log_level) void _zlog_assert_failed(const char *assertion, const char *file, unsigned int line, const char *function) { - /* 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(LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s", assertion, file, line, (function ? function : "?")); zlog_backtrace(LOG_CRIT); @@ -816,174 +321,14 @@ void _zlog_assert_failed(const char *assertion, const char *file, void memory_oom(size_t size, const char *name) { - flog_err_sys(EC_LIB_SYSTEM_CALL, - "out of memory: failed to allocate %zu bytes for %s" - "object", - size, name); - zlog_backtrace(LOG_ERR); + zlog(LOG_CRIT, + "out of memory: failed to allocate %zu bytes for %s object", + size, name); + zlog_backtrace(LOG_CRIT); + log_memstats(stderr, "log"); abort(); } -/* Open log stream */ -void openzlog(const char *progname, const char *protoname, - unsigned short instance, int syslog_flags, int syslog_facility) -{ - struct zlog *zl; - unsigned int i; - - zl = XCALLOC(MTYPE_ZLOG, sizeof(struct zlog)); - - zl->ident = progname; - zl->protoname = protoname; - zl->instance = instance; - zl->facility = syslog_facility; - zl->syslog_options = syslog_flags; - - /* Set default logging levels. */ - for (i = 0; i < array_size(zl->maxlvl); i++) - zl->maxlvl[i] = ZLOG_DISABLED; - zl->maxlvl[ZLOG_DEST_MONITOR] = LOG_DEBUG; - zl->default_lvl = LOG_DEBUG; - - openlog(progname, syslog_flags, zl->facility); - - frr_with_mutex(&loglock) { - zlog_default = zl; - } - -#ifdef HAVE_GLIBC_BACKTRACE - /* work around backtrace() using lazily resolved dynamically linked - * symbols, which will otherwise cause funny breakage in the SEGV - * handler. - * (particularly, the dynamic linker can call malloc(), which uses locks - * in programs linked with -pthread, thus can deadlock.) */ - void *bt[4]; - backtrace(bt, array_size(bt)); - free(backtrace_symbols(bt, 0)); - backtrace_symbols_fd(bt, 0, 0); -#endif -} - -void closezlog(void) -{ - frr_mutex_lock_autounlock(&loglock); - - struct zlog *zl = zlog_default; - - closelog(); - - if (zl->fp != NULL) - fclose(zl->fp); - - XFREE(MTYPE_ZLOG, zl->filename); - - XFREE(MTYPE_ZLOG, zl); - zlog_default = NULL; -} - -/* Called from command.c. */ -void zlog_set_level(zlog_dest_t dest, int log_level) -{ - frr_with_mutex(&loglock) { - zlog_default->maxlvl[dest] = log_level; - } -} - -int zlog_set_file(const char *filename, int log_level) -{ - struct zlog *zl; - FILE *fp; - mode_t oldumask; - int ret = 1; - - /* There is opend file. */ - zlog_reset_file(); - - /* Open file. */ - oldumask = umask(0777 & ~LOGFILE_MASK); - fp = fopen(filename, "a"); - umask(oldumask); - if (fp == NULL) { - ret = 0; - } else { - frr_with_mutex(&loglock) { - zl = zlog_default; - - /* Set flags. */ - zl->filename = XSTRDUP(MTYPE_ZLOG, filename); - zl->maxlvl[ZLOG_DEST_FILE] = log_level; - zl->fp = fp; - logfile_fd = fileno(fp); - } - } - - return ret; -} - -/* Reset opend file. */ -int zlog_reset_file(void) -{ - frr_mutex_lock_autounlock(&loglock); - - struct zlog *zl = zlog_default; - - if (zl->fp) - fclose(zl->fp); - zl->fp = NULL; - logfile_fd = -1; - zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED; - - XFREE(MTYPE_ZLOG, zl->filename); - - return 1; -} - -/* Reopen log file. */ -int zlog_rotate(void) -{ - pthread_mutex_lock(&loglock); - - struct zlog *zl = zlog_default; - int level; - int ret = 1; - - 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) { - - pthread_mutex_unlock(&loglock); - - flog_err_sys( - EC_LIB_SYSTEM_CALL, - "Log rotate failed: cannot open file %s for append: %s", - zl->filename, safe_strerror(save_errno)); - ret = -1; - - pthread_mutex_lock(&loglock); - } else { - logfile_fd = fileno(zl->fp); - zl->maxlvl[ZLOG_DEST_FILE] = level; - } - } - - pthread_mutex_unlock(&loglock); - - return ret; -} - /* Wrapper around strerror to handle case where it returns NULL. */ const char *safe_strerror(int errnum) { -- cgit v1.2.3