summaryrefslogtreecommitdiffstats
path: root/lib/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/log.c')
-rw-r--r--lib/log.c371
1 files changed, 126 insertions, 245 deletions
diff --git a/lib/log.c b/lib/log.c
index 5e3064a8d..5ce3bd702 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -30,6 +30,7 @@
#include "command.h"
#include "lib_errors.h"
#include "lib/hook.h"
+#include "printfrr.h"
#ifndef SUNOS_5
#include <sys/un.h>
@@ -191,19 +192,13 @@ static void time_print(FILE *fp, struct timestamp_control *ctl)
static void vzlog_file(struct zlog *zl, struct timestamp_control *tsctl,
const char *proto_str, int record_priority, int priority,
- FILE *fp, const char *format, va_list args)
+ FILE *fp, const char *msg)
{
- va_list ac;
-
time_print(fp, tsctl);
if (record_priority)
fprintf(fp, "%s: ", zlog_priority[priority]);
- fprintf(fp, "%s", proto_str);
- va_copy(ac, args);
- vfprintf(fp, format, ac);
- va_end(ac);
- fprintf(fp, "\n");
+ fprintf(fp, "%s%s\n", proto_str, msg);
fflush(fp);
}
@@ -217,33 +212,26 @@ void vzlog(int priority, const char *format, va_list args)
struct timestamp_control tsctl;
tsctl.already_rendered = 0;
struct zlog *zl = zlog_default;
+ char buf[256], *msg;
/* call external hook */
hook_call(zebra_ext_log, priority, format, args);
+ msg = vasnprintfrr(MTYPE_TMP, buf, sizeof(buf), format, args);
+
/* When zlog_default is also NULL, use stderr for logging. */
if (zl == NULL) {
tsctl.precision = 0;
time_print(stderr, &tsctl);
- fprintf(stderr, "%s: ", "unknown");
- vfprintf(stderr, format, args);
- fprintf(stderr, "\n");
+ fprintf(stderr, "%s: %s\n", "unknown", msg);
fflush(stderr);
-
- /* In this case we return at here. */
- errno = original_errno;
- pthread_mutex_unlock(&loglock);
- return;
+ goto out;
}
tsctl.precision = zl->timestamp_precision;
/* 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);
- }
+ if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG])
+ syslog(priority | zlog_default->facility, "%s", msg);
if (zl->instance)
sprintf(proto_str, "%s[%d]: ", zl->protoname, zl->instance);
@@ -253,7 +241,7 @@ void vzlog(int priority, const char *format, va_list args)
/* File output. */
if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
vzlog_file(zl, &tsctl, proto_str, zl->record_priority, priority,
- zl->fp, format, args);
+ zl->fp, msg);
/* fixed-config logging to stderr while we're stating up & haven't
* daemonized / reached mainloop yet
@@ -261,17 +249,19 @@ void vzlog(int priority, const char *format, va_list args)
* 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, format,
- args);
+ 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, format, args);
+ stdout, msg);
/* Terminal monitor. */
if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
vty_log((zl->record_priority ? zlog_priority[priority] : NULL),
- proto_str, format, &tsctl, args);
+ proto_str, msg, &tsctl);
+out:
+ if (msg != buf)
+ XFREE(MTYPE_TMP, msg);
errno = original_errno;
pthread_mutex_unlock(&loglock);
}
@@ -305,47 +295,11 @@ int vzlog_test(int priority)
return ret;
}
-static char *str_append(char *dst, int len, const char *src)
-{
- while ((len-- > 0) && *src)
- *dst++ = *src++;
- return dst;
-}
-
-static char *num_append(char *s, int len, unsigned long x)
-{
- char buf[30];
- char *t;
-
- if (!x)
- return str_append(s, len, "0");
- *(t = &buf[sizeof(buf) - 1]) = '\0';
- while (x && (t > buf)) {
- *--t = '0' + (x % 10);
- x /= 10;
- }
- return str_append(s, len, t);
-}
-
-#if defined(SA_SIGINFO) \
- || defined(HAVE_PRINTSTACK) \
- || defined(HAVE_GLIBC_BACKTRACE)
-static char *hex_append(char *s, int len, unsigned long x)
-{
- char buf[30];
- char *t;
-
- if (!x)
- return str_append(s, len, "0");
- *(t = &buf[sizeof(buf) - 1]) = '\0';
- while (x && (t > buf)) {
- unsigned int cc = (x % 16);
- *--t = ((cc < 10) ? ('0' + cc) : ('a' + cc - 10));
- x /= 16;
- }
- return str_append(s, len, t);
-}
-#endif
+/*
+ * 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)
@@ -354,7 +308,6 @@ static int syslog_connect(void)
return -1;
#else
int fd;
- char *s;
struct sockaddr_un addr;
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
@@ -365,10 +318,8 @@ static int syslog_connect(void)
#else
#define SYSLOG_SOCKET_PATH "/dev/log"
#endif
- s = str_append(addr.sun_path, sizeof(addr.sun_path),
- SYSLOG_SOCKET_PATH);
+ strlcpy(addr.sun_path, SYSLOG_SOCKET_PATH, sizeof(addr.sun_path));
#undef SYSLOG_SOCKET_PATH
- *s = '\0';
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(fd);
return -1;
@@ -381,168 +332,109 @@ 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];
- char *s;
+ struct fbuf fb = { .buf = buf, .pos = buf, .len = sizeof(buf) };
if ((syslog_fd < 0) && ((syslog_fd = syslog_connect()) < 0))
return;
-#define LOC s,buf+sizeof(buf)-s
- s = buf;
- s = str_append(LOC, "<");
- s = num_append(LOC, priority);
- s = str_append(LOC, ">");
/* forget about the timestamp, too difficult in a signal handler */
- s = str_append(LOC, zlog_default->ident);
- if (zlog_default->syslog_options & LOG_PID) {
- s = str_append(LOC, "[");
- s = num_append(LOC, getpid());
- s = str_append(LOC, "]");
- }
- s = str_append(LOC, ": ");
- s = str_append(LOC, msg);
- write_wrapper(syslog_fd, buf, s - buf);
-#undef LOC
+ 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)
{
-#define CRASHLOG_PREFIX "/var/tmp/quagga."
-#define CRASHLOG_SUFFIX "crashlog"
- if (zlog_default && zlog_default->ident) {
- /* Avoid strlen since it is not async-signal-safe. */
- const char *p;
- size_t ilen;
-
- for (p = zlog_default->ident, ilen = 0; *p; p++)
- ilen++;
- {
- char buf[sizeof(CRASHLOG_PREFIX) + ilen
- + sizeof(CRASHLOG_SUFFIX) + 3];
- char *s = buf;
-#define LOC s,buf+sizeof(buf)-s
- s = str_append(LOC, CRASHLOG_PREFIX);
- s = str_append(LOC, zlog_default->ident);
- s = str_append(LOC, ".");
- s = str_append(LOC, CRASHLOG_SUFFIX);
-#undef LOC
- *s = '\0';
- return open(buf, O_WRONLY | O_CREAT | O_EXCL,
- LOGFILE_MASK);
- }
- }
- return open(CRASHLOG_PREFIX CRASHLOG_SUFFIX,
- O_WRONLY | O_CREAT | O_EXCL, LOGFILE_MASK);
-#undef CRASHLOG_SUFFIX
-#undef CRASHLOG_PREFIX
-}
-
-/* Note: the goal here is to use only async-signal-safe functions. */
-void zlog_signal(int signo, const char *action
-#ifdef SA_SIGINFO
- ,
- siginfo_t *siginfo, void *program_counter
-#endif
- )
-{
- time_t now;
- char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")
- + 100];
- char *s = buf;
- char *msgstart = buf;
-#define LOC s,buf+sizeof(buf)-s
+ char crashlog_buf[PATH_MAX];
+ const char *crashlog_default = "/var/tmp/frr.crashlog", *crashlog;
- time(&now);
- if (zlog_default) {
- s = str_append(LOC, zlog_default->protoname);
- *s++ = ':';
- *s++ = ' ';
- msgstart = s;
- }
- s = str_append(LOC, "Received signal ");
- s = num_append(LOC, signo);
- s = str_append(LOC, " at ");
- s = num_append(LOC, now);
-#ifdef SA_SIGINFO
- s = str_append(LOC, " (si_addr 0x");
- s = hex_append(LOC, (unsigned long)(siginfo->si_addr));
- if (program_counter) {
- s = str_append(LOC, ", PC 0x");
- s = hex_append(LOC, (unsigned long)program_counter);
+ 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;
}
- s = str_append(LOC, "); ");
-#else /* SA_SIGINFO */
- s = str_append(LOC, "; ");
-#endif /* SA_SIGINFO */
- s = str_append(LOC, action);
- if (s < buf + sizeof(buf))
- *s++ = '\n';
+ return open(crashlog, O_WRONLY | O_CREAT | O_EXCL, LOGFILE_MASK);
+}
/* N.B. implicit priority is most severe */
#define PRI LOG_CRIT
-#define DUMP(FD) write_wrapper(FD, buf, s-buf);
+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))
- DUMP(logfile_fd)
+ write(logfile_fd, fb->buf, fb->pos - fb->buf);
if (!zlog_default)
- DUMP(STDERR_FILENO)
+ write(STDERR_FILENO, fb->buf, fb->pos - fb->buf);
else {
if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
- DUMP(STDOUT_FILENO)
+ write(STDOUT_FILENO, fb->buf, fb->pos - fb->buf);
/* Remove trailing '\n' for monitor and syslog */
- *--s = '\0';
+ fb->pos--;
if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
- vty_log_fixed(buf, s - buf);
+ vty_log_fixed(fb->buf, fb->pos - fb->buf);
if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
syslog_sigsafe(PRI | zlog_default->facility, msgstart,
- s - msgstart);
+ fb->pos - msgstart);
}
-#undef DUMP
+}
- zlog_backtrace_sigsafe(PRI,
+/* 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)
+{
#ifdef SA_SIGINFO
- program_counter
-#else
- NULL
+ siginfo_t *siginfo = siginfo_v;
#endif
- );
+ 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);
+#ifdef SA_SIGINFO
+ if (program_counter)
+ bprintfrr(&fb, " (si_addr 0x%tx, PC 0x%tx)",
+ (ptrdiff_t)siginfo->si_addr,
+ (ptrdiff_t)program_counter);
+ else
+ bprintfrr(&fb, " (si_addr 0x%tx)",
+ (ptrdiff_t)siginfo->si_addr);
+#endif /* SA_SIGINFO */
+ bprintfrr(&fb, "; %s\n", action);
+
+ crash_write(&fb, msgstart);
+
+ zlog_backtrace_sigsafe(PRI, program_counter);
+
+ fb.pos = buf;
- s = buf;
struct thread *tc;
tc = pthread_getspecific(thread_current);
- if (!tc)
- s = str_append(LOC, "no thread information available\n");
- else {
- s = str_append(LOC, "in thread ");
- s = str_append(LOC, tc->funcname);
- s = str_append(LOC, " scheduled from ");
- s = str_append(LOC, tc->schedfrom);
- s = str_append(LOC, ":");
- s = num_append(LOC, tc->schedfrom_line);
- s = str_append(LOC, "\n");
- }
-#define DUMP(FD) write_wrapper(FD, buf, s-buf);
- /* If no file logging configured, try to write to fallback log file. */
- if (logfile_fd >= 0)
- DUMP(logfile_fd)
- if (!zlog_default)
- DUMP(STDERR_FILENO)
- else {
- if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
- DUMP(STDOUT_FILENO)
- /* Remove trailing '\n' for monitor and syslog */
- *--s = '\0';
- if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
- vty_log_fixed(buf, s - buf);
- if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
- syslog_sigsafe(PRI | zlog_default->facility, msgstart,
- s - msgstart);
- }
-#undef DUMP
+ if (!tc)
+ bprintfrr(&fb, "no thread information available\n");
+ else
+ bprintfrr(&fb, "in thread %s scheduled from %s:%d\n",
+ tc->funcname, tc->schedfrom, tc->schedfrom_line);
-#undef PRI
-#undef LOC
+ crash_write(&fb, NULL);
}
/* Log a backtrace using only async-signal-safe functions.
@@ -550,7 +442,8 @@ void zlog_signal(int signo, const char *action
void zlog_backtrace_sigsafe(int priority, void *program_counter)
{
#ifdef HAVE_LIBUNWIND
- char buf[100];
+ char buf[256];
+ struct fbuf fb = { .buf = buf, .len = sizeof(buf) };
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip, off, sp;
@@ -564,28 +457,27 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
- if (unw_is_signal_frame(&cursor))
- dprintf(2, " ---- signal ----\n");
-
- if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off)) {
- snprintf(name, sizeof(name), "%s+%#lx",
- buf, (long)off);
- }
- dprintf(2, "%-30s %16lx %16lx", name, (long)ip, (long)sp);
- if (dladdr((void *)ip, &dlinfo)) {
- dprintf(2, " %s (mapped at %p)",
- dlinfo.dli_fname, dlinfo.dli_fbase);
- }
- dprintf(2, "\n");
+ if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off))
+ snprintfrr(name, sizeof(name), "%s+%#lx",
+ buf, (long)off);
+ fb.pos = buf;
+ if (unw_is_signal_frame(&cursor))
+ bprintfrr(&fb, " ---- signal ----\n");
+ bprintfrr(&fb, "%-30s %16lx %16lx", name, (long)ip, (long)sp);
+ if (dladdr((void *)ip, &dlinfo))
+ bprintfrr(&fb, " %s (mapped at %p)",
+ dlinfo.dli_fname, dlinfo.dli_fbase);
+ bprintfrr(&fb, "\n");
+ crash_write(&fb, NULL);
}
#elif defined(HAVE_GLIBC_BACKTRACE) || defined(HAVE_PRINTSTACK)
static const char pclabel[] = "Program counter: ";
void *array[64];
int size;
- char buf[100];
- char *s, **bt = NULL;
-#define LOC s,buf+sizeof(buf)-s
+ 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));
@@ -598,7 +490,7 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
write_wrapper(FD, pclabel, sizeof(pclabel) - 1); \
backtrace_symbols_fd(&program_counter, 1, FD); \
} \
- write_wrapper(FD, buf, s - buf); \
+ write_wrapper(FD, fb.buf, fb.pos - fb.buf); \
backtrace_symbols_fd(array, size, FD); \
}
#elif defined(HAVE_PRINTSTACK)
@@ -608,15 +500,12 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
{ \
if (program_counter) \
write_wrapper((FD), pclabel, sizeof(pclabel) - 1); \
- write_wrapper((FD), buf, s - buf); \
+ write_wrapper((FD), fb.buf, fb.pos - fb.buf); \
printstack((FD)); \
}
#endif /* HAVE_GLIBC_BACKTRACE, HAVE_PRINTSTACK */
- s = buf;
- s = str_append(LOC, "Backtrace for ");
- s = num_append(LOC, size);
- s = str_append(LOC, " stack frames:\n");
+ bprintfrr(&fb, "Backtrace for %d stack frames:\n", size);
if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
DUMP(logfile_fd)
@@ -626,12 +515,12 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
if (priority <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
DUMP(STDOUT_FILENO)
/* Remove trailing '\n' for monitor and syslog */
- *--s = '\0';
+ fb.pos--;
if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
- vty_log_fixed(buf, s - buf);
+ vty_log_fixed(fb.buf, fb.pos - fb.buf);
if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
- syslog_sigsafe(priority | zlog_default->facility, buf,
- s - buf);
+ syslog_sigsafe(priority | zlog_default->facility,
+ fb.buf, fb.pos - fb.buf);
{
int i;
#ifdef HAVE_GLIBC_BACKTRACE
@@ -639,34 +528,26 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
#endif
/* Just print the function addresses. */
for (i = 0; i < size; i++) {
- s = buf;
+ fb.pos = buf;
if (bt)
- s = str_append(LOC, bt[i]);
- else {
- s = str_append(LOC, "[bt ");
- s = num_append(LOC, i);
- s = str_append(LOC, "] 0x");
- s = hex_append(
- LOC, (unsigned long)(array[i]));
- }
- *s = '\0';
+ 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(buf, s - buf);
+ vty_log_fixed(fb.buf, fb.pos - fb.buf);
if (priority
<= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
- syslog_sigsafe(
- priority
- | zlog_default
- ->facility,
- buf, s - buf);
+ syslog_sigsafe(priority
+ | zlog_default->facility,
+ fb.buf, fb.pos - fb.buf);
}
if (bt)
free(bt);
}
}
#undef DUMP
-#undef LOC
#endif /* HAVE_STRACK_TRACE */
}