2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2010-02-03 13:03:47 +01:00
|
|
|
|
2010-01-27 22:39:29 +01:00
|
|
|
#include <errno.h>
|
2010-04-06 21:57:45 +02:00
|
|
|
#include <fcntl.h>
|
2015-11-30 21:43:37 +01:00
|
|
|
#include <inttypes.h>
|
|
|
|
#include <limits.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stddef.h>
|
2015-11-30 21:43:37 +01:00
|
|
|
#include <sys/signalfd.h>
|
2020-06-10 20:19:41 +02:00
|
|
|
#include <sys/stat.h>
|
2015-11-30 21:43:37 +01:00
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/uio.h>
|
2010-04-06 21:57:45 +02:00
|
|
|
#include <sys/un.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <unistd.h>
|
2010-01-20 19:18:52 +01:00
|
|
|
|
2015-04-21 17:26:04 +02:00
|
|
|
#include "sd-messages.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2019-03-14 12:24:39 +01:00
|
|
|
#include "errno-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2016-11-07 16:14:59 +01:00
|
|
|
#include "format-util.h"
|
2015-10-27 01:02:30 +01:00
|
|
|
#include "io-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "log.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "macro.h"
|
2020-09-29 13:06:12 +02:00
|
|
|
#include "missing_syscall.h"
|
2015-10-27 00:06:29 +01:00
|
|
|
#include "parse-util.h"
|
|
|
|
#include "proc-cmdline.h"
|
2015-04-10 19:10:00 +02:00
|
|
|
#include "process-util.h"
|
2019-09-19 18:01:23 +02:00
|
|
|
#include "ratelimit.h"
|
2015-05-29 20:14:11 +02:00
|
|
|
#include "signal-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "socket-util.h"
|
2015-10-27 01:26:31 +01:00
|
|
|
#include "stdio-util.h"
|
2015-10-26 22:31:05 +01:00
|
|
|
#include "string-table.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2015-10-27 00:40:25 +01:00
|
|
|
#include "syslog-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "terminal-util.h"
|
2015-12-01 23:22:03 +01:00
|
|
|
#include "time-util.h"
|
2018-01-11 13:13:02 +01:00
|
|
|
#include "utf8.h"
|
2010-01-20 19:18:52 +01:00
|
|
|
|
2012-01-27 18:57:37 +01:00
|
|
|
#define SNDBUF_SIZE (8*1024*1024)
|
|
|
|
|
2010-04-06 21:57:45 +02:00
|
|
|
static LogTarget log_target = LOG_TARGET_CONSOLE;
|
2017-02-23 04:57:34 +01:00
|
|
|
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;
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
static int console_fd = STDERR_FILENO;
|
2010-04-06 21:57:45 +02:00
|
|
|
static int syslog_fd = -1;
|
|
|
|
static int kmsg_fd = -1;
|
2012-01-12 04:34:31 +01:00
|
|
|
static int journal_fd = -1;
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2010-09-08 03:07:44 +02:00
|
|
|
static bool syslog_is_stream = false;
|
|
|
|
|
2020-12-08 17:44:36 +01:00
|
|
|
static int show_color = -1; /* tristate */
|
2010-06-17 22:52:55 +02:00
|
|
|
static bool show_location = false;
|
2019-07-15 15:56:24 +02:00
|
|
|
static bool show_time = false;
|
2020-09-29 13:06:12 +02:00
|
|
|
static bool show_tid = false;
|
2010-06-17 22:52:55 +02:00
|
|
|
|
2014-08-11 20:08:08 +02:00
|
|
|
static bool upgrade_syslog_to_journal = false;
|
2017-02-21 17:57:55 +01:00
|
|
|
static bool always_reopen_console = false;
|
2017-09-26 17:45:09 +02:00
|
|
|
static bool open_when_needed = false;
|
log: add new "prohibit_ipc" flag to logging system
If set, we'll avoid logging to any IPC log targets, i.e. syslog or the
journal, but allow stderr, kmsg, console logging.
This is useful as PID 1 wants to turn this off explicitly as long as the
journal is not up.
Previously we'd open/close the log stream to these services whenever
needed but this is incompatible with the "open_when_needed" logic
introduced in #6915, which might open the log streams whenever it likes,
including possibly inside of the child process we fork off that'll
become journald later on. Hence, let's make this all explicit, and
instead of managing when we open/close log streams add a boolean that
clearly prohibits the IPC targets when needed, so that opening can be
done at any time, but will honour this.
See: #7985
2018-01-24 17:36:25 +01:00
|
|
|
static bool prohibit_ipc = false;
|
2014-08-11 20:08:08 +02:00
|
|
|
|
2011-02-21 15:32:17 +01:00
|
|
|
/* Akin to glibc's __abort_msg; which is private and we hence cannot
|
2010-04-22 03:51:26 +02:00
|
|
|
* use here. */
|
|
|
|
static char *log_abort_msg = NULL;
|
|
|
|
|
2018-02-23 13:29:03 +01:00
|
|
|
/* 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)
|
|
|
|
|
2018-01-26 14:42:53 +01:00
|
|
|
static void log_close_console(void) {
|
2018-02-26 15:41:38 +01:00
|
|
|
console_fd = safe_close_above_stdio(console_fd);
|
2010-04-06 21:57:45 +02:00
|
|
|
}
|
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
static int log_open_console(void) {
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2018-01-26 14:42:53 +01:00
|
|
|
if (!always_reopen_console) {
|
|
|
|
console_fd = STDERR_FILENO;
|
2010-04-06 21:57:45 +02:00
|
|
|
return 0;
|
2018-01-26 14:42:53 +01:00
|
|
|
}
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2018-01-26 14:42:53 +01:00
|
|
|
if (console_fd < 3) {
|
2019-08-20 17:32:17 +02:00
|
|
|
int fd;
|
2018-02-09 17:53:28 +01:00
|
|
|
|
2019-08-20 17:32:17 +02:00
|
|
|
fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
console_fd = fd_move_above_stdio(fd);
|
2018-01-26 14:42:53 +01:00
|
|
|
}
|
2010-05-15 17:25:08 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-01-26 14:42:53 +01:00
|
|
|
static void log_close_kmsg(void) {
|
2014-03-18 19:22:43 +01:00
|
|
|
kmsg_fd = safe_close(kmsg_fd);
|
2010-05-15 17:25:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int log_open_kmsg(void) {
|
2010-04-06 21:57:45 +02:00
|
|
|
|
|
|
|
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);
|
2012-09-17 22:14:24 +02:00
|
|
|
if (kmsg_fd < 0)
|
2010-04-06 21:57:45 +02:00
|
|
|
return -errno;
|
2010-04-08 00:58:03 +02:00
|
|
|
|
2018-02-09 17:53:28 +01:00
|
|
|
kmsg_fd = fd_move_above_stdio(kmsg_fd);
|
2010-04-06 21:57:45 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-01-26 14:42:53 +01:00
|
|
|
static void log_close_syslog(void) {
|
2014-03-18 19:22:43 +01:00
|
|
|
syslog_fd = safe_close(syslog_fd);
|
2010-04-06 21:57:45 +02:00
|
|
|
}
|
|
|
|
|
2010-09-08 03:07:44 +02:00
|
|
|
static int create_log_socket(int type) {
|
2013-07-24 07:24:05 +02:00
|
|
|
struct timeval tv;
|
2014-11-28 02:56:39 +01:00
|
|
|
int fd;
|
2010-09-08 03:07:44 +02:00
|
|
|
|
2013-07-24 07:24:05 +02:00
|
|
|
fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
|
2012-01-12 04:34:31 +01:00
|
|
|
if (fd < 0)
|
2010-09-08 03:07:44 +02:00
|
|
|
return -errno;
|
|
|
|
|
2018-02-09 17:53:28 +01:00
|
|
|
fd = fd_move_above_stdio(fd);
|
2016-08-30 21:02:36 +02:00
|
|
|
(void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
|
2012-01-27 18:57:37 +01:00
|
|
|
|
2018-02-09 17:53:28 +01:00
|
|
|
/* 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. */
|
2017-07-20 16:19:18 +02:00
|
|
|
if (getpid_cached() == 1)
|
2013-12-14 17:54:26 +01:00
|
|
|
timeval_store(&tv, 10 * USEC_PER_MSEC);
|
|
|
|
else
|
|
|
|
timeval_store(&tv, 10 * USEC_PER_SEC);
|
2014-11-27 19:48:02 +01:00
|
|
|
(void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
2013-07-24 07:24:05 +02:00
|
|
|
|
2010-09-08 03:07:44 +02:00
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
static int log_open_syslog(void) {
|
2014-11-28 02:56:39 +01:00
|
|
|
|
|
|
|
static const union sockaddr_union sa = {
|
2013-03-25 00:59:00 +01:00
|
|
|
.un.sun_family = AF_UNIX,
|
|
|
|
.un.sun_path = "/dev/log",
|
|
|
|
};
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2014-11-28 02:56:39 +01:00
|
|
|
int r;
|
|
|
|
|
2010-04-06 21:57:45 +02:00
|
|
|
if (syslog_fd >= 0)
|
|
|
|
return 0;
|
|
|
|
|
2012-01-12 04:34:31 +01:00
|
|
|
syslog_fd = create_log_socket(SOCK_DGRAM);
|
|
|
|
if (syslog_fd < 0) {
|
|
|
|
r = syslog_fd;
|
2010-05-15 17:25:08 +02:00
|
|
|
goto fail;
|
2010-04-06 21:57:45 +02:00
|
|
|
}
|
|
|
|
|
2016-05-05 22:24:36 +02:00
|
|
|
if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
|
2014-03-18 19:22:43 +01:00
|
|
|
safe_close(syslog_fd);
|
2010-09-08 03:07:44 +02:00
|
|
|
|
|
|
|
/* Some legacy syslog systems still use stream
|
|
|
|
* sockets. They really shouldn't. But what can we
|
|
|
|
* do... */
|
2012-01-12 04:34:31 +01:00
|
|
|
syslog_fd = create_log_socket(SOCK_STREAM);
|
|
|
|
if (syslog_fd < 0) {
|
|
|
|
r = syslog_fd;
|
2010-09-08 03:07:44 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2016-05-05 22:24:36 +02:00
|
|
|
if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
|
2010-09-08 03:07:44 +02:00
|
|
|
r = -errno;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
syslog_is_stream = true;
|
|
|
|
} else
|
|
|
|
syslog_is_stream = false;
|
|
|
|
|
2010-04-06 21:57:45 +02:00
|
|
|
return 0;
|
2010-05-15 17:25:08 +02:00
|
|
|
|
|
|
|
fail:
|
|
|
|
log_close_syslog();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2018-01-26 14:42:53 +01:00
|
|
|
static void log_close_journal(void) {
|
2014-03-18 19:22:43 +01:00
|
|
|
journal_fd = safe_close(journal_fd);
|
2012-01-12 04:34:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int log_open_journal(void) {
|
2014-11-28 02:56:39 +01:00
|
|
|
|
|
|
|
static const union sockaddr_union sa = {
|
2013-03-25 00:59:00 +01:00
|
|
|
.un.sun_family = AF_UNIX,
|
|
|
|
.un.sun_path = "/run/systemd/journal/socket",
|
|
|
|
};
|
2014-11-28 02:56:39 +01:00
|
|
|
|
2012-01-12 04:34:31 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
if (journal_fd >= 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
journal_fd = create_log_socket(SOCK_DGRAM);
|
|
|
|
if (journal_fd < 0) {
|
|
|
|
r = journal_fd;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2016-05-05 22:24:36 +02:00
|
|
|
if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
|
2012-01-12 04:34:31 +01:00
|
|
|
r = -errno;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
log_close_journal();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2020-06-10 20:19:41 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
int log_open(void) {
|
|
|
|
int r;
|
|
|
|
|
2017-07-11 10:40:11 +02:00
|
|
|
/* Do not call from library code. */
|
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
/* 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
|
2018-01-26 14:42:53 +01:00
|
|
|
* 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,
|
2010-05-15 17:25:08 +02:00
|
|
|
* because there is no reason to close it. */
|
|
|
|
|
2010-06-09 15:37:37 +02:00
|
|
|
if (log_target == LOG_TARGET_NULL) {
|
2012-01-12 04:34:31 +01:00
|
|
|
log_close_journal();
|
2010-06-09 15:37:37 +02:00
|
|
|
log_close_syslog();
|
|
|
|
log_close_console();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-30 16:17:12 +02:00
|
|
|
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
|
|
|
}
|
2012-01-12 04:34:31 +01:00
|
|
|
|
2020-09-30 16:17:12 +02: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;
|
|
|
|
}
|
2012-01-12 04:34:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)) {
|
2012-01-12 04:34:31 +01:00
|
|
|
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;
|
|
|
|
}
|
2012-01-12 04:34:31 +01:00
|
|
|
}
|
2010-11-12 01:01:04 +01:00
|
|
|
}
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2012-01-12 04:34:31 +01:00
|
|
|
log_close_journal();
|
2010-05-15 17:25:08 +02:00
|
|
|
log_close_syslog();
|
2010-10-20 00:56:26 +02:00
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
return log_open_console();
|
2010-04-06 21:57:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void log_set_target(LogTarget target) {
|
|
|
|
assert(target >= 0);
|
|
|
|
assert(target < _LOG_TARGET_MAX);
|
|
|
|
|
2014-08-11 20:08:08 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-04-06 21:57:45 +02:00
|
|
|
log_target = target;
|
|
|
|
}
|
|
|
|
|
2011-07-25 21:22:57 +02:00
|
|
|
void log_close(void) {
|
2017-07-11 10:40:11 +02:00
|
|
|
/* Do not call from library code. */
|
|
|
|
|
2012-01-12 04:34:31 +01:00
|
|
|
log_close_journal();
|
2011-07-25 21:22:57 +02:00
|
|
|
log_close_syslog();
|
2012-01-12 04:34:31 +01:00
|
|
|
log_close_kmsg();
|
|
|
|
log_close_console();
|
2011-07-25 21:22:57 +02:00
|
|
|
}
|
|
|
|
|
2011-11-16 23:45:01 +01:00
|
|
|
void log_forget_fds(void) {
|
2017-07-11 10:40:11 +02:00
|
|
|
/* Do not call from library code. */
|
|
|
|
|
2012-01-12 04:34:31 +01:00
|
|
|
console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
|
2011-11-16 23:45:01 +01:00
|
|
|
}
|
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
void log_set_max_level_realm(LogRealm realm, int level) {
|
2010-04-06 21:57:45 +02:00
|
|
|
assert((level & LOG_PRIMASK) == level);
|
2017-02-23 04:57:34 +01:00
|
|
|
assert(realm < ELEMENTSOF(log_max_level));
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
log_max_level[realm] = level;
|
2010-04-06 21:57:45 +02:00
|
|
|
}
|
|
|
|
|
2012-04-03 19:25:29 +02:00
|
|
|
void log_set_facility(int facility) {
|
|
|
|
log_facility = facility;
|
|
|
|
}
|
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
static int write_to_console(
|
2011-04-07 18:48:50 +02:00
|
|
|
int level,
|
2014-11-27 19:48:02 +01:00
|
|
|
int error,
|
2014-11-28 02:56:39 +01:00
|
|
|
const char *file,
|
2011-04-07 18:48:50 +02:00
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *buffer) {
|
2010-01-20 19:18:52 +01:00
|
|
|
|
2019-07-15 15:56:24 +02:00
|
|
|
char location[256],
|
|
|
|
header_time[FORMAT_TIMESTAMP_MAX],
|
2020-09-29 13:06:12 +02:00
|
|
|
prefix[1 + DECIMAL_STR_MAX(int) + 2],
|
|
|
|
tid_string[3 + DECIMAL_STR_MAX(pid_t) + 1];
|
|
|
|
struct iovec iovec[9];
|
2019-04-26 12:27:33 +02:00
|
|
|
const char *on = NULL, *off = NULL;
|
tree-wide: be more careful with the type of array sizes
Previously we were a bit sloppy with the index and size types of arrays,
we'd regularly use unsigned. While I don't think this ever resulted in
real issues I think we should be more careful there and follow a
stricter regime: unless there's a strong reason not to use size_t for
array sizes and indexes, size_t it should be. Any allocations we do
ultimately will use size_t anyway, and converting forth and back between
unsigned and size_t will always be a source of problems.
Note that on 32bit machines "unsigned" and "size_t" are equivalent, and
on 64bit machines our arrays shouldn't grow that large anyway, and if
they do we have a problem, however that kind of overly large allocation
we have protections for usually, but for overflows we do not have that
so much, hence let's add it.
So yeah, it's a story of the current code being already "good enough",
but I think some extra type hygiene is better.
This patch tries to be comprehensive, but it probably isn't and I missed
a few cases. But I guess we can cover that later as we notice it. Among
smaller fixes, this changes:
1. strv_length()' return type becomes size_t
2. the unit file changes array size becomes size_t
3. DNS answer and query array sizes become size_t
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=76745
2018-04-27 14:09:31 +02:00
|
|
|
size_t n = 0;
|
2010-01-20 19:18:52 +01:00
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
if (console_fd < 0)
|
|
|
|
return 0;
|
|
|
|
|
2015-01-22 03:47:46 +01:00
|
|
|
if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
|
2016-08-30 21:02:36 +02:00
|
|
|
xsprintf(prefix, "<%i>", level);
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(prefix);
|
2015-01-22 03:47:46 +01:00
|
|
|
}
|
|
|
|
|
2020-12-08 17:21:31 +01:00
|
|
|
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(" ");
|
2019-07-15 15:56:24 +02:00
|
|
|
}
|
|
|
|
|
2020-09-29 13:06:12 +02:00
|
|
|
if (show_tid) {
|
|
|
|
xsprintf(tid_string, "(" PID_FMT ") ", gettid());
|
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(tid_string);
|
|
|
|
}
|
|
|
|
|
2020-12-08 17:44:36 +01:00
|
|
|
if (log_get_show_color())
|
2019-04-26 12:27:33 +02:00
|
|
|
get_log_colors(LOG_PRI(level), &on, &off, NULL);
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2012-01-05 03:25:10 +01:00
|
|
|
if (show_location) {
|
2019-07-02 09:22:48 +02:00
|
|
|
const char *lon = "", *loff = "";
|
2020-12-08 17:44:36 +01:00
|
|
|
if (log_get_show_color()) {
|
2020-11-23 00:40:57 +01:00
|
|
|
lon = ansi_highlight_yellow4();
|
2019-07-02 09:22:48 +02:00
|
|
|
loff = ANSI_NORMAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) snprintf(location, sizeof location, "%s%s:%i%s: ", lon, file, line, loff);
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(location);
|
2012-01-05 03:25:10 +01:00
|
|
|
}
|
|
|
|
|
2019-04-26 12:27:33 +02:00
|
|
|
if (on)
|
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(on);
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(buffer);
|
2019-04-26 12:27:33 +02:00
|
|
|
if (off)
|
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(off);
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING("\n");
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2013-12-18 16:49:15 +01:00
|
|
|
if (writev(console_fd, iovec, n) < 0) {
|
|
|
|
|
2017-07-20 16:19:18 +02:00
|
|
|
if (errno == EIO && getpid_cached() == 1) {
|
2013-12-18 16:49:15 +01:00
|
|
|
|
2019-08-20 17:29:49 +02:00
|
|
|
/* If somebody tried to kick us from our console tty (via vhangup() or suchlike), try
|
|
|
|
* to reconnect. */
|
2013-12-18 16:49:15 +01:00
|
|
|
|
|
|
|
log_close_console();
|
2019-08-20 17:29:49 +02:00
|
|
|
(void) log_open_console();
|
2013-12-18 16:49:15 +01:00
|
|
|
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
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
return 1;
|
2010-04-06 21:57:45 +02:00
|
|
|
}
|
2010-01-20 19:18:52 +01:00
|
|
|
|
2010-04-06 21:57:45 +02:00
|
|
|
static int write_to_syslog(
|
2014-11-27 19:48:02 +01:00
|
|
|
int level,
|
|
|
|
int error,
|
2014-11-28 02:56:39 +01:00
|
|
|
const char *file,
|
2014-11-27 19:48:02 +01:00
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *buffer) {
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2015-01-27 14:00:11 +01:00
|
|
|
char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
|
|
|
|
header_time[64],
|
|
|
|
header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
|
2013-03-25 00:59:00 +01:00
|
|
|
struct iovec iovec[5] = {};
|
|
|
|
struct msghdr msghdr = {
|
|
|
|
.msg_iov = iovec,
|
|
|
|
.msg_iovlen = ELEMENTSOF(iovec),
|
|
|
|
};
|
2010-04-06 21:57:45 +02:00
|
|
|
time_t t;
|
2018-06-25 19:55:25 +02:00
|
|
|
struct tm tm;
|
2010-04-06 21:57:45 +02:00
|
|
|
|
|
|
|
if (syslog_fd < 0)
|
2010-05-15 17:25:08 +02:00
|
|
|
return 0;
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2015-01-27 14:00:11 +01:00
|
|
|
xsprintf(header_priority, "<%i>", level);
|
2010-04-06 21:57:45 +02:00
|
|
|
|
|
|
|
t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
|
2018-06-25 19:55:25 +02:00
|
|
|
if (!localtime_r(&t, &tm))
|
2010-04-06 21:57:45 +02:00
|
|
|
return -EINVAL;
|
|
|
|
|
2018-06-25 19:55:25 +02:00
|
|
|
if (strftime(header_time, sizeof(header_time), "%h %e %T ", &tm) <= 0)
|
2010-04-06 21:57:45 +02:00
|
|
|
return -EINVAL;
|
|
|
|
|
2017-07-20 16:19:18 +02:00
|
|
|
xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2017-09-21 13:52:34 +02:00
|
|
|
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-04-06 21:57:45 +02:00
|
|
|
|
2010-09-29 15:13:04 +02:00
|
|
|
/* When using syslog via SOCK_STREAM separate the messages by NUL chars */
|
2010-09-08 03:07:44 +02:00
|
|
|
if (syslog_is_stream)
|
|
|
|
iovec[4].iov_len++;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
ssize_t n;
|
|
|
|
|
2011-12-18 14:57:54 +01:00
|
|
|
n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
|
|
|
|
if (n < 0)
|
2010-09-08 03:07:44 +02:00
|
|
|
return -errno;
|
|
|
|
|
|
|
|
if (!syslog_is_stream ||
|
|
|
|
(size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
|
|
|
|
break;
|
|
|
|
|
|
|
|
IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
|
|
|
|
}
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
return 1;
|
2010-04-06 21:57:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int write_to_kmsg(
|
2014-11-27 19:48:02 +01:00
|
|
|
int level,
|
|
|
|
int error,
|
2015-11-05 13:44:03 +01:00
|
|
|
const char *file,
|
2014-11-27 19:48:02 +01:00
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *buffer) {
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2019-09-19 18:01:23 +02:00
|
|
|
/* 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 };
|
|
|
|
|
2015-01-27 14:00:11 +01:00
|
|
|
char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
|
|
|
|
header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
|
2013-03-25 00:59:00 +01:00
|
|
|
struct iovec iovec[5] = {};
|
2010-04-06 21:57:45 +02:00
|
|
|
|
|
|
|
if (kmsg_fd < 0)
|
2010-05-15 17:25:08 +02:00
|
|
|
return 0;
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2019-09-19 18:01:23 +02:00
|
|
|
if (!ratelimit_below(&ratelimit))
|
|
|
|
return 0;
|
|
|
|
|
2015-01-27 14:00:11 +01:00
|
|
|
xsprintf(header_priority, "<%i>", level);
|
2017-07-20 16:19:18 +02:00
|
|
|
xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2017-09-21 13:52:34 +02:00
|
|
|
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");
|
2010-04-06 21:57:45 +02:00
|
|
|
|
|
|
|
if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
|
|
|
|
return -errno;
|
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
return 1;
|
2010-04-06 21:57:45 +02:00
|
|
|
}
|
|
|
|
|
2014-11-27 19:48:02 +01:00
|
|
|
static int log_do_header(
|
|
|
|
char *header,
|
|
|
|
size_t size,
|
|
|
|
int level,
|
|
|
|
int error,
|
|
|
|
const char *file, int line, const char *func,
|
2016-08-30 23:18:46 +02:00
|
|
|
const char *object_field, const char *object,
|
|
|
|
const char *extra_field, const char *extra) {
|
basic/log: make sure header is printed correctly, add test
If log_do_header() was called with overly long parameters, it'd generate
improper output. Essentially, it'd be truncated at random point, in particular
missing a newline at the end, so it'd run with the next field, usually MESSAGE=.
log_do_header is called with parameters from compiled code (file name, lien
nubmer, etc), so in practice this was unlikely to ever be a problem, but it is
possible. In particular, if systemd was compiled from sources in some deeply
nested directory (which happens for example in mock and other build roots), the
filename could be very long.
As a safety measure, let's truncate all parameters to 256 bytes. So we have
5 fields which are 256 bytes (plus the field name prefix), and a few other
fields with fixed width. This must always fit in the 2048 byte buffer.
I don't think there's much gain in calculating the required length precisely,
since it's a lot of fields and a few bytes allocated on the stack don't matter.
2018-02-22 23:55:14 +01:00
|
|
|
int r;
|
2014-11-27 19:48:02 +01:00
|
|
|
|
2018-11-20 23:03:40 +01:00
|
|
|
error = IS_SYNTHETIC_ERRNO(error) ? 0 : ERRNO_VALUE(error);
|
|
|
|
|
basic/log: make sure header is printed correctly, add test
If log_do_header() was called with overly long parameters, it'd generate
improper output. Essentially, it'd be truncated at random point, in particular
missing a newline at the end, so it'd run with the next field, usually MESSAGE=.
log_do_header is called with parameters from compiled code (file name, lien
nubmer, etc), so in practice this was unlikely to ever be a problem, but it is
possible. In particular, if systemd was compiled from sources in some deeply
nested directory (which happens for example in mock and other build roots), the
filename could be very long.
As a safety measure, let's truncate all parameters to 256 bytes. So we have
5 fields which are 256 bytes (plus the field name prefix), and a few other
fields with fixed width. This must always fit in the 2048 byte buffer.
I don't think there's much gain in calculating the required length precisely,
since it's a lot of fields and a few bytes allocated on the stack don't matter.
2018-02-22 23:55:14 +01:00
|
|
|
r = snprintf(header, size,
|
|
|
|
"PRIORITY=%i\n"
|
|
|
|
"SYSLOG_FACILITY=%i\n"
|
2020-09-29 13:07:07 +02:00
|
|
|
"TID=" PID_FMT "\n"
|
basic/log: make sure header is printed correctly, add test
If log_do_header() was called with overly long parameters, it'd generate
improper output. Essentially, it'd be truncated at random point, in particular
missing a newline at the end, so it'd run with the next field, usually MESSAGE=.
log_do_header is called with parameters from compiled code (file name, lien
nubmer, etc), so in practice this was unlikely to ever be a problem, but it is
possible. In particular, if systemd was compiled from sources in some deeply
nested directory (which happens for example in mock and other build roots), the
filename could be very long.
As a safety measure, let's truncate all parameters to 256 bytes. So we have
5 fields which are 256 bytes (plus the field name prefix), and a few other
fields with fixed width. This must always fit in the 2048 byte buffer.
I don't think there's much gain in calculating the required length precisely,
since it's a lot of fields and a few bytes allocated on the stack don't matter.
2018-02-22 23:55:14 +01:00
|
|
|
"%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),
|
2020-09-29 13:07:07 +02:00
|
|
|
gettid(),
|
basic/log: make sure header is printed correctly, add test
If log_do_header() was called with overly long parameters, it'd generate
improper output. Essentially, it'd be truncated at random point, in particular
missing a newline at the end, so it'd run with the next field, usually MESSAGE=.
log_do_header is called with parameters from compiled code (file name, lien
nubmer, etc), so in practice this was unlikely to ever be a problem, but it is
possible. In particular, if systemd was compiled from sources in some deeply
nested directory (which happens for example in mock and other build roots), the
filename could be very long.
As a safety measure, let's truncate all parameters to 256 bytes. So we have
5 fields which are 256 bytes (plus the field name prefix), and a few other
fields with fixed width. This must always fit in the 2048 byte buffer.
I don't think there's much gain in calculating the required length precisely,
since it's a lot of fields and a few bytes allocated on the stack don't matter.
2018-02-22 23:55:14 +01:00
|
|
|
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);
|
2018-02-23 13:29:03 +01:00
|
|
|
assert_raw((size_t) r < size);
|
2014-11-27 19:48:02 +01:00
|
|
|
|
2012-11-26 16:39:46 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2012-01-12 04:34:31 +01:00
|
|
|
|
2012-11-26 16:39:46 +01:00
|
|
|
static int write_to_journal(
|
2014-11-27 19:48:02 +01:00
|
|
|
int level,
|
|
|
|
int error,
|
2015-11-05 13:44:03 +01:00
|
|
|
const char *file,
|
2014-11-27 19:48:02 +01:00
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *object_field,
|
|
|
|
const char *object,
|
2016-08-30 23:18:46 +02:00
|
|
|
const char *extra_field,
|
|
|
|
const char *extra,
|
2014-11-27 19:48:02 +01:00
|
|
|
const char *buffer) {
|
2012-11-26 16:39:46 +01:00
|
|
|
|
|
|
|
char header[LINE_MAX];
|
2013-03-25 00:59:00 +01:00
|
|
|
struct iovec iovec[4] = {};
|
|
|
|
struct msghdr mh = {};
|
2012-11-26 16:39:46 +01:00
|
|
|
|
|
|
|
if (journal_fd < 0)
|
|
|
|
return 0;
|
|
|
|
|
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);
|
2012-01-12 04:34:31 +01:00
|
|
|
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[0] = IOVEC_MAKE_STRING(header);
|
|
|
|
iovec[1] = IOVEC_MAKE_STRING("MESSAGE=");
|
|
|
|
iovec[2] = IOVEC_MAKE_STRING(buffer);
|
|
|
|
iovec[3] = IOVEC_MAKE_STRING("\n");
|
2012-01-12 04:34:31 +01:00
|
|
|
|
|
|
|
mh.msg_iov = iovec;
|
|
|
|
mh.msg_iovlen = ELEMENTSOF(iovec);
|
|
|
|
|
|
|
|
if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-04-21 18:52:54 +02:00
|
|
|
int log_dispatch_internal(
|
2014-11-27 19:48:02 +01:00
|
|
|
int level,
|
|
|
|
int error,
|
2014-11-28 02:56:39 +01:00
|
|
|
const char *file,
|
2014-11-27 19:48:02 +01:00
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *object_field,
|
|
|
|
const char *object,
|
2016-08-30 23:18:46 +02:00
|
|
|
const char *extra_field,
|
2018-02-22 23:45:27 +01:00
|
|
|
const char *extra,
|
2014-11-27 19:48:02 +01:00
|
|
|
char *buffer) {
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2018-02-23 13:29:03 +01:00
|
|
|
assert_raw(buffer);
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2010-06-09 15:37:37 +02:00
|
|
|
if (log_target == LOG_TARGET_NULL)
|
2018-11-20 23:03:40 +01:00
|
|
|
return -ERRNO_VALUE(error);
|
2010-06-09 15:37:37 +02:00
|
|
|
|
2011-03-31 19:49:04 +02:00
|
|
|
/* Patch in LOG_DAEMON facility if necessary */
|
2011-03-31 21:22:44 +02:00
|
|
|
if ((level & LOG_FACMASK) == 0)
|
2018-11-20 23:03:40 +01:00
|
|
|
level |= log_facility;
|
2011-03-31 19:49:04 +02:00
|
|
|
|
2017-09-26 17:45:09 +02:00
|
|
|
if (open_when_needed)
|
2019-08-20 17:29:49 +02:00
|
|
|
(void) log_open();
|
2017-09-26 17:45:09 +02:00
|
|
|
|
2010-05-21 03:31:49 +02:00
|
|
|
do {
|
|
|
|
char *e;
|
2010-08-17 03:31:45 +02:00
|
|
|
int k = 0;
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2010-05-21 03:31:49 +02:00
|
|
|
buffer += strspn(buffer, NEWLINE);
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2010-05-21 03:31:49 +02:00
|
|
|
if (buffer[0] == 0)
|
|
|
|
break;
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2010-05-21 03:31:49 +02:00
|
|
|
if ((e = strpbrk(buffer, NEWLINE)))
|
|
|
|
*(e++) = 0;
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2016-12-18 01:55:43 +01:00
|
|
|
if (IN_SET(log_target, LOG_TARGET_AUTO,
|
|
|
|
LOG_TARGET_JOURNAL_OR_KMSG,
|
|
|
|
LOG_TARGET_JOURNAL)) {
|
2012-01-12 04:34:31 +01:00
|
|
|
|
2016-08-30 23:18:46 +02:00
|
|
|
k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
|
2018-02-22 00:31:36 +01:00
|
|
|
if (k < 0 && k != -EAGAIN)
|
|
|
|
log_close_journal();
|
2012-01-12 04:34:31 +01:00
|
|
|
}
|
|
|
|
|
2016-12-18 01:55:43 +01:00
|
|
|
if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
|
|
|
|
LOG_TARGET_SYSLOG)) {
|
2010-05-21 03:31:49 +02:00
|
|
|
|
2016-08-30 23:18:46 +02:00
|
|
|
k = write_to_syslog(level, error, file, line, func, buffer);
|
2018-02-22 00:31:36 +01:00
|
|
|
if (k < 0 && k != -EAGAIN)
|
|
|
|
log_close_syslog();
|
2010-05-21 03:31:49 +02:00
|
|
|
}
|
|
|
|
|
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)) {
|
2010-05-21 03:31:49 +02:00
|
|
|
|
2018-02-22 00:31:36 +01:00
|
|
|
if (k < 0)
|
|
|
|
log_open_kmsg();
|
|
|
|
|
2016-08-30 23:18:46 +02:00
|
|
|
k = write_to_kmsg(level, error, file, line, func, buffer);
|
2013-02-27 14:33:50 +01:00
|
|
|
if (k < 0) {
|
|
|
|
log_close_kmsg();
|
2019-08-20 17:29:49 +02:00
|
|
|
(void) log_open_console();
|
2014-11-28 03:10:55 +01:00
|
|
|
}
|
2010-05-21 03:31:49 +02:00
|
|
|
}
|
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
if (k <= 0)
|
2016-08-30 23:18:46 +02:00
|
|
|
(void) write_to_console(level, error, file, line, func, buffer);
|
2010-05-21 03:31:49 +02:00
|
|
|
|
|
|
|
buffer = e;
|
|
|
|
} while (buffer);
|
|
|
|
|
2017-09-26 17:45:09 +02:00
|
|
|
if (open_when_needed)
|
|
|
|
log_close();
|
|
|
|
|
2018-11-20 23:03:40 +01:00
|
|
|
return -ERRNO_VALUE(error);
|
2010-05-15 17:25:08 +02:00
|
|
|
}
|
|
|
|
|
2010-06-04 19:45:53 +02:00
|
|
|
int log_dump_internal(
|
2017-02-23 04:57:34 +01:00
|
|
|
int level,
|
|
|
|
int error,
|
|
|
|
const char *file,
|
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
char *buffer) {
|
2010-06-04 19:45:53 +02:00
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
|
2013-04-02 16:31:55 +02:00
|
|
|
PROTECT_ERRNO;
|
2010-06-04 19:45:53 +02:00
|
|
|
|
|
|
|
/* This modifies the buffer... */
|
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level[realm]))
|
2018-11-20 23:03:40 +01:00
|
|
|
return -ERRNO_VALUE(error);
|
2010-06-04 19:45:53 +02:00
|
|
|
|
2017-04-21 18:52:54 +02:00
|
|
|
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
|
2010-06-04 19:45:53 +02:00
|
|
|
}
|
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
int log_internalv_realm(
|
2014-11-27 19:48:02 +01:00
|
|
|
int level,
|
|
|
|
int error,
|
2015-11-05 13:44:03 +01:00
|
|
|
const char *file,
|
2014-11-27 19:48:02 +01:00
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *format,
|
|
|
|
va_list ap) {
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
|
2010-08-21 03:57:47 +02:00
|
|
|
char buffer[LINE_MAX];
|
2017-02-23 04:57:34 +01:00
|
|
|
PROTECT_ERRNO;
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level[realm]))
|
2018-11-20 23:03:40 +01:00
|
|
|
return -ERRNO_VALUE(error);
|
2010-04-06 21:57:45 +02:00
|
|
|
|
basic/log: do not use global errno in log_*_errno()
Quoting https://github.com/systemd/systemd/pull/8760#discussion_r183321060:
> When we originally added the errno patching we went for a "best of both
> worlds" approach, i.e. that we override errno if an error is specified, but
> if no error is specified (i.e. 0 is passed as error code) then we use the
> previously set errno, similar in style how plain `printf()` would do it. In
> retrospect I think we almost never purposefully made use of the second,
> i.e. the plain `printf()` logic, but we multiple times ran into this case
> accidentally and introduced a bug. Hence yes, it probably makes sense to
> switch this over, and consistently ignore the `errno` already set and always
> override it with the error passed in. The only problem I see with that is: I
> wonder if there might be a case or two lurking somewhere where we actually
> made use of the "best of both worlds" approach, and if so, if we can detect
> where... (But then again, even if there is, and we fail to find those cases,
> maybe that's not all bad, as it's just a few new bugs against probably fixing
> many more old and future bugs, if you follow what I mean).
I scanned our codebase, and found some bugs in the value passed to log_*_errno,
but no intentional cases of error=0 being passed.
2018-04-24 13:57:38 +02:00
|
|
|
/* Make sure that %m maps to the specified error (or "Success"). */
|
2018-11-20 23:03:40 +01:00
|
|
|
errno = ERRNO_VALUE(error);
|
2014-11-27 19:48:02 +01:00
|
|
|
|
2018-02-22 22:09:16 +01:00
|
|
|
(void) vsnprintf(buffer, sizeof buffer, format, ap);
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2017-04-21 18:52:54 +02:00
|
|
|
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
|
2010-04-22 03:51:26 +02:00
|
|
|
}
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
int log_internal_realm(
|
2014-11-27 19:48:02 +01:00
|
|
|
int level,
|
|
|
|
int error,
|
2015-11-05 13:44:03 +01:00
|
|
|
const char *file,
|
2014-11-27 19:48:02 +01:00
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *format, ...) {
|
2012-03-14 14:54:41 +01:00
|
|
|
|
|
|
|
va_list ap;
|
2014-11-28 03:10:55 +01:00
|
|
|
int r;
|
2012-03-14 14:54:41 +01:00
|
|
|
|
|
|
|
va_start(ap, format);
|
2017-02-23 04:57:34 +01:00
|
|
|
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(
|
2014-11-27 19:48:02 +01:00
|
|
|
int level,
|
|
|
|
int error,
|
2015-11-05 13:44:03 +01:00
|
|
|
const char *file,
|
2014-11-27 19:48:02 +01:00
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *object_field,
|
|
|
|
const char *object,
|
2016-08-30 23:18:46 +02:00
|
|
|
const char *extra_field,
|
|
|
|
const char *extra,
|
2014-11-27 19:48:02 +01:00
|
|
|
const char *format,
|
|
|
|
va_list ap) {
|
2013-01-05 17:59:46 +01:00
|
|
|
|
2013-04-02 16:31:55 +02:00
|
|
|
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;
|
2013-01-05 17:59:46 +01:00
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
|
2018-11-20 23:03:40 +01:00
|
|
|
return -ERRNO_VALUE(error);
|
2013-01-05 17:59:46 +01:00
|
|
|
|
2018-04-27 18:00:58 +02:00
|
|
|
/* Make sure that %m maps to the specified error (or "Success"). */
|
2018-11-20 23:03:40 +01:00
|
|
|
errno = ERRNO_VALUE(error);
|
2014-11-27 19:48:02 +01:00
|
|
|
|
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);
|
2017-06-22 03:10:29 +02:00
|
|
|
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), ": ");
|
2017-06-22 03:10:29 +02:00
|
|
|
} 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
|
|
|
|
2018-02-22 22:09:16 +01:00
|
|
|
(void) vsnprintf(b, LINE_MAX, format, ap);
|
2013-01-05 17:59:46 +01:00
|
|
|
|
2017-04-21 18:52:54 +02:00
|
|
|
return log_dispatch_internal(level, error, file, line, func,
|
|
|
|
object_field, object, extra_field, extra, buffer);
|
2013-01-05 17:59:46 +01:00
|
|
|
}
|
|
|
|
|
2014-11-27 20:20:23 +01:00
|
|
|
int log_object_internal(
|
2014-11-27 19:48:02 +01:00
|
|
|
int level,
|
|
|
|
int error,
|
2015-11-05 13:44:03 +01:00
|
|
|
const char *file,
|
2014-11-27 19:48:02 +01:00
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *object_field,
|
|
|
|
const char *object,
|
2016-08-30 23:18:46 +02:00
|
|
|
const char *extra_field,
|
|
|
|
const char *extra,
|
2014-11-27 19:48:02 +01:00
|
|
|
const char *format, ...) {
|
2013-01-05 17:59:46 +01:00
|
|
|
|
|
|
|
va_list ap;
|
2014-11-28 03:10:55 +01:00
|
|
|
int r;
|
2013-01-05 17:59:46 +01:00
|
|
|
|
|
|
|
va_start(ap, format);
|
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);
|
2013-01-05 17:59:46 +01:00
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-11-27 19:48:02 +01:00
|
|
|
static void log_assert(
|
|
|
|
int level,
|
|
|
|
const char *text,
|
|
|
|
const char *file,
|
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *format) {
|
|
|
|
|
2010-08-21 03:57:47 +02:00
|
|
|
static char buffer[LINE_MAX];
|
2017-02-23 04:57:34 +01:00
|
|
|
LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
|
2010-04-22 03:51:26 +02:00
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level[realm]))
|
2013-12-12 02:34:19 +01:00
|
|
|
return;
|
|
|
|
|
2014-02-20 18:18:32 +01:00
|
|
|
DISABLE_WARNING_FORMAT_NONLITERAL;
|
2018-02-22 22:09:16 +01:00
|
|
|
(void) snprintf(buffer, sizeof buffer, format, text, file, line, func);
|
2014-02-20 18:18:32 +01:00
|
|
|
REENABLE_WARNING;
|
2010-04-22 03:51:26 +02:00
|
|
|
|
|
|
|
log_abort_msg = buffer;
|
|
|
|
|
2017-04-21 18:52:54 +02:00
|
|
|
log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
|
2010-01-20 19:18:52 +01:00
|
|
|
}
|
2010-04-06 23:38:32 +02:00
|
|
|
|
2018-03-15 06:23:46 +01:00
|
|
|
_noreturn_ void log_assert_failed_realm(
|
2017-02-23 04:57:34 +01:00
|
|
|
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.");
|
2013-12-10 18:01:10 +01:00
|
|
|
abort();
|
2012-01-17 12:05:33 +01:00
|
|
|
}
|
|
|
|
|
2018-03-15 06:23:46 +01:00
|
|
|
_noreturn_ void log_assert_failed_unreachable_realm(
|
2017-02-23 04:57:34 +01:00
|
|
|
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.");
|
2013-12-10 18:01:10 +01:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
void log_assert_failed_return_realm(
|
|
|
|
LogRealm realm,
|
|
|
|
const char *text,
|
|
|
|
const char *file,
|
|
|
|
int line,
|
|
|
|
const char *func) {
|
2013-12-12 15:58:49 +01:00
|
|
|
PROTECT_ERRNO;
|
2017-02-23 04:57:34 +01:00
|
|
|
log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_DEBUG), text, file, line, func,
|
|
|
|
"Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
|
2012-01-17 12:05:33 +01:00
|
|
|
}
|
|
|
|
|
2020-12-11 07:41:04 +01:00
|
|
|
int log_oom_internal(int level, const char *file, int line, const char *func) {
|
|
|
|
return log_internal_realm(level, ENOMEM, file, line, func, "Out of memory.");
|
2012-07-26 14:23:49 +02:00
|
|
|
}
|
|
|
|
|
2015-11-08 20:05:55 +01:00
|
|
|
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,
|
2015-11-08 20:05:55 +01:00
|
|
|
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 */
|
|
|
|
|
2018-11-20 23:03:40 +01:00
|
|
|
errno = ERRNO_VALUE(error);
|
2015-11-08 20:05:55 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[(*n)++] = IOVEC_MAKE_STRING(m);
|
2015-11-08 20:05:55 +01:00
|
|
|
|
|
|
|
if (newline_separator) {
|
2018-11-26 21:52:36 +01:00
|
|
|
iovec[*n] = IOVEC_MAKE((char *)&nl, 1);
|
2015-11-08 20:05:55 +01:00
|
|
|
(*n)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
format = va_arg(ap, char *);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-24 22:21:20 +02:00
|
|
|
int log_struct_internal(
|
|
|
|
int level,
|
2014-11-27 19:48:02 +01:00
|
|
|
int error,
|
2012-08-24 22:21:20 +02:00
|
|
|
const char *file,
|
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
const char *format, ...) {
|
|
|
|
|
2017-09-21 13:52:34 +02:00
|
|
|
LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
|
2014-11-28 03:10:55 +01:00
|
|
|
char buf[LINE_MAX];
|
|
|
|
bool found = false;
|
2013-04-02 16:31:55 +02:00
|
|
|
PROTECT_ERRNO;
|
2012-08-24 22:21:20 +02:00
|
|
|
va_list ap;
|
2014-11-28 03:10:55 +01:00
|
|
|
|
2018-11-20 23:03:40 +01:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level[realm]) ||
|
|
|
|
log_target == LOG_TARGET_NULL)
|
|
|
|
return -ERRNO_VALUE(error);
|
2012-08-24 22:21:20 +02:00
|
|
|
|
|
|
|
if ((level & LOG_FACMASK) == 0)
|
2018-11-20 23:03:40 +01:00
|
|
|
level |= log_facility;
|
2012-08-24 22:21:20 +02:00
|
|
|
|
2017-09-26 17:45:09 +02:00
|
|
|
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;
|
2017-09-26 17:45:09 +02:00
|
|
|
int r;
|
|
|
|
struct msghdr mh = {
|
|
|
|
.msg_iov = iovec,
|
|
|
|
};
|
|
|
|
bool fallback = false;
|
|
|
|
|
2018-11-20 23:03:40 +01:00
|
|
|
/* If the journal is available do structured logging.
|
|
|
|
* Do not report the errno if it is synthetic. */
|
2017-09-26 17:45:09 +02:00
|
|
|
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);
|
|
|
|
}
|
2012-08-24 22:21:20 +02:00
|
|
|
|
2017-09-26 17:45:09 +02:00
|
|
|
va_end(ap);
|
|
|
|
for (i = 1; i < n; i += 2)
|
|
|
|
free(iovec[i].iov_base);
|
2012-08-24 22:21:20 +02:00
|
|
|
|
2017-09-26 17:45:09 +02:00
|
|
|
if (!fallback) {
|
|
|
|
if (open_when_needed)
|
|
|
|
log_close();
|
2012-08-24 22:21:20 +02:00
|
|
|
|
2018-11-20 23:03:40 +01:00
|
|
|
return -ERRNO_VALUE(error);
|
2017-09-26 17:45:09 +02:00
|
|
|
}
|
|
|
|
}
|
2014-11-28 03:10:55 +01:00
|
|
|
}
|
2012-08-24 22:21:20 +02:00
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
/* Fallback if journal logging is not available or didn't work. */
|
2014-11-28 02:30:49 +01:00
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
va_start(ap, format);
|
|
|
|
while (format) {
|
|
|
|
va_list aq;
|
2012-08-24 22:21:20 +02:00
|
|
|
|
2018-11-20 23:03:40 +01:00
|
|
|
errno = ERRNO_VALUE(error);
|
2012-08-24 22:21:20 +02:00
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
va_copy(aq, ap);
|
2018-02-22 22:09:16 +01:00
|
|
|
(void) vsnprintf(buf, sizeof buf, format, aq);
|
2014-11-28 03:10:55 +01:00
|
|
|
va_end(aq);
|
2012-09-24 23:22:19 +02:00
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
if (startswith(buf, "MESSAGE=")) {
|
|
|
|
found = true;
|
|
|
|
break;
|
2012-08-24 22:21:20 +02:00
|
|
|
}
|
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
VA_FORMAT_ADVANCE(format, ap);
|
|
|
|
|
|
|
|
format = va_arg(ap, char *);
|
2012-08-24 22:21:20 +02:00
|
|
|
}
|
2014-11-28 03:10:55 +01:00
|
|
|
va_end(ap);
|
2012-08-24 22:21:20 +02:00
|
|
|
|
2017-09-26 17:45:09 +02:00
|
|
|
if (!found) {
|
|
|
|
if (open_when_needed)
|
|
|
|
log_close();
|
|
|
|
|
2018-11-20 23:03:40 +01:00
|
|
|
return -ERRNO_VALUE(error);
|
2017-09-26 17:45:09 +02:00
|
|
|
}
|
2014-11-28 03:10:55 +01:00
|
|
|
|
2017-04-21 18:52:54 +02:00
|
|
|
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
|
2012-08-24 22:21:20 +02:00
|
|
|
}
|
|
|
|
|
2017-09-21 14:05:35 +02:00
|
|
|
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;
|
|
|
|
|
2018-11-20 23:03:40 +01:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level[realm]) ||
|
|
|
|
log_target == LOG_TARGET_NULL)
|
|
|
|
return -ERRNO_VALUE(error);
|
2017-09-21 14:05:35 +02:00
|
|
|
|
|
|
|
if ((level & LOG_FACMASK) == 0)
|
2018-11-20 23:03:40 +01:00
|
|
|
level |= log_facility;
|
2017-09-21 14:05:35 +02:00
|
|
|
|
|
|
|
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)
|
2018-11-20 23:03:40 +01:00
|
|
|
return -ERRNO_VALUE(error);
|
2017-09-21 14:05:35 +02:00
|
|
|
}
|
|
|
|
|
2018-05-30 13:09:03 +02:00
|
|
|
for (i = 0; i < n_input_iovec; i++)
|
|
|
|
if (memory_startswith(input_iovec[i].iov_base, input_iovec[i].iov_len, "MESSAGE="))
|
2017-09-21 14:05:35 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */
|
2018-11-20 23:03:40 +01:00
|
|
|
return -ERRNO_VALUE(error);
|
2017-09-21 14:05:35 +02:00
|
|
|
|
2017-12-14 19:02:29 +01:00
|
|
|
m = strndupa(input_iovec[i].iov_base + STRLEN("MESSAGE="),
|
|
|
|
input_iovec[i].iov_len - STRLEN("MESSAGE="));
|
2017-09-21 14:05:35 +02:00
|
|
|
|
|
|
|
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m);
|
|
|
|
}
|
|
|
|
|
2010-04-06 23:38:32 +02:00
|
|
|
int log_set_target_from_string(const char *e) {
|
|
|
|
LogTarget t;
|
|
|
|
|
2012-01-12 04:34:31 +01:00
|
|
|
t = log_target_from_string(e);
|
|
|
|
if (t < 0)
|
2010-04-06 23:38:32 +02:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
log_set_target(t);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
int log_set_max_level_from_string_realm(LogRealm realm, const char *e) {
|
2010-04-06 23:38:32 +02:00
|
|
|
int t;
|
|
|
|
|
2012-01-12 04:34:31 +01:00
|
|
|
t = log_level_from_string(e);
|
|
|
|
if (t < 0)
|
2015-09-30 14:16:40 +02:00
|
|
|
return -EINVAL;
|
2010-04-06 23:38:32 +02:00
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
log_set_max_level_realm(realm, t);
|
2010-04-06 23:38:32 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-22 20:24:52 +02:00
|
|
|
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
2014-08-15 18:07:36 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The systemd.log_xyz= settings are parsed by all tools, and
|
|
|
|
* so is "debug".
|
|
|
|
*
|
2015-02-04 01:42:49 +01:00
|
|
|
* However, "quiet" is only parsed by PID 1, and only turns of
|
|
|
|
* status output to /dev/console, but does not alter the log
|
|
|
|
* level.
|
2014-08-15 18:07:36 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
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;
|
2014-08-15 18:07:36 +02:00
|
|
|
|
|
|
|
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;
|
2014-08-15 18:07:36 +02:00
|
|
|
|
|
|
|
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")) {
|
2014-08-15 18:07:36 +02:00
|
|
|
|
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)
|
2014-08-15 18:07:36 +02:00
|
|
|
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")) {
|
2014-08-15 18:07:36 +02:00
|
|
|
|
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)
|
2014-08-15 18:07:36 +02:00
|
|
|
log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
|
2019-07-15 15:56:24 +02:00
|
|
|
|
2020-09-29 13:06:12 +02:00
|
|
|
} 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);
|
|
|
|
|
2019-07-15 15:56:24 +02:00
|
|
|
} 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);
|
|
|
|
|
2014-08-15 18:07:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
void log_parse_environment_realm(LogRealm realm) {
|
2019-07-18 17:13:09 +02:00
|
|
|
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);
|
2010-04-06 23:38:32 +02:00
|
|
|
|
2020-06-17 21:17:54 +02:00
|
|
|
log_parse_environment_cli_realm(realm);
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_parse_environment_cli_realm(LogRealm realm) {
|
|
|
|
/* Do not call from library code. */
|
|
|
|
|
|
|
|
const char *e;
|
|
|
|
|
2017-07-05 05:54:00 +02:00
|
|
|
e = getenv("SYSTEMD_LOG_TARGET");
|
2012-08-23 18:47:01 +02:00
|
|
|
if (e && log_set_target_from_string(e) < 0)
|
2014-07-21 01:47:42 +02:00
|
|
|
log_warning("Failed to parse log target '%s'. Ignoring.", e);
|
2010-04-06 23:38:32 +02:00
|
|
|
|
2017-07-05 05:54:00 +02:00
|
|
|
e = getenv("SYSTEMD_LOG_LEVEL");
|
2017-02-23 04:57:34 +01:00
|
|
|
if (e && log_set_max_level_from_string_realm(realm, e) < 0)
|
2014-07-21 01:47:42 +02:00
|
|
|
log_warning("Failed to parse log level '%s'. Ignoring.", e);
|
2010-06-17 22:52:55 +02:00
|
|
|
|
2017-07-05 05:54:00 +02:00
|
|
|
e = getenv("SYSTEMD_LOG_COLOR");
|
2012-08-23 18:47:01 +02:00
|
|
|
if (e && log_show_color_from_string(e) < 0)
|
2019-07-06 12:47:06 +02:00
|
|
|
log_warning("Failed to parse log color '%s'. Ignoring.", e);
|
2010-06-17 22:52:55 +02:00
|
|
|
|
2017-07-05 05:54:00 +02:00
|
|
|
e = getenv("SYSTEMD_LOG_LOCATION");
|
2012-08-23 18:47:01 +02:00
|
|
|
if (e && log_show_location_from_string(e) < 0)
|
2019-07-06 12:47:06 +02:00
|
|
|
log_warning("Failed to parse log location '%s'. Ignoring.", e);
|
2019-07-15 15:56:24 +02:00
|
|
|
|
|
|
|
e = getenv("SYSTEMD_LOG_TIME");
|
|
|
|
if (e && log_show_time_from_string(e) < 0)
|
|
|
|
log_warning("Failed to parse log time '%s'. Ignoring.", e);
|
2020-09-29 13:06:12 +02:00
|
|
|
|
|
|
|
e = getenv("SYSTEMD_LOG_TID");
|
|
|
|
if (e && log_show_tid_from_string(e) < 0)
|
|
|
|
log_warning("Failed to parse log tid '%s'. Ignoring.", e);
|
2010-04-06 23:38:32 +02:00
|
|
|
}
|
|
|
|
|
2010-04-10 17:40:18 +02:00
|
|
|
LogTarget log_get_target(void) {
|
|
|
|
return log_target;
|
|
|
|
}
|
|
|
|
|
2017-02-23 04:57:34 +01:00
|
|
|
int log_get_max_level_realm(LogRealm realm) {
|
|
|
|
return log_max_level[realm];
|
2010-04-10 17:40:18 +02:00
|
|
|
}
|
|
|
|
|
2010-06-17 22:52:55 +02:00
|
|
|
void log_show_color(bool b) {
|
|
|
|
show_color = b;
|
|
|
|
}
|
|
|
|
|
2014-02-16 00:13:46 +01:00
|
|
|
bool log_get_show_color(void) {
|
2020-12-08 17:44:36 +01:00
|
|
|
return show_color > 0; /* Defaults to false. */
|
2014-02-16 00:13:46 +01:00
|
|
|
}
|
|
|
|
|
2010-06-17 22:52:55 +02:00
|
|
|
void log_show_location(bool b) {
|
|
|
|
show_location = b;
|
|
|
|
}
|
|
|
|
|
2014-02-16 00:13:46 +01:00
|
|
|
bool log_get_show_location(void) {
|
|
|
|
return show_location;
|
|
|
|
}
|
|
|
|
|
2019-07-15 15:56:24 +02:00
|
|
|
void log_show_time(bool b) {
|
|
|
|
show_time = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool log_get_show_time(void) {
|
|
|
|
return show_time;
|
|
|
|
}
|
|
|
|
|
2020-09-29 13:06:12 +02:00
|
|
|
void log_show_tid(bool b) {
|
|
|
|
show_tid = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool log_get_show_tid(void) {
|
|
|
|
return show_tid;
|
|
|
|
}
|
|
|
|
|
2010-06-17 22:52:55 +02:00
|
|
|
int log_show_color_from_string(const char *e) {
|
|
|
|
int t;
|
|
|
|
|
2012-01-12 04:34:31 +01:00
|
|
|
t = parse_boolean(e);
|
|
|
|
if (t < 0)
|
|
|
|
return t;
|
2010-06-17 22:52:55 +02:00
|
|
|
|
|
|
|
log_show_color(t);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int log_show_location_from_string(const char *e) {
|
|
|
|
int t;
|
|
|
|
|
2012-01-12 04:34:31 +01:00
|
|
|
t = parse_boolean(e);
|
|
|
|
if (t < 0)
|
|
|
|
return t;
|
2010-06-17 22:52:55 +02:00
|
|
|
|
|
|
|
log_show_location(t);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-15 15:56:24 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-09-29 13:06:12 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-08-24 22:43:33 +02:00
|
|
|
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))
|
2012-08-24 22:43:33 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
|
|
|
|
}
|
|
|
|
|
2014-03-07 21:38:48 +01:00
|
|
|
static const char *const log_target_table[_LOG_TARGET_MAX] = {
|
2010-04-06 23:38:32 +02:00
|
|
|
[LOG_TARGET_CONSOLE] = "console",
|
2015-01-22 03:47:46 +01:00
|
|
|
[LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed",
|
2010-04-06 23:38:32 +02:00
|
|
|
[LOG_TARGET_KMSG] = "kmsg",
|
2012-01-12 04:34:31 +01:00
|
|
|
[LOG_TARGET_JOURNAL] = "journal",
|
|
|
|
[LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
|
|
|
|
[LOG_TARGET_SYSLOG] = "syslog",
|
2010-05-15 17:25:08 +02:00
|
|
|
[LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
|
2012-01-12 04:34:31 +01:00
|
|
|
[LOG_TARGET_AUTO] = "auto",
|
2018-01-24 18:01:01 +01:00
|
|
|
[LOG_TARGET_NULL] = "null",
|
2010-04-06 23:38:32 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
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) {
|
2018-01-11 13:09:30 +01:00
|
|
|
assert(si);
|
|
|
|
|
|
|
|
if (pid_is_valid(si->ssi_pid)) {
|
2014-02-10 02:08:55 +01:00
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
|
2018-01-11 13:09:30 +01:00
|
|
|
(void) get_process_comm(si->ssi_pid, &p);
|
2014-02-10 02:08:55 +01:00
|
|
|
|
|
|
|
log_full(level,
|
2015-01-21 04:22:15 +01:00
|
|
|
"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));
|
|
|
|
}
|
2014-08-11 20:08:08 +02:00
|
|
|
|
2015-04-21 17:26:04 +02:00
|
|
|
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;
|
2016-12-11 20:34:45 +01:00
|
|
|
const char *unit_fmt = NULL;
|
2015-04-21 17:26:04 +02:00
|
|
|
|
2018-11-20 23:03:40 +01:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]) ||
|
|
|
|
log_target == LOG_TARGET_NULL)
|
|
|
|
return -ERRNO_VALUE(error);
|
2015-04-21 17:26:04 +02:00
|
|
|
|
2019-03-04 07:18:06 +01:00
|
|
|
errno = ERRNO_VALUE(error);
|
2015-04-21 17:26:04 +02:00
|
|
|
|
|
|
|
va_start(ap, format);
|
2018-02-22 22:09:16 +01:00
|
|
|
(void) vsnprintf(buffer, sizeof buffer, format, ap);
|
2015-04-21 17:26:04 +02:00
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
if (unit)
|
2017-07-20 16:19:18 +02:00
|
|
|
unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
|
2016-12-11 20:34:45 +01:00
|
|
|
|
2019-07-01 16:37:10 +02:00
|
|
|
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)
|
2019-04-03 09:13:37 +02:00
|
|
|
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);
|
2015-04-21 17:26:04 +02:00
|
|
|
}
|
2017-02-21 17:57:55 +01:00
|
|
|
|
2018-01-11 13:13:02 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-09-26 17:45:09 +02:00
|
|
|
void log_set_upgrade_syslog_to_journal(bool b) {
|
|
|
|
upgrade_syslog_to_journal = b;
|
2018-01-24 17:33:07 +01:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
2017-09-26 17:45:09 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 17:57:55 +01:00
|
|
|
void log_set_always_reopen_console(bool b) {
|
|
|
|
always_reopen_console = b;
|
|
|
|
}
|
2017-09-26 17:45:09 +02:00
|
|
|
|
|
|
|
void log_set_open_when_needed(bool b) {
|
|
|
|
open_when_needed = b;
|
|
|
|
}
|
2018-01-11 00:39:12 +01:00
|
|
|
|
log: add new "prohibit_ipc" flag to logging system
If set, we'll avoid logging to any IPC log targets, i.e. syslog or the
journal, but allow stderr, kmsg, console logging.
This is useful as PID 1 wants to turn this off explicitly as long as the
journal is not up.
Previously we'd open/close the log stream to these services whenever
needed but this is incompatible with the "open_when_needed" logic
introduced in #6915, which might open the log streams whenever it likes,
including possibly inside of the child process we fork off that'll
become journald later on. Hence, let's make this all explicit, and
instead of managing when we open/close log streams add a boolean that
clearly prohibits the IPC targets when needed, so that opening can be
done at any time, but will honour this.
See: #7985
2018-01-24 17:36:25 +01:00
|
|
|
void log_set_prohibit_ipc(bool b) {
|
|
|
|
prohibit_ipc = b;
|
|
|
|
}
|
|
|
|
|
2018-01-11 00:39:12 +01:00
|
|
|
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;
|
|
|
|
}
|
2018-05-22 16:52:50 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2018-11-20 11:18:22 +01:00
|
|
|
|
|
|
|
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();
|
2019-08-20 17:29:49 +02:00
|
|
|
(void) log_open();
|
2018-11-20 11:18:22 +01:00
|
|
|
}
|
2020-06-17 21:17:54 +02:00
|
|
|
|
|
|
|
void log_setup_cli(void) {
|
|
|
|
/* Sets up logging the way it is most appropriate for running a program as a CLI utility. */
|
|
|
|
|
2020-12-08 17:49:13 +01:00
|
|
|
log_set_target(LOG_TARGET_AUTO);
|
2020-06-17 21:17:54 +02:00
|
|
|
log_parse_environment_cli();
|
|
|
|
(void) log_open();
|
2020-12-08 17:49:13 +01:00
|
|
|
if (log_on_console() && show_color < 0)
|
|
|
|
log_show_color(true);
|
2020-06-17 21:17:54 +02:00
|
|
|
}
|