diff --git a/log.c b/log.c index 0fb25b7..eb3a780 100644 --- a/log.c +++ b/log.c @@ -55,76 +55,6 @@ bool log_runtime; /* Daemonised, or ready in foreground */ (timespec_diff_us((x), &log_start) / 1000000LL), \ (timespec_diff_us((x), &log_start) / 100LL) -/** - * vlogmsg() - Print or send messages to log or output files as configured - * @newline: Append newline at the end of the message, if missing - * @pri: Facility and level map, same as priority for vsyslog() - * @format: Message - * @ap: Variable argument list - */ -void vlogmsg(bool newline, int pri, const char *format, va_list ap) -{ - bool debug_print = (log_mask & LOG_MASK(LOG_DEBUG)) && log_file == -1; - struct timespec tp; - - if (debug_print) { - clock_gettime(CLOCK_MONOTONIC, &tp); - fprintf(stderr, logtime_fmt_and_arg(&tp)); - fprintf(stderr, ": "); - } - - if ((log_mask & LOG_MASK(LOG_PRI(pri))) || !log_conf_parsed) { - va_list ap2; - - va_copy(ap2, ap); /* Don't clobber ap, we need it again */ - if (log_file != -1) - logfile_write(newline, pri, format, ap2); - else if (!(log_mask & LOG_MASK(LOG_DEBUG))) - passt_vsyslog(newline, pri, format, ap2); - - va_end(ap2); - } - - if (debug_print || !log_conf_parsed || - (!log_runtime && (log_mask & LOG_MASK(LOG_PRI(pri))))) { - (void)vfprintf(stderr, format, ap); - if (newline && format[strlen(format)] != '\n') - fprintf(stderr, "\n"); - } -} - -/** - * logmsg() - vlogmsg() wrapper for variable argument lists - * @newline: Append newline at the end of the message, if missing - * @pri: Facility and level map, same as priority for vsyslog() - * @format: Message - */ -void logmsg(bool newline, int pri, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - vlogmsg(newline, pri, format, ap); - va_end(ap); -} - -/** - * logmsg_perror() - vlogmsg() wrapper with perror()-like functionality - * @pri: Facility and level map, same as priority for vsyslog() - * @format: Message - */ -void logmsg_perror(int pri, const char *format, ...) -{ - int errno_copy = errno; - va_list ap; - - va_start(ap, format); - vlogmsg(false, pri, format, ap); - va_end(ap); - - logmsg(true, pri, ": %s", strerror(errno_copy)); -} - /* Prefixes for log file messages, indexed by priority */ const char *logfile_prefix[] = { NULL, NULL, NULL, /* Unused: LOG_EMERG, LOG_ALERT, LOG_CRIT */ @@ -135,110 +65,6 @@ const char *logfile_prefix[] = { " ", /* LOG_DEBUG */ }; -/** - * trace_init() - Set log_trace depending on trace (debug) mode - * @enable: Tracing debug mode enabled if non-zero - */ -void trace_init(int enable) -{ - log_trace = enable; -} - -/** - * __openlog() - Non-optional openlog() implementation, for custom vsyslog() - * @ident: openlog() identity (program name) - * @option: openlog() options, unused - * @facility: openlog() facility (LOG_DAEMON) - */ -void __openlog(const char *ident, int option, int facility) -{ - (void)option; - - if (log_sock < 0) { - struct sockaddr_un a = { .sun_family = AF_UNIX, }; - - log_sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (log_sock < 0) - return; - - strncpy(a.sun_path, _PATH_LOG, sizeof(a.sun_path)); - if (connect(log_sock, (const struct sockaddr *)&a, sizeof(a))) { - close(log_sock); - log_sock = -1; - return; - } - } - - log_mask |= facility; - strncpy(log_ident, ident, sizeof(log_ident) - 1); -} - -/** - * __setlogmask() - setlogmask() wrapper, to allow custom vsyslog() - * @mask: Same as setlogmask() mask - */ -void __setlogmask(int mask) -{ - log_mask = mask; - setlogmask(mask); -} - -/** - * passt_vsyslog() - vsyslog() implementation not using heap memory - * @newline: Append newline at the end of the message, if missing - * @pri: Facility and level map, same as priority for vsyslog() - * @format: Same as vsyslog() format - * @ap: Same as vsyslog() ap - */ -void passt_vsyslog(bool newline, int pri, const char *format, va_list ap) -{ - char buf[BUFSIZ]; - int n; - - /* Send without timestamp, the system logger should add it */ - n = snprintf(buf, BUFSIZ, "<%i> %s: ", pri, log_ident); - - n += vsnprintf(buf + n, BUFSIZ - n, format, ap); - - if (newline && format[strlen(format)] != '\n') - n += snprintf(buf + n, BUFSIZ - n, "\n"); - - if (log_sock >= 0 && send(log_sock, buf, n, 0) != n && !log_runtime) - fprintf(stderr, "Failed to send %i bytes to syslog\n", n); -} - -/** - * logfile_init() - Open log file and write header with PID, version, path - * @name: Identifier for header: passt or pasta - * @path: Path to log file - * @size: Maximum size of log file: log_cut_size is calculatd here - */ -void logfile_init(const char *name, const char *path, size_t size) -{ - char nl = '\n', exe[PATH_MAX] = { 0 }; - int n; - - if (readlink("/proc/self/exe", exe, PATH_MAX - 1) < 0) - die_perror("Failed to read own /proc/self/exe link"); - - log_file = open(path, O_CREAT | O_TRUNC | O_APPEND | O_RDWR | O_CLOEXEC, - S_IRUSR | S_IWUSR); - if (log_file == -1) - die_perror("Couldn't open log file %s", path); - - log_size = size ? size : LOGFILE_SIZE_DEFAULT; - - n = snprintf(log_header, sizeof(log_header), "%s " VERSION ": %s (%i)", - name, exe, getpid()); - - if (write(log_file, log_header, n) <= 0 || - write(log_file, &nl, 1) <= 0) - die_perror("Couldn't write to log file"); - - /* For FALLOC_FL_COLLAPSE_RANGE: VFS block size can be up to one page */ - log_cut_size = ROUND_UP(log_size * LOGFILE_CUT_RATIO / 100, PAGE_SIZE); -} - #ifdef FALLOC_FL_COLLAPSE_RANGE /** * logfile_rotate_fallocate() - Write header, set log_written after fallocate() @@ -376,7 +202,7 @@ static int logfile_rotate(int fd, const struct timespec *now) * @format: Same as vsyslog() format * @ap: Same as vsyslog() ap */ -void logfile_write(bool newline, int pri, const char *format, va_list ap) +static void logfile_write(bool newline, int pri, const char *format, va_list ap) { struct timespec now; char buf[BUFSIZ]; @@ -399,3 +225,178 @@ void logfile_write(bool newline, int pri, const char *format, va_list ap) if ((n = write(log_file, buf, n)) >= 0) log_written += n; } + +/** + * vlogmsg() - Print or send messages to log or output files as configured + * @newline: Append newline at the end of the message, if missing + * @pri: Facility and level map, same as priority for vsyslog() + * @format: Message + * @ap: Variable argument list + */ +void vlogmsg(bool newline, int pri, const char *format, va_list ap) +{ + bool debug_print = (log_mask & LOG_MASK(LOG_DEBUG)) && log_file == -1; + struct timespec tp; + + if (debug_print) { + clock_gettime(CLOCK_MONOTONIC, &tp); + fprintf(stderr, logtime_fmt_and_arg(&tp)); + fprintf(stderr, ": "); + } + + if ((log_mask & LOG_MASK(LOG_PRI(pri))) || !log_conf_parsed) { + va_list ap2; + + va_copy(ap2, ap); /* Don't clobber ap, we need it again */ + if (log_file != -1) + logfile_write(newline, pri, format, ap2); + else if (!(log_mask & LOG_MASK(LOG_DEBUG))) + passt_vsyslog(newline, pri, format, ap2); + + va_end(ap2); + } + + if (debug_print || !log_conf_parsed || + (!log_runtime && (log_mask & LOG_MASK(LOG_PRI(pri))))) { + (void)vfprintf(stderr, format, ap); + if (newline && format[strlen(format)] != '\n') + fprintf(stderr, "\n"); + } +} + +/** + * logmsg() - vlogmsg() wrapper for variable argument lists + * @newline: Append newline at the end of the message, if missing + * @pri: Facility and level map, same as priority for vsyslog() + * @format: Message + */ +void logmsg(bool newline, int pri, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vlogmsg(newline, pri, format, ap); + va_end(ap); +} + +/** + * logmsg_perror() - vlogmsg() wrapper with perror()-like functionality + * @pri: Facility and level map, same as priority for vsyslog() + * @format: Message + */ +void logmsg_perror(int pri, const char *format, ...) +{ + int errno_copy = errno; + va_list ap; + + va_start(ap, format); + vlogmsg(false, pri, format, ap); + va_end(ap); + + logmsg(true, pri, ": %s", strerror(errno_copy)); +} + +/** + * trace_init() - Set log_trace depending on trace (debug) mode + * @enable: Tracing debug mode enabled if non-zero + */ +void trace_init(int enable) +{ + log_trace = enable; +} + +/** + * __openlog() - Non-optional openlog() implementation, for custom vsyslog() + * @ident: openlog() identity (program name) + * @option: openlog() options, unused + * @facility: openlog() facility (LOG_DAEMON) + */ +void __openlog(const char *ident, int option, int facility) +{ + (void)option; + + if (log_sock < 0) { + struct sockaddr_un a = { .sun_family = AF_UNIX, }; + + log_sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (log_sock < 0) + return; + + strncpy(a.sun_path, _PATH_LOG, sizeof(a.sun_path)); + if (connect(log_sock, (const struct sockaddr *)&a, sizeof(a))) { + close(log_sock); + log_sock = -1; + return; + } + } + + log_mask |= facility; + strncpy(log_ident, ident, sizeof(log_ident) - 1); +} + +/** + * __setlogmask() - setlogmask() wrapper, to allow custom vsyslog() + * @mask: Same as setlogmask() mask + */ +void __setlogmask(int mask) +{ + log_mask = mask; + setlogmask(mask); +} + +/** + * passt_vsyslog() - vsyslog() implementation not using heap memory + * @newline: Append newline at the end of the message, if missing + * @pri: Facility and level map, same as priority for vsyslog() + * @format: Same as vsyslog() format + * @ap: Same as vsyslog() ap + */ +void passt_vsyslog(bool newline, int pri, const char *format, va_list ap) +{ + char buf[BUFSIZ]; + int n; + + /* Send without timestamp, the system logger should add it */ + n = snprintf(buf, BUFSIZ, "<%i> %s: ", pri, log_ident); + + n += vsnprintf(buf + n, BUFSIZ - n, format, ap); + + if (newline && format[strlen(format)] != '\n') + n += snprintf(buf + n, BUFSIZ - n, "\n"); + + if (log_sock >= 0 && send(log_sock, buf, n, 0) != n && !log_runtime) + fprintf(stderr, "Failed to send %i bytes to syslog\n", n); +} + +/** + * logfile_init() - Open log file and write header with PID, version, path + * @name: Identifier for header: passt or pasta + * @path: Path to log file + * @size: Maximum size of log file: log_cut_size is calculatd here + */ +void logfile_init(const char *name, const char *path, size_t size) +{ + char nl = '\n', exe[PATH_MAX] = { 0 }; + int n; + + if (readlink("/proc/self/exe", exe, PATH_MAX - 1) < 0) + die_perror("Failed to read own /proc/self/exe link"); + + log_file = open(path, O_CREAT | O_TRUNC | O_APPEND | O_RDWR | O_CLOEXEC, + S_IRUSR | S_IWUSR); + if (log_file == -1) + die_perror("Couldn't open log file %s", path); + + log_size = size ? size : LOGFILE_SIZE_DEFAULT; + + n = snprintf(log_header, sizeof(log_header), "%s " VERSION ": %s (%i)", + name, exe, getpid()); + + if (write(log_file, log_header, n) <= 0 || + write(log_file, &nl, 1) <= 0) + die_perror("Couldn't write to log file"); + + /* For FALLOC_FL_COLLAPSE_RANGE: VFS block size can be up to one page */ + log_cut_size = ROUND_UP(log_size * LOGFILE_CUT_RATIO / 100, PAGE_SIZE); +} + diff --git a/log.h b/log.h index e03199c..5cb16d6 100644 --- a/log.h +++ b/log.h @@ -56,7 +56,6 @@ void trace_init(int enable); void __openlog(const char *ident, int option, int facility); void logfile_init(const char *name, const char *path, size_t size); void passt_vsyslog(bool newline, int pri, const char *format, va_list ap); -void logfile_write(bool newline, int pri, const char *format, va_list ap); void __setlogmask(int mask); #endif /* LOG_H */