#include <sys/socket.h>
#include <sys/un.h>
#include <stddef.h>
+#include <printf.h>
#include "log.h"
#include "util.h"
+#include "missing.h"
#include "macro.h"
#include "socket-util.h"
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;
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;
}
} 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;
}
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;
}
const char*file,
int line,
const char *func,
+ const char *object_name,
+ const char *object,
const char *buffer) {
char location[64];
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];
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)
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];
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"
- "SYSLOG_IDENTIFIER=%s\n"
- "MESSAGE=",
- LOG_PRI(level),
- LOG_FAC(level),
- file,
- line,
- func,
- program_invocation_short_name);
+ log_do_header(header, sizeof(header), level,
+ file, line, func, object_name, object);
- char_array_0(header);
-
- 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);
const char*file,
int line,
const char *func,
+ const char *object_name,
+ const char *object,
char *buffer) {
int r = 0;
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();
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();
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();
}
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;
}
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;
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;
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) {
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
journal_fd >= 0) {
char header[LINE_MAX];
- struct iovec iovec[17];
+ struct iovec iovec[17] = {{0}};
unsigned n = 0, i;
struct msghdr mh;
- const char nl = '\n';
+ static const char nl = '\n';
/* If the journal is available do structured logging */
-
- snprintf(header, sizeof(header),
- "PRIORITY=%i\n"
- "SYSLOG_FACILITY=%i\n"
- "CODE_FILE=%s\n"
- "CODE_LINE=%i\n"
- "CODE_FUNCTION=%s\n"
- "SYSLOG_IDENTIFIER=%s\n",
- LOG_PRI(level),
- LOG_FAC(level),
- file,
- line,
- func,
- program_invocation_short_name);
- char_array_0(header);
-
- zero(iovec);
+ 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 */
- if (vasprintf(&buf, format, ap) < 0) {
+ 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);
format = va_arg(ap, char *);
}
- va_end(ap);
zero(mh);
mh.msg_iov = iovec;
r = 1;
finish:
+ va_end(ap);
for (i = 1; i < n; i += 2)
free(iovec[i].iov_base);
va_start(ap, format);
while (format) {
+ va_list aq;
- vsnprintf(buf, sizeof(buf), format, ap);
+ va_copy(aq, ap);
+ vsnprintf(buf, sizeof(buf), format, aq);
+ va_end(aq);
char_array_0(buf);
if (startswith(buf, "MESSAGE=")) {
break;
}
+ VA_FORMAT_ADVANCE(format, ap);
+
format = va_arg(ap, char *);
}
va_end(ap);
if (found)
- r = log_dispatch(level, file, line, func, buf + 8);
+ r = log_dispatch(level, file, line, func,
+ NULL, NULL, buf + 8);
else
r = -EINVAL;
}
void log_parse_environment(void) {
const char *e;
- e = __secure_getenv("SYSTEMD_LOG_TARGET");
+ 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);
- e = __secure_getenv("SYSTEMD_LOG_LEVEL");
+ 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);
- e = __secure_getenv("SYSTEMD_LOG_COLOR");
+ e = secure_getenv("SYSTEMD_LOG_COLOR");
if (e && log_show_color_from_string(e) < 0)
log_warning("Failed to parse bool %s. Ignoring.", e);
- e = __secure_getenv("SYSTEMD_LOG_LOCATION");
+ e = secure_getenv("SYSTEMD_LOG_LOCATION");
if (e && log_show_location_from_string(e) < 0)
log_warning("Failed to parse bool %s. Ignoring.", e);
}