X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Flog.c;h=293c261f9e83bbde58a3a17483f787ccf4ffc366;hb=82910f1358c1d15f4e432e6d1f42efdeaf1eddb1;hp=9fffc1dbc00ba2123cae35afbf3d4eb0156865eb;hpb=d7832d2c6e0ef5f2839a2296c1cc2fc85c7d9632;p=elogind.git
diff --git a/src/shared/log.c b/src/shared/log.c
index 9fffc1dbc..293c261f9 100644
--- a/src/shared/log.c
+++ b/src/shared/log.c
@@ -6,16 +6,16 @@
Copyright 2010 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see .
***/
@@ -27,9 +27,11 @@
#include
#include
#include
+#include
#include "log.h"
#include "util.h"
+#include "missing.h"
#include "macro.h"
#include "socket-util.h"
@@ -72,14 +74,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;
@@ -101,12 +98,8 @@ 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;
}
@@ -173,13 +166,10 @@ 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;
}
@@ -214,13 +204,10 @@ static int log_open_journal(void) {
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;
}
@@ -240,7 +227,7 @@ int log_open(void) {
return 0;
}
- if (log_target != LOG_TARGET_AUTO ||
+ if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) ||
getpid() == 1 ||
isatty(STDERR_FILENO) <= 0) {
@@ -266,6 +253,7 @@ int log_open(void) {
}
if (log_target == LOG_TARGET_AUTO ||
+ log_target == LOG_TARGET_SAFE ||
log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
log_target == LOG_TARGET_KMSG) {
@@ -320,6 +308,8 @@ static int write_to_console(
const char*file,
int line,
const char *func,
+ const char *object_name,
+ const char *object,
const char *buffer) {
char location[64];
@@ -358,6 +348,8 @@ static int write_to_syslog(
const char*file,
int line,
const char *func,
+ const char *object_name,
+ const char *object,
const char *buffer) {
char header_priority[16], header_time[64], header_pid[16];
@@ -373,7 +365,8 @@ 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)
@@ -419,6 +412,8 @@ static int write_to_kmsg(
const char*file,
int line,
const char *func,
+ const char *object_name,
+ const char *object,
const char *buffer) {
char header_priority[16], header_pid[16];
@@ -446,41 +441,61 @@ 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) {
+ snprintf(header, size,
+ "PRIORITY=%i\n"
+ "SYSLOG_FACILITY=%i\n"
+ "%s%.*s%s"
+ "%s%.*i%s"
+ "%s%.*s%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" : "",
+ 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" : "",
+ 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) {
char header[LINE_MAX];
- struct iovec iovec[3];
- struct msghdr mh;
+ struct iovec iovec[4] = {{0}};
+ struct msghdr mh = {0};
if (journal_fd < 0)
return 0;
- snprintf(header, sizeof(header),
- "PRIORITY=%i\n"
- "SYSLOG_FACILITY=%i\n"
- "CODE_FILE=%s\n"
- "CODE_LINE=%i\n"
- "CODE_FUNCTION=%s\n"
- "MESSAGE=",
- LOG_PRI(level),
- LOG_FAC(level),
- file,
- line,
- func);
-
- char_array_0(header);
+ log_do_header(header, sizeof(header), level,
+ file, line, func, object_name, 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);
@@ -495,6 +510,8 @@ static int log_dispatch(
const char*file,
int line,
const char *func,
+ const char *object_name,
+ const char *object,
char *buffer) {
int r = 0;
@@ -522,7 +539,8 @@ 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, file, line, func,
+ object_name, object, buffer);
if (k < 0) {
if (k != -EAGAIN)
log_close_journal();
@@ -534,7 +552,8 @@ 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, file, line, func,
+ object_name, object, buffer);
if (k < 0) {
if (k != -EAGAIN)
log_close_syslog();
@@ -545,10 +564,13 @@ static int log_dispatch(
if (k <= 0 &&
(log_target == LOG_TARGET_AUTO ||
+ log_target == LOG_TARGET_SAFE ||
log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
+ 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, file, line, func,
+ object_name, object, buffer);
if (k < 0) {
log_close_kmsg();
log_open_console();
@@ -557,7 +579,8 @@ static int log_dispatch(
}
if (k <= 0) {
- k = write_to_console(level, file, line, func, buffer);
+ k = write_to_console(level, file, line, func,
+ object_name, object, buffer);
if (k < 0)
return k;
}
@@ -583,7 +606,7 @@ int log_dump_internal(
return 0;
saved_errno = errno;
- r = log_dispatch(level, file, line, func, buffer);
+ r = log_dispatch(level, file, line, func, NULL, NULL, buffer);
errno = saved_errno;
return r;
@@ -607,7 +630,7 @@ int log_metav(
vsnprintf(buffer, sizeof(buffer), format, ap);
char_array_0(buffer);
- r = log_dispatch(level, file, line, func, buffer);
+ r = log_dispatch(level, file, line, func, NULL, NULL, buffer);
errno = saved_errno;
return r;
@@ -630,6 +653,53 @@ int log_meta(
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) {
+
+ char buffer[LINE_MAX];
+ int saved_errno, r;
+
+ if (_likely_(LOG_PRI(level) > log_max_level))
+ return 0;
+
+ saved_errno = errno;
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ char_array_0(buffer);
+
+ r = log_dispatch(level, file, line, func,
+ object_name, object, buffer);
+ errno = saved_errno;
+
+ return r;
+}
+
+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 r;
+ va_list ap;
+
+ va_start(ap, format);
+ r = log_metav_object(level, file, line, func,
+ object_name, 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) {
@@ -640,7 +710,7 @@ _noreturn_ static void log_assert(const char *text, const char *file, int line,
char_array_0(buffer);
log_abort_msg = buffer;
- log_dispatch(LOG_CRIT, file, line, func, buffer);
+ log_dispatch(LOG_CRIT, file, line, func, NULL, NULL, buffer);
abort();
}
#pragma GCC diagnostic pop
@@ -653,6 +723,130 @@ _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file
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_meta(LOG_ERR, file, line, func, "Out of memory.");
+ return -ENOMEM;
+}
+
+int log_struct_internal(
+ int level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *format, ...) {
+
+ int saved_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);
+
+ saved_errno = errno;
+
+ 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] = {{0}};
+ unsigned n = 0, i;
+ struct msghdr mh;
+ 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);
+ 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 */
+
+ 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 *);
+ }
+
+ zero(mh);
+ mh.msg_iov = iovec;
+ 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;
+
+ 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, file, line, func,
+ NULL, NULL, buf + 8);
+ else
+ r = -EINVAL;
+ }
+
+ errno = saved_errno;
+ return r;
+}
+
int log_set_target_from_string(const char *e) {
LogTarget t;
@@ -678,21 +872,21 @@ int log_set_max_level_from_string(const char *e) {
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);
+ 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) {
@@ -733,6 +927,13 @@ int log_show_location_from_string(const char *e) {
return 0;
}
+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_CONSOLE] = "console",
[LOG_TARGET_KMSG] = "kmsg",
@@ -741,6 +942,7 @@ static const char *const log_target_table[] = {
[LOG_TARGET_SYSLOG] = "syslog",
[LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
[LOG_TARGET_AUTO] = "auto",
+ [LOG_TARGET_SAFE] = "safe",
[LOG_TARGET_NULL] = "null"
};