Systemd/src/basic/log.c

1493 lines
46 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <sys/signalfd.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <unistd.h>
2010-01-20 19:18:52 +01:00
#include "sd-messages.h"
#include "alloc-util.h"
2019-03-14 12:24:39 +01:00
#include "errno-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "io-util.h"
#include "log.h"
#include "macro.h"
#include "missing_syscall.h"
#include "parse-util.h"
#include "proc-cmdline.h"
2015-04-10 19:10:00 +02:00
#include "process-util.h"
#include "ratelimit.h"
#include "signal-util.h"
#include "socket-util.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
#include "syslog-util.h"
#include "terminal-util.h"
#include "time-util.h"
#include "utf8.h"
2010-01-20 19:18:52 +01:00
#define SNDBUF_SIZE (8*1024*1024)
static LogTarget log_target = LOG_TARGET_CONSOLE;
static int log_max_level[] = {LOG_INFO, LOG_INFO};
assert_cc(ELEMENTSOF(log_max_level) == _LOG_REALM_MAX);
2012-04-03 19:25:29 +02:00
static int log_facility = LOG_DAEMON;
static int console_fd = STDERR_FILENO;
static int syslog_fd = -1;
static int kmsg_fd = -1;
static int journal_fd = -1;
static bool syslog_is_stream = false;
static int show_color = -1; /* tristate */
static bool show_location = false;
static bool show_time = false;
static bool show_tid = false;
static bool upgrade_syslog_to_journal = false;
static bool always_reopen_console = false;
static bool open_when_needed = false;
static bool prohibit_ipc = false;
/* Akin to glibc's __abort_msg; which is private and we hence cannot
* use here. */
static char *log_abort_msg = NULL;
/* An assert to use in logging functions that does not call recursively
* into our logging functions (since that might lead to a loop). */
#define assert_raw(expr) \
do { \
if (_unlikely_(!(expr))) { \
fputs(#expr "\n", stderr); \
abort(); \
} \
} while (false)
static void log_close_console(void) {
console_fd = safe_close_above_stdio(console_fd);
}
static int log_open_console(void) {
if (!always_reopen_console) {
console_fd = STDERR_FILENO;
return 0;
}
if (console_fd < 3) {
int fd;
fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return fd;
console_fd = fd_move_above_stdio(fd);
}
return 0;
}
static void log_close_kmsg(void) {
kmsg_fd = safe_close(kmsg_fd);
}
static int log_open_kmsg(void) {
if (kmsg_fd >= 0)
return 0;
2012-01-05 03:25:10 +01:00
kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
if (kmsg_fd < 0)
return -errno;
kmsg_fd = fd_move_above_stdio(kmsg_fd);
return 0;
}
static void log_close_syslog(void) {
syslog_fd = safe_close(syslog_fd);
}
static int create_log_socket(int type) {
struct timeval tv;
int fd;
fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
fd = fd_move_above_stdio(fd);
(void) 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_cached() == 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) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/dev/log",
};
int r;
if (syslog_fd >= 0)
return 0;
syslog_fd = create_log_socket(SOCK_DGRAM);
if (syslog_fd < 0) {
r = syslog_fd;
goto fail;
}
if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
safe_close(syslog_fd);
/* Some legacy syslog systems still use stream
* sockets. They really shouldn't. But what can we
* do... */
syslog_fd = create_log_socket(SOCK_STREAM);
if (syslog_fd < 0) {
r = syslog_fd;
goto fail;
}
if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = -errno;
goto fail;
}
syslog_is_stream = true;
} else
syslog_is_stream = false;
return 0;
fail:
log_close_syslog();
return r;
}
static void log_close_journal(void) {
journal_fd = safe_close(journal_fd);
}
static int log_open_journal(void) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/socket",
};
int r;
if (journal_fd >= 0)
return 0;
journal_fd = create_log_socket(SOCK_DGRAM);
if (journal_fd < 0) {
r = journal_fd;
goto fail;
}
if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = -errno;
goto fail;
}
return 0;
fail:
log_close_journal();
return r;
}
static bool stderr_is_journal(void) {
_cleanup_free_ char *w = NULL;
const char *e;
uint64_t dev, ino;
struct stat st;
e = getenv("JOURNAL_STREAM");
if (!e)
return false;
if (extract_first_word(&e, &w, ":", EXTRACT_DONT_COALESCE_SEPARATORS) <= 0)
return false;
if (!e)
return false;
if (safe_atou64(w, &dev) < 0)
return false;
if (safe_atou64(e, &ino) < 0)
return false;
if (fstat(STDERR_FILENO, &st) < 0)
return false;
return st.st_dev == dev && st.st_ino == ino;
}
int log_open(void) {
int r;
/* Do not call from library code. */
/* If we don't use the console we close it here, to not get
* killed by SAK. If we don't use syslog we close it here so
* that we are not confused by somebody deleting the socket in
* the fs, and to make sure we don't use it if prohibit_ipc is
* set. If we don't use /dev/kmsg we still keep it open,
* because there is no reason to close it. */
2010-06-09 15:37:37 +02:00
if (log_target == LOG_TARGET_NULL) {
log_close_journal();
2010-06-09 15:37:37 +02:00
log_close_syslog();
log_close_console();
return 0;
}
if (getpid_cached() == 1 ||
stderr_is_journal() ||
IN_SET(log_target,
LOG_TARGET_KMSG,
LOG_TARGET_JOURNAL,
LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_SYSLOG,
LOG_TARGET_SYSLOG_OR_KMSG)) {
if (!prohibit_ipc) {
if (IN_SET(log_target,
LOG_TARGET_AUTO,
LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_JOURNAL)) {
r = log_open_journal();
if (r >= 0) {
log_close_syslog();
log_close_console();
return r;
}
2010-11-12 01:01:04 +01:00
}
if (IN_SET(log_target,
LOG_TARGET_SYSLOG_OR_KMSG,
LOG_TARGET_SYSLOG)) {
r = log_open_syslog();
if (r >= 0) {
log_close_journal();
log_close_console();
return r;
}
}
}
2016-12-18 01:55:43 +01:00
if (IN_SET(log_target, LOG_TARGET_AUTO,
LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_SYSLOG_OR_KMSG,
LOG_TARGET_KMSG)) {
r = log_open_kmsg();
if (r >= 0) {
log_close_journal();
2010-11-12 01:01:04 +01:00
log_close_syslog();
log_close_console();
return r;
}
}
2010-11-12 01:01:04 +01:00
}
log_close_journal();
log_close_syslog();
return log_open_console();
}
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;
}
void log_close(void) {
/* Do not call from library code. */
log_close_journal();
log_close_syslog();
log_close_kmsg();
log_close_console();
}
void log_forget_fds(void) {
/* Do not call from library code. */
console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
}
void log_set_max_level_realm(LogRealm realm, int level) {
assert((level & LOG_PRIMASK) == level);
assert(realm < ELEMENTSOF(log_max_level));
log_max_level[realm] = level;
}
2012-04-03 19:25:29 +02:00
void log_set_facility(int facility) {
log_facility = facility;
}
static int write_to_console(
int level,
int error,
const char *file,
int line,
const char *func,
const char *buffer) {
2010-01-20 19:18:52 +01:00
char location[256],
header_time[FORMAT_TIMESTAMP_MAX],
prefix[1 + DECIMAL_STR_MAX(int) + 2],
tid_string[3 + DECIMAL_STR_MAX(pid_t) + 1];
struct iovec iovec[9];
const char *on = NULL, *off = NULL;
size_t n = 0;
2010-01-20 19:18:52 +01:00
if (console_fd < 0)
return 0;
if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
xsprintf(prefix, "<%i>", level);
iovec[n++] = IOVEC_MAKE_STRING(prefix);
}
if (show_time &&
format_timestamp(header_time, sizeof(header_time), now(CLOCK_REALTIME))) {
iovec[n++] = IOVEC_MAKE_STRING(header_time);
iovec[n++] = IOVEC_MAKE_STRING(" ");
}
if (show_tid) {
xsprintf(tid_string, "(" PID_FMT ") ", gettid());
iovec[n++] = IOVEC_MAKE_STRING(tid_string);
}
if (log_get_show_color())
get_log_colors(LOG_PRI(level), &on, &off, NULL);
2012-01-05 03:25:10 +01:00
if (show_location) {
const char *lon = "", *loff = "";
if (log_get_show_color()) {
lon = ANSI_HIGHLIGHT_YELLOW4;
loff = ANSI_NORMAL;
}
(void) snprintf(location, sizeof location, "%s%s:%i%s: ", lon, file, line, loff);
iovec[n++] = IOVEC_MAKE_STRING(location);
2012-01-05 03:25:10 +01:00
}
if (on)
iovec[n++] = IOVEC_MAKE_STRING(on);
iovec[n++] = IOVEC_MAKE_STRING(buffer);
if (off)
iovec[n++] = IOVEC_MAKE_STRING(off);
iovec[n++] = IOVEC_MAKE_STRING("\n");
if (writev(console_fd, iovec, n) < 0) {
if (errno == EIO && getpid_cached() == 1) {
/* If somebody tried to kick us from our console tty (via vhangup() or suchlike), try
* to reconnect. */
log_close_console();
(void) log_open_console();
if (console_fd < 0)
return 0;
if (writev(console_fd, iovec, n) < 0)
return -errno;
} else
return -errno;
}
2010-01-20 19:18:52 +01:00
return 1;
}
2010-01-20 19:18:52 +01:00
static int write_to_syslog(
int level,
int error,
const char *file,
int line,
const char *func,
const char *buffer) {
char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
header_time[64],
header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
struct iovec iovec[5] = {};
struct msghdr msghdr = {
.msg_iov = iovec,
.msg_iovlen = ELEMENTSOF(iovec),
};
time_t t;
struct tm tm;
if (syslog_fd < 0)
return 0;
xsprintf(header_priority, "<%i>", level);
t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
if (!localtime_r(&t, &tm))
return -EINVAL;
if (strftime(header_time, sizeof(header_time), "%h %e %T ", &tm) <= 0)
return -EINVAL;
xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
iovec[0] = IOVEC_MAKE_STRING(header_priority);
iovec[1] = IOVEC_MAKE_STRING(header_time);
iovec[2] = IOVEC_MAKE_STRING(program_invocation_short_name);
iovec[3] = IOVEC_MAKE_STRING(header_pid);
iovec[4] = IOVEC_MAKE_STRING(buffer);
2010-09-29 15:13:04 +02:00
/* When using syslog via SOCK_STREAM separate the messages by NUL chars */
if (syslog_is_stream)
iovec[4].iov_len++;
for (;;) {
ssize_t n;
n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
if (n < 0)
return -errno;
if (!syslog_is_stream ||
(size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
break;
IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
}
return 1;
}
static int write_to_kmsg(
int level,
int error,
2015-11-05 13:44:03 +01:00
const char *file,
int line,
const char *func,
const char *buffer) {
/* Set a ratelimit on the amount of messages logged to /dev/kmsg. This is mostly supposed to be a
* safety catch for the case where start indiscriminately logging in a loop. It will not catch cases
* where we log excessively, but not in a tight loop.
*
* Note that this ratelimit is per-emitter, so we might still overwhelm /dev/kmsg with multiple
* loggers.
*/
static thread_local RateLimit ratelimit = { 5 * USEC_PER_SEC, 200 };
char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
struct iovec iovec[5] = {};
if (kmsg_fd < 0)
return 0;
if (!ratelimit_below(&ratelimit))
return 0;
xsprintf(header_priority, "<%i>", level);
xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
iovec[0] = IOVEC_MAKE_STRING(header_priority);
iovec[1] = IOVEC_MAKE_STRING(program_invocation_short_name);
iovec[2] = IOVEC_MAKE_STRING(header_pid);
iovec[3] = IOVEC_MAKE_STRING(buffer);
iovec[4] = IOVEC_MAKE_STRING("\n");
if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
return -errno;
return 1;
}
static int log_do_header(
char *header,
size_t size,
int level,
int error,
const char *file, int line, const char *func,
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
const char *object_field, const char *object,
const char *extra_field, const char *extra) {
int r;
error = IS_SYNTHETIC_ERRNO(error) ? 0 : ERRNO_VALUE(error);
r = snprintf(header, size,
"PRIORITY=%i\n"
"SYSLOG_FACILITY=%i\n"
"TID=" PID_FMT "\n"
"%s%.256s%s" /* CODE_FILE */
"%s%.*i%s" /* CODE_LINE */
"%s%.256s%s" /* CODE_FUNC */
"%s%.*i%s" /* ERRNO */
"%s%.256s%s" /* object */
"%s%.256s%s" /* extra */
"SYSLOG_IDENTIFIER=%.256s\n",
LOG_PRI(level),
LOG_FAC(level),
gettid(),
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_FUNC=",
isempty(func) ? "" : func,
isempty(func) ? "" : "\n",
error ? "ERRNO=" : "",
error ? 1 : 0, error,
error ? "\n" : "",
isempty(object) ? "" : object_field,
isempty(object) ? "" : object,
isempty(object) ? "" : "\n",
isempty(extra) ? "" : extra_field,
isempty(extra) ? "" : extra,
isempty(extra) ? "" : "\n",
program_invocation_short_name);
assert_raw((size_t) r < size);
return 0;
}
static int write_to_journal(
int level,
int error,
2015-11-05 13:44:03 +01:00
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
const char *extra_field,
const char *extra,
const char *buffer) {
char header[LINE_MAX];
struct iovec iovec[4] = {};
struct msghdr mh = {};
if (journal_fd < 0)
return 0;
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
iovec[0] = IOVEC_MAKE_STRING(header);
iovec[1] = IOVEC_MAKE_STRING("MESSAGE=");
iovec[2] = IOVEC_MAKE_STRING(buffer);
iovec[3] = IOVEC_MAKE_STRING("\n");
mh.msg_iov = iovec;
mh.msg_iovlen = ELEMENTSOF(iovec);
if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
return -errno;
return 1;
}
int log_dispatch_internal(
int level,
int error,
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
const char *extra_field,
const char *extra,
char *buffer) {
assert_raw(buffer);
2010-06-09 15:37:37 +02:00
if (log_target == LOG_TARGET_NULL)
return -ERRNO_VALUE(error);
2010-06-09 15:37:37 +02:00
/* Patch in LOG_DAEMON facility if necessary */
2011-03-31 21:22:44 +02:00
if ((level & LOG_FACMASK) == 0)
level |= log_facility;
if (open_when_needed)
(void) log_open();
do {
char *e;
2010-08-17 03:31:45 +02:00
int k = 0;
buffer += strspn(buffer, NEWLINE);
if (buffer[0] == 0)
break;
if ((e = strpbrk(buffer, NEWLINE)))
*(e++) = 0;
2016-12-18 01:55:43 +01:00
if (IN_SET(log_target, LOG_TARGET_AUTO,
LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_JOURNAL)) {
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
if (k < 0 && k != -EAGAIN)
log_close_journal();
}
2016-12-18 01:55:43 +01:00
if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
LOG_TARGET_SYSLOG)) {
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
k = write_to_syslog(level, error, file, line, func, buffer);
if (k < 0 && k != -EAGAIN)
log_close_syslog();
}
2010-08-17 03:31:45 +02:00
if (k <= 0 &&
2016-12-18 01:55:43 +01:00
IN_SET(log_target, LOG_TARGET_AUTO,
LOG_TARGET_SYSLOG_OR_KMSG,
LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_KMSG)) {
if (k < 0)
log_open_kmsg();
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
k = write_to_kmsg(level, error, file, line, func, buffer);
if (k < 0) {
log_close_kmsg();
(void) log_open_console();
}
}
if (k <= 0)
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
(void) write_to_console(level, error, file, line, func, buffer);
buffer = e;
} while (buffer);
if (open_when_needed)
log_close();
return -ERRNO_VALUE(error);
}
int log_dump_internal(
int level,
int error,
const char *file,
int line,
const char *func,
char *buffer) {
LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
PROTECT_ERRNO;
/* This modifies the buffer... */
if (_likely_(LOG_PRI(level) > log_max_level[realm]))
return -ERRNO_VALUE(error);
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
}
int log_internalv_realm(
int level,
int error,
2015-11-05 13:44:03 +01:00
const char *file,
int line,
const char *func,
const char *format,
va_list ap) {
LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
char buffer[LINE_MAX];
PROTECT_ERRNO;
if (_likely_(LOG_PRI(level) > log_max_level[realm]))
return -ERRNO_VALUE(error);
/* Make sure that %m maps to the specified error (or "Success"). */
errno = ERRNO_VALUE(error);
(void) vsnprintf(buffer, sizeof buffer, format, ap);
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
}
int log_internal_realm(
int level,
int error,
2015-11-05 13:44:03 +01:00
const char *file,
int line,
const char *func,
const char *format, ...) {
2012-03-14 14:54:41 +01:00
va_list ap;
int r;
2012-03-14 14:54:41 +01:00
va_start(ap, format);
r = log_internalv_realm(level, error, file, line, func, format, ap);
2012-03-14 14:54:41 +01:00
va_end(ap);
return r;
}
2019-03-08 06:21:15 +01:00
int log_object_internalv(
int level,
int error,
2015-11-05 13:44:03 +01:00
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
const char *extra_field,
const char *extra,
const char *format,
va_list ap) {
PROTECT_ERRNO;
core,network: major per-object logging rework This changes log_unit_info() (and friends) to take a real Unit* object insted of just a unit name as parameter. The call will now prefix all logged messages with the unit name, thus allowing the unit name to be dropped from the various passed romat strings, simplifying invocations drastically, and unifying log output across messages. Also, UNIT= vs. USER_UNIT= is now derived from the Manager object attached to the Unit object, instead of getpid(). This has the benefit of correcting the field for --test runs. Also contains a couple of other logging improvements: - Drops a couple of strerror() invocations in favour of using %m. - Not only .mount units now warn if a symlinks exist for the mount point already, .automount units do that too, now. - A few invocations of log_struct() that didn't actually pass any additional structured data have been replaced by simpler invocations of log_unit_info() and friends. - For structured data a new LOG_UNIT_MESSAGE() macro has been added, that works like LOG_MESSAGE() but prefixes the message with the unit name. Similar, there's now LOG_LINK_MESSAGE() and LOG_NETDEV_MESSAGE(). - For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(), LOG_NETDEV_INTERFACE() macros have been added that generate the necessary per object fields. The old log_unit_struct() call has been removed in favour of these new macros used in raw log_struct() invocations. In addition to removing one more function call this allows generated structured log messages that contain two object fields, as necessary for example for network interfaces that are joined into another network interface, and whose messages shall be indexed by both. - The LOG_ERRNO() macro has been removed, in favour of log_struct_errno(). The latter has the benefit of ensuring that %m in format strings is properly resolved to the specified error number. - A number of logging messages have been converted to use log_unit_info() instead of log_info() - The client code in sysv-generator no longer #includes core code from src/core/. - log_unit_full_errno() has been removed, log_unit_full() instead takes an errno now, too. - log_unit_info(), log_link_info(), log_netdev_info() and friends, now avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
char *buffer, *b;
if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
return -ERRNO_VALUE(error);
/* Make sure that %m maps to the specified error (or "Success"). */
errno = ERRNO_VALUE(error);
core,network: major per-object logging rework This changes log_unit_info() (and friends) to take a real Unit* object insted of just a unit name as parameter. The call will now prefix all logged messages with the unit name, thus allowing the unit name to be dropped from the various passed romat strings, simplifying invocations drastically, and unifying log output across messages. Also, UNIT= vs. USER_UNIT= is now derived from the Manager object attached to the Unit object, instead of getpid(). This has the benefit of correcting the field for --test runs. Also contains a couple of other logging improvements: - Drops a couple of strerror() invocations in favour of using %m. - Not only .mount units now warn if a symlinks exist for the mount point already, .automount units do that too, now. - A few invocations of log_struct() that didn't actually pass any additional structured data have been replaced by simpler invocations of log_unit_info() and friends. - For structured data a new LOG_UNIT_MESSAGE() macro has been added, that works like LOG_MESSAGE() but prefixes the message with the unit name. Similar, there's now LOG_LINK_MESSAGE() and LOG_NETDEV_MESSAGE(). - For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(), LOG_NETDEV_INTERFACE() macros have been added that generate the necessary per object fields. The old log_unit_struct() call has been removed in favour of these new macros used in raw log_struct() invocations. In addition to removing one more function call this allows generated structured log messages that contain two object fields, as necessary for example for network interfaces that are joined into another network interface, and whose messages shall be indexed by both. - The LOG_ERRNO() macro has been removed, in favour of log_struct_errno(). The latter has the benefit of ensuring that %m in format strings is properly resolved to the specified error number. - A number of logging messages have been converted to use log_unit_info() instead of log_info() - The client code in sysv-generator no longer #includes core code from src/core/. - log_unit_full_errno() has been removed, log_unit_full() instead takes an errno now, too. - log_unit_info(), log_link_info(), log_netdev_info() and friends, now avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
/* Prepend the object name before the message */
if (object) {
size_t n;
n = strlen(object);
buffer = newa(char, n + 2 + LINE_MAX);
core,network: major per-object logging rework This changes log_unit_info() (and friends) to take a real Unit* object insted of just a unit name as parameter. The call will now prefix all logged messages with the unit name, thus allowing the unit name to be dropped from the various passed romat strings, simplifying invocations drastically, and unifying log output across messages. Also, UNIT= vs. USER_UNIT= is now derived from the Manager object attached to the Unit object, instead of getpid(). This has the benefit of correcting the field for --test runs. Also contains a couple of other logging improvements: - Drops a couple of strerror() invocations in favour of using %m. - Not only .mount units now warn if a symlinks exist for the mount point already, .automount units do that too, now. - A few invocations of log_struct() that didn't actually pass any additional structured data have been replaced by simpler invocations of log_unit_info() and friends. - For structured data a new LOG_UNIT_MESSAGE() macro has been added, that works like LOG_MESSAGE() but prefixes the message with the unit name. Similar, there's now LOG_LINK_MESSAGE() and LOG_NETDEV_MESSAGE(). - For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(), LOG_NETDEV_INTERFACE() macros have been added that generate the necessary per object fields. The old log_unit_struct() call has been removed in favour of these new macros used in raw log_struct() invocations. In addition to removing one more function call this allows generated structured log messages that contain two object fields, as necessary for example for network interfaces that are joined into another network interface, and whose messages shall be indexed by both. - The LOG_ERRNO() macro has been removed, in favour of log_struct_errno(). The latter has the benefit of ensuring that %m in format strings is properly resolved to the specified error number. - A number of logging messages have been converted to use log_unit_info() instead of log_info() - The client code in sysv-generator no longer #includes core code from src/core/. - log_unit_full_errno() has been removed, log_unit_full() instead takes an errno now, too. - log_unit_info(), log_link_info(), log_netdev_info() and friends, now avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
b = stpcpy(stpcpy(buffer, object), ": ");
} else
b = buffer = newa(char, LINE_MAX);
core,network: major per-object logging rework This changes log_unit_info() (and friends) to take a real Unit* object insted of just a unit name as parameter. The call will now prefix all logged messages with the unit name, thus allowing the unit name to be dropped from the various passed romat strings, simplifying invocations drastically, and unifying log output across messages. Also, UNIT= vs. USER_UNIT= is now derived from the Manager object attached to the Unit object, instead of getpid(). This has the benefit of correcting the field for --test runs. Also contains a couple of other logging improvements: - Drops a couple of strerror() invocations in favour of using %m. - Not only .mount units now warn if a symlinks exist for the mount point already, .automount units do that too, now. - A few invocations of log_struct() that didn't actually pass any additional structured data have been replaced by simpler invocations of log_unit_info() and friends. - For structured data a new LOG_UNIT_MESSAGE() macro has been added, that works like LOG_MESSAGE() but prefixes the message with the unit name. Similar, there's now LOG_LINK_MESSAGE() and LOG_NETDEV_MESSAGE(). - For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(), LOG_NETDEV_INTERFACE() macros have been added that generate the necessary per object fields. The old log_unit_struct() call has been removed in favour of these new macros used in raw log_struct() invocations. In addition to removing one more function call this allows generated structured log messages that contain two object fields, as necessary for example for network interfaces that are joined into another network interface, and whose messages shall be indexed by both. - The LOG_ERRNO() macro has been removed, in favour of log_struct_errno(). The latter has the benefit of ensuring that %m in format strings is properly resolved to the specified error number. - A number of logging messages have been converted to use log_unit_info() instead of log_info() - The client code in sysv-generator no longer #includes core code from src/core/. - log_unit_full_errno() has been removed, log_unit_full() instead takes an errno now, too. - log_unit_info(), log_link_info(), log_netdev_info() and friends, now avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
(void) vsnprintf(b, LINE_MAX, format, ap);
return log_dispatch_internal(level, error, file, line, func,
object_field, object, extra_field, extra, buffer);
}
int log_object_internal(
int level,
int error,
2015-11-05 13:44:03 +01:00
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
const char *extra_field,
const char *extra,
const char *format, ...) {
va_list ap;
int r;
va_start(ap, format);
core: add "invocation ID" concept to service manager This adds a new invocation ID concept to the service manager. The invocation ID identifies each runtime cycle of a unit uniquely. A new randomized 128bit ID is generated each time a unit moves from and inactive to an activating or active state. The primary usecase for this concept is to connect the runtime data PID 1 maintains about a service with the offline data the journal stores about it. Previously we'd use the unit name plus start/stop times, which however is highly racy since the journal will generally process log data after the service already ended. The "invocation ID" kinda matches the "boot ID" concept of the Linux kernel, except that it applies to an individual unit instead of the whole system. The invocation ID is passed to the activated processes as environment variable. It is additionally stored as extended attribute on the cgroup of the unit. The latter is used by journald to automatically retrieve it for each log logged message and attach it to the log entry. The environment variable is very easily accessible, even for unprivileged services. OTOH the extended attribute is only accessible to privileged processes (this is because cgroupfs only supports the "trusted." xattr namespace, not "user."). The environment variable may be altered by services, the extended attribute may not be, hence is the better choice for the journal. Note that reading the invocation ID off the extended attribute from journald is racy, similar to the way reading the unit name for a logging process is. This patch adds APIs to read the invocation ID to sd-id128: sd_id128_get_invocation() may be used in a similar fashion to sd_id128_get_boot(). PID1's own logging is updated to always include the invocation ID when it logs information about a unit. A new bus call GetUnitByInvocationID() is added that allows retrieving a bus path to a unit by its invocation ID. The bus path is built using the invocation ID, thus providing a path for referring to a unit that is valid only for the current runtime cycleof it. Outlook for the future: should the kernel eventually allow passing of cgroup information along AF_UNIX/SOCK_DGRAM messages via a unique cgroup id, then we can alter the invocation ID to be generated as hash from that rather than entirely randomly. This way we can derive the invocation race-freely from the messages.
2016-08-30 23:18:46 +02:00
r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap);
va_end(ap);
return r;
}
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];
LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
if (_likely_(LOG_PRI(level) > log_max_level[realm]))
return;
DISABLE_WARNING_FORMAT_NONLITERAL;
(void) snprintf(buffer, sizeof buffer, format, text, file, line, func);
REENABLE_WARNING;
log_abort_msg = buffer;
log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
2010-01-20 19:18:52 +01:00
}
_noreturn_ void log_assert_failed_realm(
LogRealm realm,
const char *text,
const char *file,
int line,
const char *func) {
log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
"Assertion '%s' failed at %s:%u, function %s(). Aborting.");
abort();
}
_noreturn_ void log_assert_failed_unreachable_realm(
LogRealm realm,
const char *text,
const char *file,
int line,
const char *func) {
log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
"Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
abort();
}
void log_assert_failed_return_realm(
LogRealm realm,
const char *text,
const char *file,
int line,
const char *func) {
PROTECT_ERRNO;
log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_DEBUG), text, file, line, func,
"Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
}
int log_oom_internal(LogRealm realm, const char *file, int line, const char *func) {
return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
ENOMEM, file, line, func, "Out of memory.");
}
int log_format_iovec(
struct iovec *iovec,
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald And let's make use of it to implement two new unit settings with it: 1. LogLevelMax= is a new per-unit setting that may be used to configure log priority filtering: set it to LogLevelMax=notice and only messages of level "notice" and lower (i.e. more important) will be processed, all others are dropped. 2. LogExtraFields= is a new per-unit setting for configuring per-unit journal fields, that are implicitly included in every log record generated by the unit's processes. It takes field/value pairs in the form of FOO=BAR. Also, related to this, one exisiting unit setting is ported to this new facility: 3. The invocation ID is now pulled from /run/systemd/units/ instead of cgroupfs xattrs. This substantially relaxes requirements of systemd on the kernel version and the privileges it runs with (specifically, cgroupfs xattrs are not available in containers, since they are stored in kernel memory, and hence are unsafe to permit to lesser privileged code). /run/systemd/units/ is a new directory, which contains a number of files and symlinks encoding the above information. PID 1 creates and manages these files, and journald reads them from there. Note that this is supposed to be a direct path between PID 1 and the journal only, due to the special runtime environment the journal runs in. Normally, today we shouldn't introduce new interfaces that (mis-)use a file system as IPC framework, and instead just an IPC system, but this is very hard to do between the journal and PID 1, as long as the IPC system is a subject PID 1 manages, and itself a client to the journal. This patch cleans up a couple of types used in journal code: specifically we switch to size_t for a couple of memory-sizing values, as size_t is the right choice for everything that is memory. Fixes: #4089 Fixes: #3041 Fixes: #4441
2017-11-02 19:43:32 +01:00
size_t iovec_len,
size_t *n,
bool newline_separator,
int error,
const char *format,
va_list ap) {
static const char nl = '\n';
while (format && *n + 1 < iovec_len) {
va_list aq;
char *m;
int r;
/* We need to copy the va_list structure,
* since vasprintf() leaves it afterwards at
* an undefined location */
errno = ERRNO_VALUE(error);
va_copy(aq, ap);
r = vasprintf(&m, format, aq);
va_end(aq);
if (r < 0)
return -EINVAL;
/* Now, jump enough ahead, so that we point to
* the next format string */
VA_FORMAT_ADVANCE(format, ap);
iovec[(*n)++] = IOVEC_MAKE_STRING(m);
if (newline_separator) {
iovec[*n] = IOVEC_MAKE((char *)&nl, 1);
(*n)++;
}
format = va_arg(ap, char *);
}
return 0;
}
int log_struct_internal(
int level,
int error,
const char *file,
int line,
const char *func,
const char *format, ...) {
LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
char buf[LINE_MAX];
bool found = false;
PROTECT_ERRNO;
va_list ap;
if (_likely_(LOG_PRI(level) > log_max_level[realm]) ||
log_target == LOG_TARGET_NULL)
return -ERRNO_VALUE(error);
if ((level & LOG_FACMASK) == 0)
level |= log_facility;
if (IN_SET(log_target,
LOG_TARGET_AUTO,
LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_JOURNAL)) {
if (open_when_needed)
log_open_journal();
if (journal_fd >= 0) {
char header[LINE_MAX];
struct iovec iovec[17] = {};
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald And let's make use of it to implement two new unit settings with it: 1. LogLevelMax= is a new per-unit setting that may be used to configure log priority filtering: set it to LogLevelMax=notice and only messages of level "notice" and lower (i.e. more important) will be processed, all others are dropped. 2. LogExtraFields= is a new per-unit setting for configuring per-unit journal fields, that are implicitly included in every log record generated by the unit's processes. It takes field/value pairs in the form of FOO=BAR. Also, related to this, one exisiting unit setting is ported to this new facility: 3. The invocation ID is now pulled from /run/systemd/units/ instead of cgroupfs xattrs. This substantially relaxes requirements of systemd on the kernel version and the privileges it runs with (specifically, cgroupfs xattrs are not available in containers, since they are stored in kernel memory, and hence are unsafe to permit to lesser privileged code). /run/systemd/units/ is a new directory, which contains a number of files and symlinks encoding the above information. PID 1 creates and manages these files, and journald reads them from there. Note that this is supposed to be a direct path between PID 1 and the journal only, due to the special runtime environment the journal runs in. Normally, today we shouldn't introduce new interfaces that (mis-)use a file system as IPC framework, and instead just an IPC system, but this is very hard to do between the journal and PID 1, as long as the IPC system is a subject PID 1 manages, and itself a client to the journal. This patch cleans up a couple of types used in journal code: specifically we switch to size_t for a couple of memory-sizing values, as size_t is the right choice for everything that is memory. Fixes: #4089 Fixes: #3041 Fixes: #4441
2017-11-02 19:43:32 +01:00
size_t n = 0, i;
int r;
struct msghdr mh = {
.msg_iov = iovec,
};
bool fallback = false;
/* If the journal is available do structured logging.
* Do not report the errno if it is synthetic. */
log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
iovec[n++] = IOVEC_MAKE_STRING(header);
va_start(ap, format);
r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
if (r < 0)
fallback = true;
else {
mh.msg_iovlen = n;
(void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
}
va_end(ap);
for (i = 1; i < n; i += 2)
free(iovec[i].iov_base);
if (!fallback) {
if (open_when_needed)
log_close();
return -ERRNO_VALUE(error);
}
}
}
/* Fallback if journal logging is not available or didn't work. */
va_start(ap, format);
while (format) {
va_list aq;
errno = ERRNO_VALUE(error);
va_copy(aq, ap);
(void) vsnprintf(buf, sizeof buf, format, aq);
va_end(aq);
if (startswith(buf, "MESSAGE=")) {
found = true;
break;
}
VA_FORMAT_ADVANCE(format, ap);
format = va_arg(ap, char *);
}
va_end(ap);
if (!found) {
if (open_when_needed)
log_close();
return -ERRNO_VALUE(error);
}
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
}
int log_struct_iovec_internal(
int level,
int error,
const char *file,
int line,
const char *func,
const struct iovec input_iovec[],
size_t n_input_iovec) {
LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
PROTECT_ERRNO;
size_t i;
char *m;
if (_likely_(LOG_PRI(level) > log_max_level[realm]) ||
log_target == LOG_TARGET_NULL)
return -ERRNO_VALUE(error);
if ((level & LOG_FACMASK) == 0)
level |= log_facility;
if (IN_SET(log_target, LOG_TARGET_AUTO,
LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_JOURNAL) &&
journal_fd >= 0) {
struct iovec iovec[1 + n_input_iovec*2];
char header[LINE_MAX];
struct msghdr mh = {
.msg_iov = iovec,
.msg_iovlen = 1 + n_input_iovec*2,
};
log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
iovec[0] = IOVEC_MAKE_STRING(header);
for (i = 0; i < n_input_iovec; i++) {
iovec[1+i*2] = input_iovec[i];
iovec[1+i*2+1] = IOVEC_MAKE_STRING("\n");
}
if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) >= 0)
return -ERRNO_VALUE(error);
}
for (i = 0; i < n_input_iovec; i++)
if (memory_startswith(input_iovec[i].iov_base, input_iovec[i].iov_len, "MESSAGE="))
break;
if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */
return -ERRNO_VALUE(error);
m = strndupa(input_iovec[i].iov_base + STRLEN("MESSAGE="),
input_iovec[i].iov_len - STRLEN("MESSAGE="));
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m);
}
int log_set_target_from_string(const char *e) {
LogTarget t;
t = log_target_from_string(e);
if (t < 0)
return -EINVAL;
log_set_target(t);
return 0;
}
int log_set_max_level_from_string_realm(LogRealm realm, const char *e) {
int t;
t = log_level_from_string(e);
if (t < 0)
return -EINVAL;
log_set_max_level_realm(realm, t);
return 0;
}
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
/*
* The systemd.log_xyz= settings are parsed by all tools, and
* so is "debug".
*
* However, "quiet" is only parsed by PID 1, and only turns of
* status output to /dev/console, but does not alter the log
* level.
*/
if (streq(key, "debug") && !value)
log_set_max_level(LOG_DEBUG);
util-lib: various improvements to kernel command line parsing This improves kernel command line parsing in a number of ways: a) An kernel option "foo_bar=xyz" is now considered equivalent to "foo-bar-xyz", i.e. when comparing kernel command line option names "-" and "_" are now considered equivalent (this only applies to the option names though, not the option values!). Most of our kernel options used "-" as word separator in kernel command line options so far, but some used "_". With this change, which was a source of confusion for users (well, at least of one user: myself, I just couldn't remember that it's systemd.debug-shell, not systemd.debug_shell). Considering both as equivalent is inspired how modern kernel module loading normalizes all kernel module names to use underscores now too. b) All options previously using a dash for separating words in kernel command line options now use an underscore instead, in all documentation and in code. Since a) has been implemented this should not create any compatibility problems, but normalizes our documentation and our code. c) All kernel command line options which take booleans (or are boolean-like) have been reworked so that "foobar" (without argument) is now equivalent to "foobar=1" (but not "foobar=0"), thus normalizing the handling of our boolean arguments. Specifically this means systemd.debug-shell and systemd_debug_shell=1 are now entirely equivalent. d) All kernel command line options which take an argument, and where no argument is specified will now result in a log message. e.g. passing just "systemd.unit" will no result in a complain that it needs an argument. This is implemented in the proc_cmdline_missing_value() function. e) There's now a call proc_cmdline_get_bool() similar to proc_cmdline_get_key() that parses booleans (following the logic explained in c). f) The proc_cmdline_parse() call's boolean argument has been replaced by a new flags argument that takes a common set of bits with proc_cmdline_get_key(). g) All kernel command line APIs now begin with the same "proc_cmdline_" prefix. h) There are now tests for much of this. Yay!
2016-12-12 18:29:15 +01:00
else if (proc_cmdline_key_streq(key, "systemd.log_target")) {
if (proc_cmdline_value_missing(key, value))
return 0;
if (log_set_target_from_string(value) < 0)
log_warning("Failed to parse log target '%s'. Ignoring.", value);
util-lib: various improvements to kernel command line parsing This improves kernel command line parsing in a number of ways: a) An kernel option "foo_bar=xyz" is now considered equivalent to "foo-bar-xyz", i.e. when comparing kernel command line option names "-" and "_" are now considered equivalent (this only applies to the option names though, not the option values!). Most of our kernel options used "-" as word separator in kernel command line options so far, but some used "_". With this change, which was a source of confusion for users (well, at least of one user: myself, I just couldn't remember that it's systemd.debug-shell, not systemd.debug_shell). Considering both as equivalent is inspired how modern kernel module loading normalizes all kernel module names to use underscores now too. b) All options previously using a dash for separating words in kernel command line options now use an underscore instead, in all documentation and in code. Since a) has been implemented this should not create any compatibility problems, but normalizes our documentation and our code. c) All kernel command line options which take booleans (or are boolean-like) have been reworked so that "foobar" (without argument) is now equivalent to "foobar=1" (but not "foobar=0"), thus normalizing the handling of our boolean arguments. Specifically this means systemd.debug-shell and systemd_debug_shell=1 are now entirely equivalent. d) All kernel command line options which take an argument, and where no argument is specified will now result in a log message. e.g. passing just "systemd.unit" will no result in a complain that it needs an argument. This is implemented in the proc_cmdline_missing_value() function. e) There's now a call proc_cmdline_get_bool() similar to proc_cmdline_get_key() that parses booleans (following the logic explained in c). f) The proc_cmdline_parse() call's boolean argument has been replaced by a new flags argument that takes a common set of bits with proc_cmdline_get_key(). g) All kernel command line APIs now begin with the same "proc_cmdline_" prefix. h) There are now tests for much of this. Yay!
2016-12-12 18:29:15 +01:00
} else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
if (proc_cmdline_value_missing(key, value))
return 0;
if (log_set_max_level_from_string(value) < 0)
log_warning("Failed to parse log level '%s'. Ignoring.", value);
util-lib: various improvements to kernel command line parsing This improves kernel command line parsing in a number of ways: a) An kernel option "foo_bar=xyz" is now considered equivalent to "foo-bar-xyz", i.e. when comparing kernel command line option names "-" and "_" are now considered equivalent (this only applies to the option names though, not the option values!). Most of our kernel options used "-" as word separator in kernel command line options so far, but some used "_". With this change, which was a source of confusion for users (well, at least of one user: myself, I just couldn't remember that it's systemd.debug-shell, not systemd.debug_shell). Considering both as equivalent is inspired how modern kernel module loading normalizes all kernel module names to use underscores now too. b) All options previously using a dash for separating words in kernel command line options now use an underscore instead, in all documentation and in code. Since a) has been implemented this should not create any compatibility problems, but normalizes our documentation and our code. c) All kernel command line options which take booleans (or are boolean-like) have been reworked so that "foobar" (without argument) is now equivalent to "foobar=1" (but not "foobar=0"), thus normalizing the handling of our boolean arguments. Specifically this means systemd.debug-shell and systemd_debug_shell=1 are now entirely equivalent. d) All kernel command line options which take an argument, and where no argument is specified will now result in a log message. e.g. passing just "systemd.unit" will no result in a complain that it needs an argument. This is implemented in the proc_cmdline_missing_value() function. e) There's now a call proc_cmdline_get_bool() similar to proc_cmdline_get_key() that parses booleans (following the logic explained in c). f) The proc_cmdline_parse() call's boolean argument has been replaced by a new flags argument that takes a common set of bits with proc_cmdline_get_key(). g) All kernel command line APIs now begin with the same "proc_cmdline_" prefix. h) There are now tests for much of this. Yay!
2016-12-12 18:29:15 +01:00
} else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
util-lib: various improvements to kernel command line parsing This improves kernel command line parsing in a number of ways: a) An kernel option "foo_bar=xyz" is now considered equivalent to "foo-bar-xyz", i.e. when comparing kernel command line option names "-" and "_" are now considered equivalent (this only applies to the option names though, not the option values!). Most of our kernel options used "-" as word separator in kernel command line options so far, but some used "_". With this change, which was a source of confusion for users (well, at least of one user: myself, I just couldn't remember that it's systemd.debug-shell, not systemd.debug_shell). Considering both as equivalent is inspired how modern kernel module loading normalizes all kernel module names to use underscores now too. b) All options previously using a dash for separating words in kernel command line options now use an underscore instead, in all documentation and in code. Since a) has been implemented this should not create any compatibility problems, but normalizes our documentation and our code. c) All kernel command line options which take booleans (or are boolean-like) have been reworked so that "foobar" (without argument) is now equivalent to "foobar=1" (but not "foobar=0"), thus normalizing the handling of our boolean arguments. Specifically this means systemd.debug-shell and systemd_debug_shell=1 are now entirely equivalent. d) All kernel command line options which take an argument, and where no argument is specified will now result in a log message. e.g. passing just "systemd.unit" will no result in a complain that it needs an argument. This is implemented in the proc_cmdline_missing_value() function. e) There's now a call proc_cmdline_get_bool() similar to proc_cmdline_get_key() that parses booleans (following the logic explained in c). f) The proc_cmdline_parse() call's boolean argument has been replaced by a new flags argument that takes a common set of bits with proc_cmdline_get_key(). g) All kernel command line APIs now begin with the same "proc_cmdline_" prefix. h) There are now tests for much of this. Yay!
2016-12-12 18:29:15 +01:00
if (log_show_color_from_string(value ?: "1") < 0)
log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
util-lib: various improvements to kernel command line parsing This improves kernel command line parsing in a number of ways: a) An kernel option "foo_bar=xyz" is now considered equivalent to "foo-bar-xyz", i.e. when comparing kernel command line option names "-" and "_" are now considered equivalent (this only applies to the option names though, not the option values!). Most of our kernel options used "-" as word separator in kernel command line options so far, but some used "_". With this change, which was a source of confusion for users (well, at least of one user: myself, I just couldn't remember that it's systemd.debug-shell, not systemd.debug_shell). Considering both as equivalent is inspired how modern kernel module loading normalizes all kernel module names to use underscores now too. b) All options previously using a dash for separating words in kernel command line options now use an underscore instead, in all documentation and in code. Since a) has been implemented this should not create any compatibility problems, but normalizes our documentation and our code. c) All kernel command line options which take booleans (or are boolean-like) have been reworked so that "foobar" (without argument) is now equivalent to "foobar=1" (but not "foobar=0"), thus normalizing the handling of our boolean arguments. Specifically this means systemd.debug-shell and systemd_debug_shell=1 are now entirely equivalent. d) All kernel command line options which take an argument, and where no argument is specified will now result in a log message. e.g. passing just "systemd.unit" will no result in a complain that it needs an argument. This is implemented in the proc_cmdline_missing_value() function. e) There's now a call proc_cmdline_get_bool() similar to proc_cmdline_get_key() that parses booleans (following the logic explained in c). f) The proc_cmdline_parse() call's boolean argument has been replaced by a new flags argument that takes a common set of bits with proc_cmdline_get_key(). g) All kernel command line APIs now begin with the same "proc_cmdline_" prefix. h) There are now tests for much of this. Yay!
2016-12-12 18:29:15 +01:00
} else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
util-lib: various improvements to kernel command line parsing This improves kernel command line parsing in a number of ways: a) An kernel option "foo_bar=xyz" is now considered equivalent to "foo-bar-xyz", i.e. when comparing kernel command line option names "-" and "_" are now considered equivalent (this only applies to the option names though, not the option values!). Most of our kernel options used "-" as word separator in kernel command line options so far, but some used "_". With this change, which was a source of confusion for users (well, at least of one user: myself, I just couldn't remember that it's systemd.debug-shell, not systemd.debug_shell). Considering both as equivalent is inspired how modern kernel module loading normalizes all kernel module names to use underscores now too. b) All options previously using a dash for separating words in kernel command line options now use an underscore instead, in all documentation and in code. Since a) has been implemented this should not create any compatibility problems, but normalizes our documentation and our code. c) All kernel command line options which take booleans (or are boolean-like) have been reworked so that "foobar" (without argument) is now equivalent to "foobar=1" (but not "foobar=0"), thus normalizing the handling of our boolean arguments. Specifically this means systemd.debug-shell and systemd_debug_shell=1 are now entirely equivalent. d) All kernel command line options which take an argument, and where no argument is specified will now result in a log message. e.g. passing just "systemd.unit" will no result in a complain that it needs an argument. This is implemented in the proc_cmdline_missing_value() function. e) There's now a call proc_cmdline_get_bool() similar to proc_cmdline_get_key() that parses booleans (following the logic explained in c). f) The proc_cmdline_parse() call's boolean argument has been replaced by a new flags argument that takes a common set of bits with proc_cmdline_get_key(). g) All kernel command line APIs now begin with the same "proc_cmdline_" prefix. h) There are now tests for much of this. Yay!
2016-12-12 18:29:15 +01:00
if (log_show_location_from_string(value ?: "1") < 0)
log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_tid")) {
if (log_show_tid_from_string(value ?: "1") < 0)
log_warning("Failed to parse log tid setting '%s'. Ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_time")) {
if (log_show_time_from_string(value ?: "1") < 0)
log_warning("Failed to parse log time setting '%s'. Ignoring.", value);
}
return 0;
}
void log_parse_environment_realm(LogRealm realm) {
if (getpid_cached() == 1 || get_ctty_devnr(0, NULL) < 0)
/* Only try to read the command line in daemons. We assume that anything that has a
* controlling tty is user stuff. For PID1 we do a special check in case it hasn't
* closed the console yet. */
util-lib: various improvements to kernel command line parsing This improves kernel command line parsing in a number of ways: a) An kernel option "foo_bar=xyz" is now considered equivalent to "foo-bar-xyz", i.e. when comparing kernel command line option names "-" and "_" are now considered equivalent (this only applies to the option names though, not the option values!). Most of our kernel options used "-" as word separator in kernel command line options so far, but some used "_". With this change, which was a source of confusion for users (well, at least of one user: myself, I just couldn't remember that it's systemd.debug-shell, not systemd.debug_shell). Considering both as equivalent is inspired how modern kernel module loading normalizes all kernel module names to use underscores now too. b) All options previously using a dash for separating words in kernel command line options now use an underscore instead, in all documentation and in code. Since a) has been implemented this should not create any compatibility problems, but normalizes our documentation and our code. c) All kernel command line options which take booleans (or are boolean-like) have been reworked so that "foobar" (without argument) is now equivalent to "foobar=1" (but not "foobar=0"), thus normalizing the handling of our boolean arguments. Specifically this means systemd.debug-shell and systemd_debug_shell=1 are now entirely equivalent. d) All kernel command line options which take an argument, and where no argument is specified will now result in a log message. e.g. passing just "systemd.unit" will no result in a complain that it needs an argument. This is implemented in the proc_cmdline_missing_value() function. e) There's now a call proc_cmdline_get_bool() similar to proc_cmdline_get_key() that parses booleans (following the logic explained in c). f) The proc_cmdline_parse() call's boolean argument has been replaced by a new flags argument that takes a common set of bits with proc_cmdline_get_key(). g) All kernel command line APIs now begin with the same "proc_cmdline_" prefix. h) There are now tests for much of this. Yay!
2016-12-12 18:29:15 +01:00
(void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
log_parse_environment_cli_realm(realm);
}
void log_parse_environment_cli_realm(LogRealm realm) {
/* Do not call from library code. */
const char *e;
e = getenv("SYSTEMD_LOG_TARGET");
if (e && log_set_target_from_string(e) < 0)
log_warning("Failed to parse log target '%s'. Ignoring.", e);
e = getenv("SYSTEMD_LOG_LEVEL");
if (e && log_set_max_level_from_string_realm(realm, e) < 0)
log_warning("Failed to parse log level '%s'. Ignoring.", e);
e = getenv("SYSTEMD_LOG_COLOR");
if (e && log_show_color_from_string(e) < 0)
log_warning("Failed to parse log color '%s'. Ignoring.", e);
e = getenv("SYSTEMD_LOG_LOCATION");
if (e && log_show_location_from_string(e) < 0)
log_warning("Failed to parse log location '%s'. Ignoring.", e);
e = getenv("SYSTEMD_LOG_TIME");
if (e && log_show_time_from_string(e) < 0)
log_warning("Failed to parse log time '%s'. Ignoring.", e);
e = getenv("SYSTEMD_LOG_TID");
if (e && log_show_tid_from_string(e) < 0)
log_warning("Failed to parse log tid '%s'. Ignoring.", e);
}
LogTarget log_get_target(void) {
return log_target;
}
int log_get_max_level_realm(LogRealm realm) {
return log_max_level[realm];
}
void log_show_color(bool b) {
show_color = b;
}
bool log_get_show_color(void) {
return show_color > 0; /* Defaults to false. */
}
void log_show_location(bool b) {
show_location = b;
}
bool log_get_show_location(void) {
return show_location;
}
void log_show_time(bool b) {
show_time = b;
}
bool log_get_show_time(void) {
return show_time;
}
void log_show_tid(bool b) {
show_tid = b;
}
bool log_get_show_tid(void) {
return show_tid;
}
int log_show_color_from_string(const char *e) {
int t;
t = parse_boolean(e);
if (t < 0)
return t;
log_show_color(t);
return 0;
}
int log_show_location_from_string(const char *e) {
int t;
t = parse_boolean(e);
if (t < 0)
return t;
log_show_location(t);
return 0;
}
int log_show_time_from_string(const char *e) {
int t;
t = parse_boolean(e);
if (t < 0)
return t;
log_show_time(t);
return 0;
}
int log_show_tid_from_string(const char *e) {
int t;
t = parse_boolean(e);
if (t < 0)
return t;
log_show_tid(t);
return 0;
}
bool log_on_console(void) {
2016-12-18 01:55:43 +01:00
if (IN_SET(log_target, LOG_TARGET_CONSOLE,
LOG_TARGET_CONSOLE_PREFIXED))
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_CONSOLE_PREFIXED] = "console-prefixed",
[LOG_TARGET_KMSG] = "kmsg",
[LOG_TARGET_JOURNAL] = "journal",
[LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
[LOG_TARGET_SYSLOG] = "syslog",
[LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
[LOG_TARGET_AUTO] = "auto",
[LOG_TARGET_NULL] = "null",
};
DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
2014-02-10 02:08:55 +01:00
void log_received_signal(int level, const struct signalfd_siginfo *si) {
assert(si);
if (pid_is_valid(si->ssi_pid)) {
2014-02-10 02:08:55 +01:00
_cleanup_free_ char *p = NULL;
(void) get_process_comm(si->ssi_pid, &p);
2014-02-10 02:08:55 +01:00
log_full(level,
"Received SIG%s from PID %"PRIu32" (%s).",
2014-02-10 02:08:55 +01:00
signal_to_string(si->ssi_signo),
si->ssi_pid, strna(p));
} else
log_full(level,
"Received SIG%s.",
signal_to_string(si->ssi_signo));
}
int log_syntax_internal(
const char *unit,
int level,
const char *config_file,
unsigned config_line,
int error,
const char *file,
int line,
const char *func,
const char *format, ...) {
PROTECT_ERRNO;
char buffer[LINE_MAX];
va_list ap;
const char *unit_fmt = NULL;
if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]) ||
log_target == LOG_TARGET_NULL)
return -ERRNO_VALUE(error);
errno = ERRNO_VALUE(error);
va_start(ap, format);
(void) vsnprintf(buffer, sizeof buffer, format, ap);
va_end(ap);
if (unit)
unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
if (config_file) {
if (config_line > 0)
return log_struct_internal(
LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
error,
file, line, func,
"MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
"CONFIG_FILE=%s", config_file,
"CONFIG_LINE=%u", config_line,
LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),
unit_fmt, unit,
NULL);
else
return log_struct_internal(
LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
error,
file, line, func,
"MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
"CONFIG_FILE=%s", config_file,
LOG_MESSAGE("%s: %s", config_file, buffer),
unit_fmt, unit,
NULL);
} else if (unit)
return log_struct_internal(
LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
error,
file, line, func,
"MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
LOG_MESSAGE("%s: %s", unit, buffer),
unit_fmt, unit,
NULL);
else
return log_struct_internal(
LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
error,
file, line, func,
"MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
LOG_MESSAGE("%s", buffer),
NULL);
}
int log_syntax_invalid_utf8_internal(
const char *unit,
int level,
const char *config_file,
unsigned config_line,
const char *file,
int line,
const char *func,
const char *rvalue) {
_cleanup_free_ char *p = NULL;
if (rvalue)
p = utf8_escape_invalid(rvalue);
log_syntax_internal(unit, level, config_file, config_line, 0, file, line, func,
"String is not UTF-8 clean, ignoring assignment: %s", strna(p));
return -EINVAL;
}
void log_set_upgrade_syslog_to_journal(bool b) {
upgrade_syslog_to_journal = b;
/* Make the change effective immediately */
if (b) {
if (log_target == LOG_TARGET_SYSLOG)
log_target = LOG_TARGET_JOURNAL;
else if (log_target == LOG_TARGET_SYSLOG_OR_KMSG)
log_target = LOG_TARGET_JOURNAL_OR_KMSG;
}
}
void log_set_always_reopen_console(bool b) {
always_reopen_console = b;
}
void log_set_open_when_needed(bool b) {
open_when_needed = b;
}
void log_set_prohibit_ipc(bool b) {
prohibit_ipc = b;
}
int log_emergency_level(void) {
/* Returns the log level to use for log_emergency() logging. We use LOG_EMERG only when we are PID 1, as only
* then the system of the whole system is obviously affected. */
return getpid_cached() == 1 ? LOG_EMERG : LOG_ERR;
}
int log_dup_console(void) {
int copy;
/* Duplicate the fd we use for fd logging if it's < 3 and use the copy from now on. This call is useful
* whenever we want to continue logging through the original fd, but want to rearrange stderr. */
if (console_fd >= 3)
return 0;
copy = fcntl(console_fd, F_DUPFD_CLOEXEC, 3);
if (copy < 0)
return -errno;
console_fd = copy;
return 0;
}
void log_setup_service(void) {
/* Sets up logging the way it is most appropriate for running a program as a service. Note that using this
* doesn't make the binary unsuitable for invocation on the command line, as log output will still go to the
* terminal if invoked interactively. */
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
(void) log_open();
}
void log_setup_cli(void) {
/* Sets up logging the way it is most appropriate for running a program as a CLI utility. */
log_set_target(LOG_TARGET_AUTO);
log_parse_environment_cli();
(void) log_open();
if (log_on_console() && show_color < 0)
log_show_color(true);
}