X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Flog.c;h=ba959b914e117ef0d3639dc3bdff35604d74fa9b;hp=2a075ffebab7953c81c905b6811fb719ed80bb44;hb=086891e5c119abb9854237fc32e736fe2d67234c;hpb=b8d0ffc21f9c237cdeef49b1873b47df1a0a1543 diff --git a/src/shared/log.c b/src/shared/log.c index 2a075ffeb..ba959b914 100644 --- a/src/shared/log.c +++ b/src/shared/log.c @@ -51,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; @@ -62,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; } @@ -84,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) { @@ -105,12 +102,7 @@ static int log_open_kmsg(void) { } 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) { @@ -130,7 +122,7 @@ static int create_log_socket(int type) { timeval_store(&tv, 10 * USEC_PER_MSEC); else timeval_store(&tv, 10 * USEC_PER_SEC); - setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); return fd; } @@ -152,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 @@ -180,12 +172,7 @@ fail: } 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) { @@ -282,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; } @@ -308,10 +302,11 @@ 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_name, + const char *object_field, const char *object, const char *buffer) { @@ -362,13 +357,14 @@ static int write_to_console( } static int write_to_syslog( - int level, - const char*file, - int line, - const char *func, - const char *object_name, - const char *object, - 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] = {}; @@ -393,7 +389,7 @@ static int write_to_syslog( 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); IOVEC_SET_STRING(iovec[0], header_priority); @@ -424,13 +420,14 @@ static int write_to_syslog( } static int write_to_kmsg( - int level, - const char*file, - int line, - const char *func, - const char *object_name, - const char *object, - 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] = {}; @@ -441,7 +438,7 @@ 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); IOVEC_SET_STRING(iovec[0], header_priority); @@ -456,45 +453,55 @@ static int write_to_kmsg( return 1; } -static int log_do_header(char *header, size_t size, - int level, - const char *file, int line, const char *func, - const char *object_name, const char *object) { +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, size, "PRIORITY=%i\n" "SYSLOG_FACILITY=%i\n" - "%s%.*s%s" + "%s%s%s" "%s%.*i%s" - "%s%.*s%s" - "%s%.*s%s" + "%s%s%s" + "%s%.*i%s" + "%s%s%s" "SYSLOG_IDENTIFIER=%s\n", LOG_PRI(level), LOG_FAC(level), - file ? "CODE_FILE=" : "", - file ? LINE_MAX : 0, file, /* %.0s means no output */ - file ? "\n" : "", + 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" : "", - func ? "CODE_FUNCTION=" : "", - func ? LINE_MAX : 0, func, - func ? "\n" : "", - object ? object_name : "", - object ? LINE_MAX : 0, object, /* %.0s means no output */ - object ? "\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; } static int write_to_journal( - int level, - const char*file, - int line, - const char *func, - const char *object_name, - const char *object, - 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[LINE_MAX]; struct iovec iovec[4] = {}; @@ -503,8 +510,7 @@ static int write_to_journal( if (journal_fd < 0) return 0; - log_do_header(header, sizeof(header), level, - file, line, func, object_name, object); + log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object); IOVEC_SET_STRING(iovec[0], header); IOVEC_SET_STRING(iovec[1], "MESSAGE="); @@ -521,13 +527,14 @@ static int write_to_journal( } static int log_dispatch( - int level, - const char*file, - int line, - const char *func, - const char *object_name, - const char *object, - 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; @@ -554,8 +561,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, - object_name, object, buffer); + k = write_to_journal(level, error, file, line, func, object_field, object, buffer); if (k < 0) { if (k != -EAGAIN) log_close_journal(); @@ -567,8 +573,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, - object_name, object, buffer); + k = write_to_syslog(level, error, file, line, func, object_field, object, buffer); if (k < 0) { if (k != -EAGAIN) log_close_syslog(); @@ -584,8 +589,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, - object_name, object, buffer); + k = write_to_kmsg(level, error, file, line, func, object_field, object, buffer); if (k < 0) { log_close_kmsg(); log_open_console(); @@ -594,8 +598,7 @@ static int log_dispatch( } if (k <= 0) { - k = write_to_console(level, file, line, func, - object_name, object, buffer); + k = write_to_console(level, error, file, line, func, object_field, object, buffer); if (k < 0) return k; } @@ -608,6 +611,7 @@ static int log_dispatch( int log_dump_internal( int level, + int error, const char*file, int line, const char *func, @@ -620,16 +624,17 @@ int log_dump_internal( if (_likely_(LOG_PRI(level) > log_max_level)) return 0; - return log_dispatch(level, file, line, func, NULL, NULL, buffer); + 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 level, + int error, + const char*file, + int line, + const char *func, + const char *format, + va_list ap) { PROTECT_ERRNO; char buffer[LINE_MAX]; @@ -637,38 +642,44 @@ int log_metav( if (_likely_(LOG_PRI(level) > log_max_level)) return 0; + /* Make sure that %m maps to the specified error */ + if (error != 0) + errno = error; + vsnprintf(buffer, sizeof(buffer), format, ap); char_array_0(buffer); - return log_dispatch(level, file, line, func, NULL, NULL, buffer); + return log_dispatch(level, error, file, line, func, NULL, NULL, buffer); } int log_meta( - int level, - const char*file, - int line, - const char *func, - const char *format, ...) { + 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_metav(level, file, line, func, format, ap); + r = log_metav(level, error, file, line, func, format, ap); va_end(ap); return r; } int log_metav_object( - int level, - const char*file, - int line, - const char *func, - const char *object_name, - const char *object, - const char *format, - va_list ap) { + 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]; @@ -676,49 +687,58 @@ int log_metav_object( if (_likely_(LOG_PRI(level) > log_max_level)) return 0; + /* Make sure that %m maps to the specified error */ + if (error != 0) + errno = error; + vsnprintf(buffer, sizeof(buffer), format, ap); char_array_0(buffer); - return log_dispatch(level, file, line, func, - object_name, object, buffer); + return log_dispatch(level, error, file, line, func, object_field, object, buffer); } int log_meta_object( - int level, - const char*file, - int line, - const char *func, - const char *object_name, - const char *object, - const char *format, ...) { + 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_object(level, file, line, func, - object_name, object, format, ap); + r = log_metav_object(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" -static void log_assert(int level, 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(level, file, line, func, NULL, NULL, buffer); + log_dispatch(level, 0, file, line, func, NULL, NULL, buffer); } -#pragma GCC diagnostic pop 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."); @@ -736,12 +756,13 @@ void log_assert_failed_return(const char *text, const char *file, int line, cons } int log_oom_internal(const char *file, int line, const char *func) { - log_meta(LOG_ERR, file, line, func, "Out of memory."); + log_meta(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, @@ -774,8 +795,7 @@ int log_struct_internal( static const char nl = '\n'; /* If the journal is available do structured logging */ - log_do_header(header, sizeof(header), level, - file, line, func, NULL, NULL); + log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL); IOVEC_SET_STRING(iovec[n++], header); va_start(ap, format); @@ -847,8 +867,7 @@ int log_struct_internal( va_end(ap); if (found) - r = log_dispatch(level, file, line, func, - NULL, NULL, buf + 8); + r = log_dispatch(level, error, file, line, func, NULL, NULL, buf + 8); else r = -EINVAL; } @@ -878,41 +897,62 @@ int log_set_max_level_from_string(const char *e) { return 0; } -void log_parse_environment(void) { - _cleanup_free_ char *line = NULL; - const char *e; - int r; +static int parse_proc_cmdline_item(const char *key, const char *value) { - r = proc_cmdline(&line); - if (r < 0) - log_warning("Failed to read /proc/cmdline. Ignoring: %s", strerror(-r)); - else if (r > 0) { - char *w, *state; - size_t l; + /* + * The systemd.log_xyz= settings are parsed by all tools, and + * so is "debug". + * + * However, "quiet" is only parsed by PID 1! + */ - FOREACH_WORD_QUOTED(w, l, line, state) { - if (l == 5 && startswith(w, "debug")) { - log_set_max_level(LOG_DEBUG); - break; - } - } + 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; + + (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); + log_warning("Failed to parse log target '%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); + log_warning("Failed to parse log level '%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); + 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); + log_warning("Failed to parse bool '%s'. Ignoring.", e); } LogTarget log_get_target(void) { @@ -927,10 +967,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; @@ -960,7 +1008,7 @@ bool log_on_console(void) { return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0; } -static const char *const log_target_table[] = { +static const char *const log_target_table[_LOG_TARGET_MAX] = { [LOG_TARGET_CONSOLE] = "console", [LOG_TARGET_KMSG] = "kmsg", [LOG_TARGET_JOURNAL] = "journal", @@ -973,3 +1021,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; +}