diff options
Diffstat (limited to 'log.c')
-rw-r--r-- | log.c | 341 |
1 files changed, 171 insertions, 170 deletions
@@ -55,6 +55,177 @@ bool log_runtime; /* Daemonised, or ready in foreground */ (timespec_diff_us((x), &log_start) / 1000000LL), \ (timespec_diff_us((x), &log_start) / 100LL) +/* Prefixes for log file messages, indexed by priority */ +const char *logfile_prefix[] = { + NULL, NULL, NULL, /* Unused: LOG_EMERG, LOG_ALERT, LOG_CRIT */ + "ERROR: ", + "WARNING: ", + NULL, /* Unused: LOG_NOTICE */ + "info: ", + " ", /* LOG_DEBUG */ +}; + +#ifdef FALLOC_FL_COLLAPSE_RANGE +/** + * logfile_rotate_fallocate() - Write header, set log_written after fallocate() + * @fd: Log file descriptor + * @now: Current timestamp + * + * #syscalls lseek ppc64le:_llseek ppc64:_llseek arm:_llseek + */ +static void logfile_rotate_fallocate(int fd, const struct timespec *now) +{ + char buf[BUFSIZ]; + const char *nl; + int n; + + if (lseek(fd, 0, SEEK_SET) == -1) + return; + if (read(fd, buf, BUFSIZ) == -1) + return; + + n = snprintf(buf, BUFSIZ, "%s - log truncated at ", log_header); + n += snprintf(buf + n, BUFSIZ - n, logtime_fmt_and_arg(now)); + + /* Avoid partial lines by padding the header with spaces */ + nl = memchr(buf + n + 1, '\n', BUFSIZ - n - 1); + if (nl) + memset(buf + n, ' ', nl - (buf + n)); + + if (lseek(fd, 0, SEEK_SET) == -1) + return; + if (write(fd, buf, BUFSIZ) == -1) + return; + + log_written -= log_cut_size; +} +#endif /* FALLOC_FL_COLLAPSE_RANGE */ + +/** + * logfile_rotate_move() - Fallback: move recent entries toward start, then cut + * @fd: Log file descriptor + * @now: Current timestamp + * + * #syscalls lseek ppc64le:_llseek ppc64:_llseek arm:_llseek + * #syscalls ftruncate + */ +static void logfile_rotate_move(int fd, const struct timespec *now) +{ + int header_len, write_offset, end, discard, n; + char buf[BUFSIZ]; + const char *nl; + + header_len = snprintf(buf, BUFSIZ, "%s - log truncated at ", + log_header); + header_len += snprintf(buf + header_len, BUFSIZ - header_len, + logtime_fmt_and_arg(now)); + + if (lseek(fd, 0, SEEK_SET) == -1) + return; + if (write(fd, buf, header_len) == -1) + return; + + end = write_offset = header_len; + discard = log_cut_size + header_len; + + /* Try to cut cleanly at newline */ + if (lseek(fd, discard, SEEK_SET) == -1) + goto out; + if ((n = read(fd, buf, BUFSIZ)) <= 0) + goto out; + if ((nl = memchr(buf, '\n', n))) + discard += (nl - buf) + 1; + + /* Go to first block to be moved */ + if (lseek(fd, discard, SEEK_SET) == -1) + goto out; + + while ((n = read(fd, buf, BUFSIZ)) > 0) { + end = header_len; + + if (lseek(fd, write_offset, SEEK_SET) == -1) + goto out; + if ((n = write(fd, buf, n)) == -1) + goto out; + write_offset += n; + + if ((n = lseek(fd, 0, SEEK_CUR)) == -1) + goto out; + + if (lseek(fd, discard - header_len, SEEK_CUR) == -1) + goto out; + + end = n; + } + +out: + if (ftruncate(fd, end)) + return; + + log_written = end; +} + +/** + * logfile_rotate() - "Rotate" log file once it's full + * @fd: Log file descriptor + * @now: Current timestamp + * + * Return: 0 on success, negative error code on failure + * + * #syscalls fcntl + * + * fallocate() passed as EXTRA_SYSCALL only if FALLOC_FL_COLLAPSE_RANGE is there + */ +static int logfile_rotate(int fd, const struct timespec *now) +{ + if (fcntl(fd, F_SETFL, O_RDWR /* Drop O_APPEND: explicit lseek() */)) + return -errno; + +#ifdef FALLOC_FL_COLLAPSE_RANGE + /* Only for Linux >= 3.15, extent-based ext4 or XFS, glibc >= 2.18 */ + if (!fallocate(fd, FALLOC_FL_COLLAPSE_RANGE, 0, log_cut_size)) + logfile_rotate_fallocate(fd, now); + else +#endif + logfile_rotate_move(fd, now); + + if (fcntl(fd, F_SETFL, O_RDWR | O_APPEND)) + return -errno; + + return 0; +} + +/** + * logfile_write() - Write entry to log file, trigger rotation if full + * @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 + */ +static void logfile_write(bool newline, int pri, const char *format, va_list ap) +{ + struct timespec now; + char buf[BUFSIZ]; + int n; + + if (clock_gettime(CLOCK_MONOTONIC, &now)) + return; + + n = snprintf(buf, BUFSIZ, logtime_fmt_and_arg(&now)); + n += snprintf(buf + n, BUFSIZ - n, ": %s", logfile_prefix[pri]); + + n += vsnprintf(buf + n, BUFSIZ - n, format, ap); + + if (newline && format[strlen(format)] != '\n') + n += snprintf(buf + n, BUFSIZ - n, "\n"); + + if ((log_written + n >= log_size) && logfile_rotate(log_file, &now)) + return; + + 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 @@ -125,16 +296,6 @@ void logmsg_perror(int pri, const char *format, ...) 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 */ - "ERROR: ", - "WARNING: ", - NULL, /* Unused: LOG_NOTICE */ - "info: ", - " ", /* LOG_DEBUG */ -}; - /** * trace_init() - Set log_trace depending on trace (debug) mode * @enable: Tracing debug mode enabled if non-zero @@ -239,163 +400,3 @@ void logfile_init(const char *name, const char *path, size_t size) 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() - * @fd: Log file descriptor - * @now: Current timestamp - * - * #syscalls lseek ppc64le:_llseek ppc64:_llseek arm:_llseek - */ -static void logfile_rotate_fallocate(int fd, const struct timespec *now) -{ - char buf[BUFSIZ]; - const char *nl; - int n; - - if (lseek(fd, 0, SEEK_SET) == -1) - return; - if (read(fd, buf, BUFSIZ) == -1) - return; - - n = snprintf(buf, BUFSIZ, "%s - log truncated at ", log_header); - n += snprintf(buf + n, BUFSIZ - n, logtime_fmt_and_arg(now)); - - /* Avoid partial lines by padding the header with spaces */ - nl = memchr(buf + n + 1, '\n', BUFSIZ - n - 1); - if (nl) - memset(buf + n, ' ', nl - (buf + n)); - - if (lseek(fd, 0, SEEK_SET) == -1) - return; - if (write(fd, buf, BUFSIZ) == -1) - return; - - log_written -= log_cut_size; -} -#endif /* FALLOC_FL_COLLAPSE_RANGE */ - -/** - * logfile_rotate_move() - Fallback: move recent entries toward start, then cut - * @fd: Log file descriptor - * @now: Current timestamp - * - * #syscalls lseek ppc64le:_llseek ppc64:_llseek arm:_llseek - * #syscalls ftruncate - */ -static void logfile_rotate_move(int fd, const struct timespec *now) -{ - int header_len, write_offset, end, discard, n; - char buf[BUFSIZ]; - const char *nl; - - header_len = snprintf(buf, BUFSIZ, "%s - log truncated at ", - log_header); - header_len += snprintf(buf + header_len, BUFSIZ - header_len, - logtime_fmt_and_arg(now)); - - if (lseek(fd, 0, SEEK_SET) == -1) - return; - if (write(fd, buf, header_len) == -1) - return; - - end = write_offset = header_len; - discard = log_cut_size + header_len; - - /* Try to cut cleanly at newline */ - if (lseek(fd, discard, SEEK_SET) == -1) - goto out; - if ((n = read(fd, buf, BUFSIZ)) <= 0) - goto out; - if ((nl = memchr(buf, '\n', n))) - discard += (nl - buf) + 1; - - /* Go to first block to be moved */ - if (lseek(fd, discard, SEEK_SET) == -1) - goto out; - - while ((n = read(fd, buf, BUFSIZ)) > 0) { - end = header_len; - - if (lseek(fd, write_offset, SEEK_SET) == -1) - goto out; - if ((n = write(fd, buf, n)) == -1) - goto out; - write_offset += n; - - if ((n = lseek(fd, 0, SEEK_CUR)) == -1) - goto out; - - if (lseek(fd, discard - header_len, SEEK_CUR) == -1) - goto out; - - end = n; - } - -out: - if (ftruncate(fd, end)) - return; - - log_written = end; -} - -/** - * logfile_rotate() - "Rotate" log file once it's full - * @fd: Log file descriptor - * @now: Current timestamp - * - * Return: 0 on success, negative error code on failure - * - * #syscalls fcntl - * - * fallocate() passed as EXTRA_SYSCALL only if FALLOC_FL_COLLAPSE_RANGE is there - */ -static int logfile_rotate(int fd, const struct timespec *now) -{ - if (fcntl(fd, F_SETFL, O_RDWR /* Drop O_APPEND: explicit lseek() */)) - return -errno; - -#ifdef FALLOC_FL_COLLAPSE_RANGE - /* Only for Linux >= 3.15, extent-based ext4 or XFS, glibc >= 2.18 */ - if (!fallocate(fd, FALLOC_FL_COLLAPSE_RANGE, 0, log_cut_size)) - logfile_rotate_fallocate(fd, now); - else -#endif - logfile_rotate_move(fd, now); - - if (fcntl(fd, F_SETFL, O_RDWR | O_APPEND)) - return -errno; - - return 0; -} - -/** - * logfile_write() - Write entry to log file, trigger rotation if full - * @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 logfile_write(bool newline, int pri, const char *format, va_list ap) -{ - struct timespec now; - char buf[BUFSIZ]; - int n; - - if (clock_gettime(CLOCK_MONOTONIC, &now)) - return; - - n = snprintf(buf, BUFSIZ, logtime_fmt_and_arg(&now)); - n += snprintf(buf + n, BUFSIZ - n, ": %s", logfile_prefix[pri]); - - n += vsnprintf(buf + n, BUFSIZ - n, format, ap); - - if (newline && format[strlen(format)] != '\n') - n += snprintf(buf + n, BUFSIZ - n, "\n"); - - if ((log_written + n >= log_size) && logfile_rotate(log_file, &now)) - return; - - if ((n = write(log_file, buf, n)) >= 0) - log_written += n; -} |