X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Flog.c;h=eba5853ab0a53ed9ad587b2a5f7c2339472b8eb1;hp=6a10dc4540ed288032f6fefb3ccedaf730d777a3;hb=6357ac664c9ce8ae5b83bdb98011da24185e4efa;hpb=a6903061530cac5fbaa99a080a93221c02c349f9 diff --git a/src/shared/log.c b/src/shared/log.c index 6a10dc454..eba5853ab 100644 --- a/src/shared/log.c +++ b/src/shared/log.c @@ -27,9 +27,11 @@ #include #include #include +#include #include "log.h" #include "util.h" +#include "missing.h" #include "macro.h" #include "socket-util.h" @@ -49,6 +51,8 @@ static bool syslog_is_stream = false; static bool show_color = false; static bool show_location = false; +static bool upgrade_syslog_to_journal = false; + /* Akin to glibc's __abort_msg; which is private and we hence cannot * use here. */ static char *log_abort_msg = NULL; @@ -60,7 +64,7 @@ void log_close_console(void) { if (getpid() == 1) { if (console_fd >= 3) - close_nointr_nofail(console_fd); + safe_close(console_fd); console_fd = -1; } @@ -72,14 +76,9 @@ static int log_open_console(void) { return 0; if (getpid() == 1) { - console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (console_fd < 0) { - log_error("Failed to open /dev/console for logging: %s", strerror(-console_fd)); + if (console_fd < 0) return console_fd; - } - - log_debug("Successfully opened /dev/console for logging."); } else console_fd = STDERR_FILENO; @@ -87,12 +86,7 @@ static int log_open_console(void) { } void log_close_kmsg(void) { - - if (kmsg_fd < 0) - return; - - close_nointr_nofail(kmsg_fd); - kmsg_fd = -1; + kmsg_fd = safe_close(kmsg_fd); } static int log_open_kmsg(void) { @@ -101,51 +95,48 @@ static int log_open_kmsg(void) { return 0; kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (kmsg_fd < 0) { - log_error("Failed to open /dev/kmsg for logging: %s", strerror(errno)); + if (kmsg_fd < 0) return -errno; - } - - log_debug("Successfully opened /dev/kmsg for logging."); return 0; } void log_close_syslog(void) { - - if (syslog_fd < 0) - return; - - close_nointr_nofail(syslog_fd); - syslog_fd = -1; + syslog_fd = safe_close(syslog_fd); } static int create_log_socket(int type) { int fd; + struct timeval tv; - /* All output to the syslog/journal fds we do asynchronously, - * and if the buffers are full we just drop the messages */ - - fd = socket(AF_UNIX, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0); if (fd < 0) return -errno; fd_inc_sndbuf(fd, SNDBUF_SIZE); + /* We need a blocking fd here since we'd otherwise lose + messages way too early. However, let's not hang forever in the + unlikely case of a deadlock. */ + if (getpid() == 1) + timeval_store(&tv, 10 * USEC_PER_MSEC); + else + timeval_store(&tv, 10 * USEC_PER_SEC); + (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + return fd; } static int log_open_syslog(void) { - union sockaddr_union sa; int r; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/dev/log", + }; if (syslog_fd >= 0) return 0; - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path)); - syslog_fd = create_log_socket(SOCK_DGRAM); if (syslog_fd < 0) { r = syslog_fd; @@ -153,7 +144,7 @@ static int log_open_syslog(void) { } if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { - close_nointr_nofail(syslog_fd); + safe_close(syslog_fd); /* Some legacy syslog systems still use stream * sockets. They really shouldn't. But what can we @@ -173,27 +164,22 @@ static int log_open_syslog(void) { } else syslog_is_stream = false; - log_debug("Successfully opened syslog for logging."); - return 0; fail: log_close_syslog(); - log_debug("Failed to open syslog for logging: %s", strerror(-r)); return r; } void log_close_journal(void) { - - if (journal_fd < 0) - return; - - close_nointr_nofail(journal_fd); - journal_fd = -1; + journal_fd = safe_close(journal_fd); } static int log_open_journal(void) { - union sockaddr_union sa; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/socket", + }; int r; if (journal_fd >= 0) @@ -205,22 +191,15 @@ static int log_open_journal(void) { goto fail; } - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path)); - if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { r = -errno; goto fail; } - log_debug("Successfully opened journal for logging."); - return 0; fail: log_close_journal(); - log_debug("Failed to open journal for logging: %s", strerror(-r)); return r; } @@ -283,8 +262,6 @@ int log_open(void) { log_close_journal(); log_close_syslog(); - /* Get the real /dev/console if we are PID=1, hence reopen */ - log_close_console(); return log_open_console(); } @@ -292,6 +269,13 @@ void log_set_target(LogTarget target) { assert(target >= 0); assert(target < _LOG_TARGET_MAX); + if (upgrade_syslog_to_journal) { + if (target == LOG_TARGET_SYSLOG) + target = LOG_TARGET_JOURNAL; + else if (target == LOG_TARGET_SYSLOG_OR_KMSG) + target = LOG_TARGET_JOURNAL_OR_KMSG; + } + log_target = target; } @@ -318,13 +302,16 @@ void log_set_facility(int facility) { static int write_to_console( int level, + int error, const char*file, int line, const char *func, + const char *object_field, + const char *object, const char *buffer) { char location[64]; - struct iovec iovec[5]; + struct iovec iovec[5] = {}; unsigned n = 0; bool highlight; @@ -333,8 +320,6 @@ static int write_to_console( highlight = LOG_PRI(level) <= LOG_ERR && show_color; - zero(iovec); - if (show_location) { snprintf(location, sizeof(location), "(%s:%u) ", file, line); char_array_0(location); @@ -348,22 +333,45 @@ static int write_to_console( IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF); IOVEC_SET_STRING(iovec[n++], "\n"); - if (writev(console_fd, iovec, n) < 0) - return -errno; + if (writev(console_fd, iovec, n) < 0) { + + if (errno == EIO && getpid() == 1) { + + /* If somebody tried to kick us from our + * console tty (via vhangup() or suchlike), + * try to reconnect */ + + log_close_console(); + log_open_console(); + + if (console_fd < 0) + return 0; + + if (writev(console_fd, iovec, n) < 0) + return -errno; + } else + return -errno; + } return 1; } static int write_to_syslog( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { + int level, + int error, + const char*file, + int line, + const char *func, + const char *object_field, + const char *object, + const char *buffer) { - char header_priority[16], header_time[64], header_pid[16]; - struct iovec iovec[5]; - struct msghdr msghdr; + char header_priority[1 + DECIMAL_STR_MAX(int) + 2], header_time[64], header_pid[1 + DECIMAL_STR_MAX(pid_t) + 4]; + struct iovec iovec[5] = {}; + struct msghdr msghdr = { + .msg_iov = iovec, + .msg_iovlen = ELEMENTSOF(iovec), + }; time_t t; struct tm *tm; @@ -374,16 +382,16 @@ static int write_to_syslog( char_array_0(header_priority); t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC); - if (!(tm = localtime(&t))) + tm = localtime(&t); + if (!tm) return -EINVAL; if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) return -EINVAL; - snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid()); + snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid()); char_array_0(header_pid); - zero(iovec); IOVEC_SET_STRING(iovec[0], header_priority); IOVEC_SET_STRING(iovec[1], header_time); IOVEC_SET_STRING(iovec[2], program_invocation_short_name); @@ -394,10 +402,6 @@ static int write_to_syslog( if (syslog_is_stream) iovec[4].iov_len++; - zero(msghdr); - msghdr.msg_iov = iovec; - msghdr.msg_iovlen = ELEMENTSOF(iovec); - for (;;) { ssize_t n; @@ -416,14 +420,17 @@ static int write_to_syslog( } static int write_to_kmsg( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { + int level, + int error, + const char*file, + int line, + const char *func, + const char *object_field, + const char *object, + const char *buffer) { - char header_priority[16], header_pid[16]; - struct iovec iovec[5]; + char header_priority[1 + DECIMAL_STR_MAX(int) + 2], header_pid[1 + DECIMAL_STR_MAX(pid_t) + 4]; + struct iovec iovec[5] = {}; if (kmsg_fd < 0) return 0; @@ -431,10 +438,9 @@ static int write_to_kmsg( snprintf(header_priority, sizeof(header_priority), "<%i>", level); char_array_0(header_priority); - snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid()); + snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid()); char_array_0(header_pid); - zero(iovec); IOVEC_SET_STRING(iovec[0], header_priority); IOVEC_SET_STRING(iovec[1], program_invocation_short_name); IOVEC_SET_STRING(iovec[2], header_pid); @@ -447,43 +453,70 @@ static int write_to_kmsg( return 1; } -static int write_to_journal( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { - - char header[LINE_MAX]; - struct iovec iovec[3]; - struct msghdr mh; - - if (journal_fd < 0) - return 0; +static int log_do_header( + char *header, + size_t size, + int level, + int error, + const char *file, int line, const char *func, + const char *object_field, const char *object) { - snprintf(header, sizeof(header), + snprintf(header, size, "PRIORITY=%i\n" "SYSLOG_FACILITY=%i\n" - "CODE_FILE=%s\n" - "CODE_LINE=%i\n" - "CODE_FUNCTION=%s\n" - "SYSLOG_IDENTIFIER=%s\n" - "MESSAGE=", + "%s%s%s" + "%s%.*i%s" + "%s%s%s" + "%s%.*i%s" + "%s%s%s" + "SYSLOG_IDENTIFIER=%s\n", LOG_PRI(level), LOG_FAC(level), - file, - line, - func, + isempty(file) ? "" : "CODE_FILE=", + isempty(file) ? "" : file, + isempty(file) ? "" : "\n", + line ? "CODE_LINE=" : "", + line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */ + line ? "\n" : "", + isempty(func) ? "" : "CODE_FUNCTION=", + isempty(func) ? "" : func, + isempty(func) ? "" : "\n", + error ? "ERRNO=" : "", + error ? 1 : 0, error, + error ? "\n" : "", + isempty(object) ? "" : object_field, + isempty(object) ? "" : object, + isempty(object) ? "" : "\n", program_invocation_short_name); + header[size - 1] = '\0'; + + return 0; +} - char_array_0(header); +static int write_to_journal( + int level, + int error, + const char*file, + int line, + const char *func, + const char *object_field, + const char *object, + const char *buffer) { + + char header[LINE_MAX]; + struct iovec iovec[4] = {}; + struct msghdr mh = {}; + + if (journal_fd < 0) + return 0; + + log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object); - zero(iovec); IOVEC_SET_STRING(iovec[0], header); - IOVEC_SET_STRING(iovec[1], buffer); - IOVEC_SET_STRING(iovec[2], "\n"); + IOVEC_SET_STRING(iovec[1], "MESSAGE="); + IOVEC_SET_STRING(iovec[2], buffer); + IOVEC_SET_STRING(iovec[3], "\n"); - zero(mh); mh.msg_iov = iovec; mh.msg_iovlen = ELEMENTSOF(iovec); @@ -494,11 +527,14 @@ static int write_to_journal( } static int log_dispatch( - int level, - const char*file, - int line, - const char *func, - char *buffer) { + int level, + int error, + const char*file, + int line, + const char *func, + const char *object_field, + const char *object, + char *buffer) { int r = 0; @@ -509,6 +545,9 @@ static int log_dispatch( if ((level & LOG_FACMASK) == 0) level = log_facility | LOG_PRI(level); + if (error < 0) + error = -error; + do { char *e; int k = 0; @@ -525,7 +564,7 @@ static int log_dispatch( log_target == LOG_TARGET_JOURNAL_OR_KMSG || log_target == LOG_TARGET_JOURNAL) { - k = write_to_journal(level, file, line, func, buffer); + k = write_to_journal(level, error, file, line, func, object_field, object, buffer); if (k < 0) { if (k != -EAGAIN) log_close_journal(); @@ -537,7 +576,7 @@ static int log_dispatch( if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || log_target == LOG_TARGET_SYSLOG) { - k = write_to_syslog(level, file, line, func, buffer); + k = write_to_syslog(level, error, file, line, func, object_field, object, buffer); if (k < 0) { if (k != -EAGAIN) log_close_syslog(); @@ -553,7 +592,7 @@ static int log_dispatch( log_target == LOG_TARGET_JOURNAL_OR_KMSG || log_target == LOG_TARGET_KMSG)) { - k = write_to_kmsg(level, file, line, func, buffer); + k = write_to_kmsg(level, error, file, line, func, object_field, object, buffer); if (k < 0) { log_close_kmsg(); log_open_console(); @@ -562,7 +601,7 @@ static int log_dispatch( } if (k <= 0) { - k = write_to_console(level, file, line, func, buffer); + k = write_to_console(level, error, file, line, func, object_field, object, buffer); if (k < 0) return k; } @@ -575,87 +614,277 @@ static int log_dispatch( int log_dump_internal( int level, + int error, const char*file, int line, const char *func, char *buffer) { - int saved_errno, r; + PROTECT_ERRNO; /* This modifies the buffer... */ if (_likely_(LOG_PRI(level) > log_max_level)) return 0; - saved_errno = errno; - r = log_dispatch(level, file, line, func, buffer); - errno = saved_errno; - - return r; + return log_dispatch(level, error, file, line, func, NULL, NULL, buffer); } -int log_metav( - int level, - const char*file, - int line, - const char *func, - const char *format, - va_list ap) { +int log_internalv( + int level, + int error, + const char*file, + int line, + const char *func, + const char *format, + va_list ap) { + PROTECT_ERRNO; char buffer[LINE_MAX]; - int saved_errno, r; if (_likely_(LOG_PRI(level) > log_max_level)) return 0; - saved_errno = errno; + /* Make sure that %m maps to the specified error */ + if (error != 0) + errno = abs(error); + vsnprintf(buffer, sizeof(buffer), format, ap); char_array_0(buffer); - r = log_dispatch(level, file, line, func, buffer); - errno = saved_errno; + return log_dispatch(level, error, file, line, func, NULL, NULL, buffer); +} + +int log_internal( + int level, + int error, + const char*file, + int line, + const char *func, + const char *format, ...) { + + int r; + va_list ap; + + va_start(ap, format); + r = log_internalv(level, error, file, line, func, format, ap); + va_end(ap); return r; } -int log_meta( - int level, - const char*file, - int line, - const char *func, - const char *format, ...) { +int log_object_internalv( + int level, + int error, + const char*file, + int line, + const char *func, + const char *object_field, + const char *object, + const char *format, + va_list ap) { + + PROTECT_ERRNO; + char buffer[LINE_MAX]; + + if (_likely_(LOG_PRI(level) > log_max_level)) + return 0; + + /* Make sure that %m maps to the specified error */ + if (error != 0) + errno = abs(error); + + vsnprintf(buffer, sizeof(buffer), format, ap); + char_array_0(buffer); + + return log_dispatch(level, error, file, line, func, object_field, object, buffer); +} + +int log_object_internal( + int level, + int error, + const char*file, + int line, + const char *func, + const char *object_field, + const char *object, + const char *format, ...) { int r; va_list ap; va_start(ap, format); - r = log_metav(level, file, line, func, format, ap); + r = log_object_internalv(level, error, file, line, func, object_field, object, format, ap); va_end(ap); return r; } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -_noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) { +static void log_assert( + int level, + const char *text, + const char *file, + int line, + const char *func, + const char *format) { + static char buffer[LINE_MAX]; + if (_likely_(LOG_PRI(level) > log_max_level)) + return; + + DISABLE_WARNING_FORMAT_NONLITERAL; snprintf(buffer, sizeof(buffer), format, text, file, line, func); + REENABLE_WARNING; char_array_0(buffer); log_abort_msg = buffer; - log_dispatch(LOG_CRIT, file, line, func, buffer); + log_dispatch(level, 0, file, line, func, NULL, NULL, buffer); +} + +noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) { + log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting."); + abort(); +} + +noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) { + log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting."); abort(); } -#pragma GCC diagnostic pop -_noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) { - log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting."); +void log_assert_failed_return(const char *text, const char *file, int line, const char *func) { + PROTECT_ERRNO; + log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring."); } -_noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) { - log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting."); +int log_oom_internal(const char *file, int line, const char *func) { + log_internal(LOG_ERR, ENOMEM, file, line, func, "Out of memory."); + return -ENOMEM; +} + +int log_struct_internal( + int level, + int error, + const char *file, + int line, + const char *func, + const char *format, ...) { + + PROTECT_ERRNO; + va_list ap; + int r; + + if (_likely_(LOG_PRI(level) > log_max_level)) + return 0; + + if (log_target == LOG_TARGET_NULL) + return 0; + + if ((level & LOG_FACMASK) == 0) + level = log_facility | LOG_PRI(level); + + if (error < 0) + error = -error; + + if ((log_target == LOG_TARGET_AUTO || + log_target == LOG_TARGET_JOURNAL_OR_KMSG || + log_target == LOG_TARGET_JOURNAL) && + journal_fd >= 0) { + + char header[LINE_MAX]; + struct iovec iovec[17] = {}; + unsigned n = 0, i; + struct msghdr mh = { + .msg_iov = iovec, + }; + static const char nl = '\n'; + + /* If the journal is available do structured logging */ + log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL); + IOVEC_SET_STRING(iovec[n++], header); + + va_start(ap, format); + while (format && n + 1 < ELEMENTSOF(iovec)) { + char *buf; + va_list aq; + + /* We need to copy the va_list structure, + * since vasprintf() leaves it afterwards at + * an undefined location */ + + if (error != 0) + errno = error; + + va_copy(aq, ap); + if (vasprintf(&buf, format, aq) < 0) { + va_end(aq); + r = -ENOMEM; + goto finish; + } + va_end(aq); + + /* Now, jump enough ahead, so that we point to + * the next format string */ + VA_FORMAT_ADVANCE(format, ap); + + IOVEC_SET_STRING(iovec[n++], buf); + + iovec[n].iov_base = (char*) &nl; + iovec[n].iov_len = 1; + n++; + + format = va_arg(ap, char *); + } + + mh.msg_iovlen = n; + + if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0) + r = -errno; + else + r = 1; + + finish: + va_end(ap); + for (i = 1; i < n; i += 2) + free(iovec[i].iov_base); + + } else { + char buf[LINE_MAX]; + bool found = false; + + /* Fallback if journal logging is not available */ + + va_start(ap, format); + while (format) { + va_list aq; + + if (error != 0) + errno = error; + + va_copy(aq, ap); + vsnprintf(buf, sizeof(buf), format, aq); + va_end(aq); + char_array_0(buf); + + if (startswith(buf, "MESSAGE=")) { + found = true; + break; + } + + VA_FORMAT_ADVANCE(format, ap); + + format = va_arg(ap, char *); + } + va_end(ap); + + if (found) + r = log_dispatch(level, error, file, line, func, NULL, NULL, buf + 8); + else + r = -EINVAL; + } + + return r; } int log_set_target_from_string(const char *e) { @@ -680,24 +909,62 @@ int log_set_max_level_from_string(const char *e) { return 0; } +static int parse_proc_cmdline_item(const char *key, const char *value) { + + /* + * The systemd.log_xyz= settings are parsed by all tools, and + * so is "debug". + * + * However, "quiet" is only parsed by PID 1! + */ + + if (streq(key, "debug") && !value) + log_set_max_level(LOG_DEBUG); + + else if (streq(key, "systemd.log_target") && value) { + + if (log_set_target_from_string(value) < 0) + log_warning("Failed to parse log target '%s'. Ignoring.", value); + + } else if (streq(key, "systemd.log_level") && value) { + + if (log_set_max_level_from_string(value) < 0) + log_warning("Failed to parse log level '%s'. Ignoring.", value); + + } else if (streq(key, "systemd.log_color") && value) { + + if (log_show_color_from_string(value) < 0) + log_warning("Failed to parse log color setting '%s'. Ignoring.", value); + + } else if (streq(key, "systemd.log_location") && value) { + + if (log_show_location_from_string(value) < 0) + log_warning("Failed to parse log location setting '%s'. Ignoring.", value); + } + + return 0; +} + void log_parse_environment(void) { const char *e; - if ((e = getenv("SYSTEMD_LOG_TARGET"))) - if (log_set_target_from_string(e) < 0) - log_warning("Failed to parse log target %s. Ignoring.", e); + (void) parse_proc_cmdline(parse_proc_cmdline_item); + + e = secure_getenv("SYSTEMD_LOG_TARGET"); + if (e && log_set_target_from_string(e) < 0) + log_warning("Failed to parse log target '%s'. Ignoring.", e); - if ((e = getenv("SYSTEMD_LOG_LEVEL"))) - if (log_set_max_level_from_string(e) < 0) - log_warning("Failed to parse log level %s. Ignoring.", e); + e = secure_getenv("SYSTEMD_LOG_LEVEL"); + if (e && log_set_max_level_from_string(e) < 0) + log_warning("Failed to parse log level '%s'. Ignoring.", e); - if ((e = getenv("SYSTEMD_LOG_COLOR"))) - if (log_show_color_from_string(e) < 0) - log_warning("Failed to parse bool %s. Ignoring.", e); + e = secure_getenv("SYSTEMD_LOG_COLOR"); + if (e && log_show_color_from_string(e) < 0) + log_warning("Failed to parse bool '%s'. Ignoring.", e); - if ((e = getenv("SYSTEMD_LOG_LOCATION"))) - if (log_show_location_from_string(e) < 0) - log_warning("Failed to parse bool %s. Ignoring.", e); + e = secure_getenv("SYSTEMD_LOG_LOCATION"); + if (e && log_show_location_from_string(e) < 0) + log_warning("Failed to parse bool '%s'. Ignoring.", e); } LogTarget log_get_target(void) { @@ -712,10 +979,18 @@ void log_show_color(bool b) { show_color = b; } +bool log_get_show_color(void) { + return show_color; +} + void log_show_location(bool b) { show_location = b; } +bool log_get_show_location(void) { + return show_location; +} + int log_show_color_from_string(const char *e) { int t; @@ -738,7 +1013,14 @@ int log_show_location_from_string(const char *e) { return 0; } -static const char *const log_target_table[] = { +bool log_on_console(void) { + if (log_target == LOG_TARGET_CONSOLE) + return true; + + return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0; +} + +static const char *const log_target_table[_LOG_TARGET_MAX] = { [LOG_TARGET_CONSOLE] = "console", [LOG_TARGET_KMSG] = "kmsg", [LOG_TARGET_JOURNAL] = "journal", @@ -751,3 +1033,24 @@ static const char *const log_target_table[] = { }; DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget); + +void log_received_signal(int level, const struct signalfd_siginfo *si) { + if (si->ssi_pid > 0) { + _cleanup_free_ char *p = NULL; + + get_process_comm(si->ssi_pid, &p); + + log_full(level, + "Received SIG%s from PID "PID_FMT" (%s).", + signal_to_string(si->ssi_signo), + si->ssi_pid, strna(p)); + } else + log_full(level, + "Received SIG%s.", + signal_to_string(si->ssi_signo)); + +} + +void log_set_upgrade_syslog_to_journal(bool b) { + upgrade_syslog_to_journal = b; +}