2010-02-03 13:03:47 +01:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2010 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
2012-04-12 00:20:58 +02:00
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
2010-02-03 13:03:47 +01:00
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2012-04-12 00:20:58 +02:00
|
|
|
Lesser General Public License for more details.
|
2010-02-03 13:03:47 +01:00
|
|
|
|
2012-04-12 00:20:58 +02:00
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
2010-02-03 13:03:47 +01:00
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
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>
|
|
|
|
#include <stdio.h>
|
2015-11-30 21:43:37 +01:00
|
|
|
#include <string.h>
|
|
|
|
#include <sys/signalfd.h>
|
2010-04-06 21:57:45 +02:00
|
|
|
#include <sys/socket.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-11-30 21:43:37 +01:00
|
|
|
#include <time.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"
|
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"
|
|
|
|
#include "missing.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"
|
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"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "util.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;
|
2010-06-17 22:52:55 +02:00
|
|
|
static int log_max_level = LOG_INFO;
|
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;
|
|
|
|
|
2010-06-17 22:52:55 +02:00
|
|
|
static bool show_color = false;
|
|
|
|
static bool show_location = false;
|
|
|
|
|
2014-08-11 20:08:08 +02:00
|
|
|
static bool upgrade_syslog_to_journal = false;
|
|
|
|
|
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;
|
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
void log_close_console(void) {
|
|
|
|
|
|
|
|
if (console_fd < 0)
|
|
|
|
return;
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2010-05-18 05:10:52 +02:00
|
|
|
if (getpid() == 1) {
|
|
|
|
if (console_fd >= 3)
|
2014-03-18 19:22:43 +01:00
|
|
|
safe_close(console_fd);
|
2010-05-18 05:10:52 +02:00
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
console_fd = -1;
|
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
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
if (console_fd >= 0)
|
2010-04-06 21:57:45 +02:00
|
|
|
return 0;
|
2010-05-15 17:25:08 +02:00
|
|
|
|
|
|
|
if (getpid() == 1) {
|
2012-01-12 04:34:31 +01:00
|
|
|
console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
|
2012-09-17 22:14:24 +02:00
|
|
|
if (console_fd < 0)
|
2010-05-15 17:25:08 +02:00
|
|
|
return console_fd;
|
|
|
|
} else
|
|
|
|
console_fd = STDERR_FILENO;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2010-04-06 21:57:45 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2016-08-30 21:02:36 +02:00
|
|
|
(void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
|
2012-01-27 18:57:37 +01:00
|
|
|
|
2013-07-24 07:24:05 +02: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. */
|
2013-12-14 17:54:26 +01:00
|
|
|
if (getpid() == 1)
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-12 04:34:31 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
int log_open(void) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* If we don't use the console we close it here, to not get
|
|
|
|
* killed by SAK. If we don't use syslog we close it here so
|
|
|
|
* that we are not confused by somebody deleting the socket in
|
|
|
|
* the fs. If we don't use /dev/kmsg we still keep it open,
|
|
|
|
* because there is no reason to close it. */
|
|
|
|
|
2010-06-09 15:37:37 +02:00
|
|
|
if (log_target == LOG_TARGET_NULL) {
|
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;
|
|
|
|
}
|
|
|
|
|
2016-12-18 01:55:43 +01:00
|
|
|
if (!IN_SET(log_target, LOG_TARGET_AUTO, LOG_TARGET_SAFE) ||
|
2010-11-12 01:01:04 +01:00
|
|
|
getpid() == 1 ||
|
2010-11-12 01:02:03 +01:00
|
|
|
isatty(STDERR_FILENO) <= 0) {
|
2010-11-12 01:01:04 +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_JOURNAL)) {
|
2012-01-12 04:34:31 +01:00
|
|
|
r = log_open_journal();
|
|
|
|
if (r >= 0) {
|
|
|
|
log_close_syslog();
|
2010-11-12 01:01:04 +01:00
|
|
|
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_SYSLOG_OR_KMSG,
|
|
|
|
LOG_TARGET_SYSLOG)) {
|
2012-01-12 04:34:31 +01:00
|
|
|
r = log_open_syslog();
|
|
|
|
if (r >= 0) {
|
|
|
|
log_close_journal();
|
|
|
|
log_close_console();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-18 01:55:43 +01:00
|
|
|
if (IN_SET(log_target, LOG_TARGET_AUTO,
|
|
|
|
LOG_TARGET_SAFE,
|
|
|
|
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) {
|
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) {
|
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
|
|
|
}
|
|
|
|
|
2010-04-06 21:57:45 +02:00
|
|
|
void log_set_max_level(int level) {
|
|
|
|
assert((level & LOG_PRIMASK) == level);
|
|
|
|
|
|
|
|
log_max_level = level;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2016-07-07 06:30:34 +02:00
|
|
|
char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2];
|
2015-01-22 03:47:46 +01:00
|
|
|
struct iovec iovec[6] = {};
|
2010-05-15 17:25:08 +02:00
|
|
|
unsigned n = 0;
|
|
|
|
bool highlight;
|
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);
|
2015-01-22 03:47:46 +01:00
|
|
|
IOVEC_SET_STRING(iovec[n++], prefix);
|
|
|
|
}
|
|
|
|
|
2010-06-17 22:52:55 +02:00
|
|
|
highlight = LOG_PRI(level) <= LOG_ERR && show_color;
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2012-01-05 03:25:10 +01:00
|
|
|
if (show_location) {
|
2016-07-07 06:30:34 +02:00
|
|
|
snprintf(location, sizeof(location), "(%s:%i) ", file, line);
|
2010-06-17 22:52:55 +02:00
|
|
|
IOVEC_SET_STRING(iovec[n++], location);
|
2012-01-05 03:25:10 +01:00
|
|
|
}
|
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
if (highlight)
|
2015-09-19 00:45:05 +02:00
|
|
|
IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED);
|
2010-05-15 17:25:08 +02:00
|
|
|
IOVEC_SET_STRING(iovec[n++], buffer);
|
|
|
|
if (highlight)
|
2015-09-19 00:45:05 +02:00
|
|
|
IOVEC_SET_STRING(iovec[n++], ANSI_NORMAL);
|
2010-05-15 17:25:08 +02:00
|
|
|
IOVEC_SET_STRING(iovec[n++], "\n");
|
|
|
|
|
2013-12-18 16:49:15 +01:00
|
|
|
if (writev(console_fd, iovec, n) < 0) {
|
|
|
|
|
|
|
|
if (errno == EIO && getpid() == 1) {
|
|
|
|
|
|
|
|
/* If somebody tried to kick us from our
|
|
|
|
* console tty (via vhangup() or suchlike),
|
|
|
|
* try to reconnect */
|
|
|
|
|
|
|
|
log_close_console();
|
|
|
|
log_open_console();
|
|
|
|
|
|
|
|
if (console_fd < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (writev(console_fd, iovec, n) < 0)
|
|
|
|
return -errno;
|
|
|
|
} else
|
|
|
|
return -errno;
|
|
|
|
}
|
2010-01-20 19:18:52 +01:00
|
|
|
|
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;
|
|
|
|
struct tm *tm;
|
|
|
|
|
|
|
|
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);
|
2013-01-05 17:59:46 +01:00
|
|
|
tm = localtime(&t);
|
|
|
|
if (!tm)
|
2010-04-06 21:57:45 +02:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2015-01-27 14:00:11 +01:00
|
|
|
xsprintf(header_pid, "["PID_FMT"]: ", getpid());
|
2010-04-06 21:57:45 +02:00
|
|
|
|
|
|
|
IOVEC_SET_STRING(iovec[0], header_priority);
|
|
|
|
IOVEC_SET_STRING(iovec[1], header_time);
|
2010-06-16 21:54:17 +02:00
|
|
|
IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
|
2010-04-06 21:57:45 +02:00
|
|
|
IOVEC_SET_STRING(iovec[3], header_pid);
|
|
|
|
IOVEC_SET_STRING(iovec[4], buffer);
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
2015-01-27 14:00:11 +01:00
|
|
|
xsprintf(header_priority, "<%i>", level);
|
|
|
|
xsprintf(header_pid, "["PID_FMT"]: ", getpid());
|
2010-04-06 21:57:45 +02:00
|
|
|
|
|
|
|
IOVEC_SET_STRING(iovec[0], header_priority);
|
2010-06-16 21:54:17 +02:00
|
|
|
IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
|
2010-04-06 21:57:45 +02:00
|
|
|
IOVEC_SET_STRING(iovec[2], header_pid);
|
|
|
|
IOVEC_SET_STRING(iovec[3], buffer);
|
2010-05-15 17:25:08 +02:00
|
|
|
IOVEC_SET_STRING(iovec[4], "\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) {
|
2014-11-27 19:48:02 +01:00
|
|
|
|
2012-11-26 16:39:46 +01:00
|
|
|
snprintf(header, size,
|
2012-01-12 04:34:31 +01:00
|
|
|
"PRIORITY=%i\n"
|
2012-04-03 19:25:29 +02:00
|
|
|
"SYSLOG_FACILITY=%i\n"
|
2014-11-27 19:48:02 +01:00
|
|
|
"%s%s%s"
|
2012-11-26 16:39:46 +01:00
|
|
|
"%s%.*i%s"
|
2014-11-27 19:48:02 +01:00
|
|
|
"%s%s%s"
|
|
|
|
"%s%.*i%s"
|
|
|
|
"%s%s%s"
|
2016-08-30 23:18:46 +02:00
|
|
|
"%s%s%s"
|
2012-11-26 16:39:46 +01:00
|
|
|
"SYSLOG_IDENTIFIER=%s\n",
|
2012-01-12 04:34:31 +01:00
|
|
|
LOG_PRI(level),
|
2012-04-03 19:25:29 +02:00
|
|
|
LOG_FAC(level),
|
2014-11-27 19:48:02 +01:00
|
|
|
isempty(file) ? "" : "CODE_FILE=",
|
|
|
|
isempty(file) ? "" : file,
|
|
|
|
isempty(file) ? "" : "\n",
|
2012-11-26 16:39:46 +01:00
|
|
|
line ? "CODE_LINE=" : "",
|
|
|
|
line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
|
|
|
|
line ? "\n" : "",
|
basic/log: CODE_FUNCTION → CODE_FUNC
systemd.journal-fields(7) documents CODE_FUNC=. Internally, we were
inconsistent: sd_journal_print uses CODE_FUNC=, log.h has CODE_FUNCTION=,
python-systemd and bootchart also used CODE_FUNC=, when they were internal.
Most external projects use sd_journal_* functions, so CODE_FUNC=,
python-systemd still uses CODE_FUNC=, as does systemd-bootchart, and
independent reimplementations in golang-github-coreos-go-systemd, qtbase,
network manager, glib, pulseaudio. Hence, I don't think there's much
choice.
2016-12-11 21:40:55 +01:00
|
|
|
isempty(func) ? "" : "CODE_FUNC=",
|
2014-11-27 19:48:02 +01:00
|
|
|
isempty(func) ? "" : func,
|
|
|
|
isempty(func) ? "" : "\n",
|
|
|
|
error ? "ERRNO=" : "",
|
|
|
|
error ? 1 : 0, error,
|
|
|
|
error ? "\n" : "",
|
|
|
|
isempty(object) ? "" : object_field,
|
|
|
|
isempty(object) ? "" : object,
|
|
|
|
isempty(object) ? "" : "\n",
|
2016-08-30 23:18:46 +02:00
|
|
|
isempty(extra) ? "" : extra_field,
|
|
|
|
isempty(extra) ? "" : extra,
|
|
|
|
isempty(extra) ? "" : "\n",
|
2012-04-22 01:01:54 +02:00
|
|
|
program_invocation_short_name);
|
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
|
|
|
|
|
|
|
IOVEC_SET_STRING(iovec[0], header);
|
2012-11-26 16:39:46 +01:00
|
|
|
IOVEC_SET_STRING(iovec[1], "MESSAGE=");
|
|
|
|
IOVEC_SET_STRING(iovec[2], buffer);
|
|
|
|
IOVEC_SET_STRING(iovec[3], "\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;
|
|
|
|
}
|
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
static int log_dispatch(
|
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,
|
|
|
|
const char *extra_field,
|
2014-11-27 19:48:02 +01:00
|
|
|
char *buffer) {
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
assert(buffer);
|
2010-05-15 17:25:08 +02:00
|
|
|
|
2016-08-30 21:02:36 +02:00
|
|
|
if (error < 0)
|
|
|
|
error = -error;
|
|
|
|
|
2010-06-09 15:37:37 +02:00
|
|
|
if (log_target == LOG_TARGET_NULL)
|
2014-11-28 03:10:55 +01:00
|
|
|
return -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)
|
2012-04-03 19:25:29 +02:00
|
|
|
level = log_facility | LOG_PRI(level);
|
2011-03-31 19:49:04 +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);
|
2013-02-27 14:33:50 +01:00
|
|
|
if (k < 0) {
|
|
|
|
if (k != -EAGAIN)
|
2012-01-12 04:34:31 +01:00
|
|
|
log_close_journal();
|
|
|
|
log_open_kmsg();
|
2014-11-28 03:10:55 +01:00
|
|
|
}
|
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);
|
2013-02-27 14:33:50 +01:00
|
|
|
if (k < 0) {
|
|
|
|
if (k != -EAGAIN)
|
2011-12-18 14:57:54 +01:00
|
|
|
log_close_syslog();
|
2010-05-21 03:31:49 +02:00
|
|
|
log_open_kmsg();
|
2014-11-28 03:10:55 +01:00
|
|
|
}
|
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_SAFE,
|
|
|
|
LOG_TARGET_SYSLOG_OR_KMSG,
|
|
|
|
LOG_TARGET_JOURNAL_OR_KMSG,
|
|
|
|
LOG_TARGET_KMSG)) {
|
2010-05-21 03:31:49 +02:00
|
|
|
|
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();
|
2010-05-21 03:31:49 +02:00
|
|
|
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);
|
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
return -error;
|
2010-05-15 17:25:08 +02:00
|
|
|
}
|
|
|
|
|
2010-06-04 19:45:53 +02:00
|
|
|
int log_dump_internal(
|
|
|
|
int level,
|
2014-11-27 19:48:02 +01:00
|
|
|
int error,
|
2014-11-28 03:10:55 +01:00
|
|
|
const char *file,
|
2010-06-04 19:45:53 +02:00
|
|
|
int line,
|
|
|
|
const char *func,
|
|
|
|
char *buffer) {
|
|
|
|
|
2013-04-02 16:31:55 +02:00
|
|
|
PROTECT_ERRNO;
|
2010-06-04 19:45:53 +02:00
|
|
|
|
|
|
|
/* This modifies the buffer... */
|
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
if (error < 0)
|
|
|
|
error = -error;
|
|
|
|
|
2010-06-04 19:45:53 +02:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level))
|
2014-11-28 03:10:55 +01:00
|
|
|
return -error;
|
2010-06-04 19:45:53 +02:00
|
|
|
|
2016-08-30 23:18:46 +02:00
|
|
|
return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
|
2010-06-04 19:45:53 +02:00
|
|
|
}
|
|
|
|
|
2014-11-27 20:20:23 +01:00
|
|
|
int log_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 *format,
|
|
|
|
va_list ap) {
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2013-04-02 16:31:55 +02:00
|
|
|
PROTECT_ERRNO;
|
2010-08-21 03:57:47 +02:00
|
|
|
char buffer[LINE_MAX];
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
if (error < 0)
|
|
|
|
error = -error;
|
|
|
|
|
2010-06-02 21:34:03 +02:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level))
|
2014-11-28 03:10:55 +01:00
|
|
|
return -error;
|
2010-04-06 21:57:45 +02:00
|
|
|
|
2014-11-27 19:48:02 +01:00
|
|
|
/* Make sure that %m maps to the specified error */
|
|
|
|
if (error != 0)
|
2014-11-28 03:10:55 +01:00
|
|
|
errno = error;
|
2014-11-27 19:48:02 +01:00
|
|
|
|
2010-05-15 17:25:08 +02:00
|
|
|
vsnprintf(buffer, sizeof(buffer), format, ap);
|
|
|
|
|
2016-08-30 23:18:46 +02:00
|
|
|
return log_dispatch(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
|
|
|
|
2014-11-27 20:20:23 +01:00
|
|
|
int log_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 *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);
|
2014-11-27 20:20:23 +01:00
|
|
|
r = log_internalv(level, error, file, line, func, format, ap);
|
2012-03-14 14:54:41 +01:00
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-11-27 20:20:23 +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;
|
|
|
|
size_t l;
|
2013-01-05 17:59:46 +01:00
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
if (error < 0)
|
|
|
|
error = -error;
|
|
|
|
|
2013-01-05 17:59:46 +01:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level))
|
2014-11-28 03:10:55 +01:00
|
|
|
return -error;
|
2013-01-05 17:59:46 +01:00
|
|
|
|
2014-11-27 19:48:02 +01:00
|
|
|
/* Make sure that %m maps to the specified error */
|
|
|
|
if (error != 0)
|
2014-11-28 03:10:55 +01:00
|
|
|
errno = 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);
|
|
|
|
l = n + 2 + LINE_MAX;
|
|
|
|
|
|
|
|
buffer = newa(char, l);
|
|
|
|
b = stpcpy(stpcpy(buffer, object), ": ");
|
|
|
|
} else {
|
|
|
|
l = LINE_MAX;
|
|
|
|
b = buffer = newa(char, l);
|
|
|
|
}
|
|
|
|
|
|
|
|
vsnprintf(b, l, format, ap);
|
2013-01-05 17:59:46 +01:00
|
|
|
|
2016-08-30 23:18:46 +02:00
|
|
|
return log_dispatch(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];
|
2010-04-22 03:51:26 +02:00
|
|
|
|
2013-12-12 02:34:19 +01:00
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level))
|
|
|
|
return;
|
|
|
|
|
2014-02-20 18:18:32 +01:00
|
|
|
DISABLE_WARNING_FORMAT_NONLITERAL;
|
2016-11-03 03:02:46 +01:00
|
|
|
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;
|
|
|
|
|
2016-08-30 23:18:46 +02:00
|
|
|
log_dispatch(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
|
|
|
|
2013-12-16 17:53:53 +01:00
|
|
|
noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
|
2013-12-10 18:01:10 +01:00
|
|
|
log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
|
|
|
|
abort();
|
2012-01-17 12:05:33 +01:00
|
|
|
}
|
|
|
|
|
2013-12-16 17:53:53 +01:00
|
|
|
noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
|
2013-12-10 18:01:10 +01:00
|
|
|
log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_assert_failed_return(const char *text, const char *file, int line, const char *func) {
|
2013-12-12 15:58:49 +01:00
|
|
|
PROTECT_ERRNO;
|
2013-12-10 18:01:10 +01:00
|
|
|
log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
|
2012-01-17 12:05:33 +01:00
|
|
|
}
|
|
|
|
|
2012-08-24 22:21:20 +02:00
|
|
|
int log_oom_internal(const char *file, int line, const char *func) {
|
2014-11-27 20:20:23 +01:00
|
|
|
log_internal(LOG_ERR, ENOMEM, file, line, func, "Out of memory.");
|
2012-07-26 14:23:49 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2015-11-08 20:05:55 +01:00
|
|
|
int log_format_iovec(
|
|
|
|
struct iovec *iovec,
|
|
|
|
unsigned iovec_len,
|
|
|
|
unsigned *n,
|
|
|
|
bool newline_separator,
|
|
|
|
int error,
|
|
|
|
const char *format,
|
|
|
|
va_list ap) {
|
|
|
|
|
|
|
|
static const char nl = '\n';
|
|
|
|
|
|
|
|
while (format && *n + 1 < iovec_len) {
|
|
|
|
va_list aq;
|
|
|
|
char *m;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* We need to copy the va_list structure,
|
|
|
|
* since vasprintf() leaves it afterwards at
|
|
|
|
* an undefined location */
|
|
|
|
|
|
|
|
if (error != 0)
|
|
|
|
errno = error;
|
|
|
|
|
|
|
|
va_copy(aq, ap);
|
|
|
|
r = vasprintf(&m, format, aq);
|
|
|
|
va_end(aq);
|
|
|
|
if (r < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* Now, jump enough ahead, so that we point to
|
|
|
|
* the next format string */
|
|
|
|
VA_FORMAT_ADVANCE(format, ap);
|
|
|
|
|
|
|
|
IOVEC_SET_STRING(iovec[(*n)++], m);
|
|
|
|
|
|
|
|
if (newline_separator) {
|
|
|
|
iovec[*n].iov_base = (char*) &nl;
|
|
|
|
iovec[*n].iov_len = 1;
|
|
|
|
(*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, ...) {
|
|
|
|
|
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
|
|
|
|
|
|
|
if (error < 0)
|
|
|
|
error = -error;
|
2012-08-24 22:21:20 +02:00
|
|
|
|
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level))
|
2014-11-28 03:10:55 +01:00
|
|
|
return -error;
|
2012-08-24 22:21:20 +02:00
|
|
|
|
|
|
|
if (log_target == LOG_TARGET_NULL)
|
2014-11-28 03:10:55 +01:00
|
|
|
return -error;
|
2012-08-24 22:21:20 +02:00
|
|
|
|
|
|
|
if ((level & LOG_FACMASK) == 0)
|
|
|
|
level = log_facility | LOG_PRI(level);
|
|
|
|
|
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-08-24 22:21:20 +02:00
|
|
|
journal_fd >= 0) {
|
|
|
|
char header[LINE_MAX];
|
2013-03-25 00:59:00 +01:00
|
|
|
struct iovec iovec[17] = {};
|
2012-08-24 22:21:20 +02:00
|
|
|
unsigned n = 0, i;
|
2015-11-08 20:05:55 +01:00
|
|
|
int r;
|
2013-04-16 03:58:22 +02:00
|
|
|
struct msghdr mh = {
|
|
|
|
.msg_iov = iovec,
|
|
|
|
};
|
2014-11-28 03:10:55 +01:00
|
|
|
bool fallback = false;
|
2012-08-24 22:21:20 +02:00
|
|
|
|
|
|
|
/* If the journal is available do structured logging */
|
2016-08-30 23:18:46 +02:00
|
|
|
log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
|
2012-08-24 22:21:20 +02:00
|
|
|
IOVEC_SET_STRING(iovec[n++], header);
|
|
|
|
|
|
|
|
va_start(ap, format);
|
2015-11-08 20:05:55 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-09-21 10:22:46 +02:00
|
|
|
va_end(ap);
|
2012-08-24 22:21:20 +02:00
|
|
|
for (i = 1; i < n; i += 2)
|
|
|
|
free(iovec[i].iov_base);
|
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
if (!fallback)
|
|
|
|
return -error;
|
|
|
|
}
|
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
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
if (error != 0)
|
|
|
|
errno = error;
|
2012-08-24 22:21:20 +02:00
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
va_copy(aq, ap);
|
|
|
|
vsnprintf(buf, sizeof(buf), format, aq);
|
|
|
|
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
|
|
|
|
2014-11-28 03:10:55 +01:00
|
|
|
if (!found)
|
|
|
|
return -error;
|
|
|
|
|
2016-08-30 23:18:46 +02:00
|
|
|
return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
|
2012-08-24 22:21:20 +02:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
int log_set_max_level_from_string(const char *e) {
|
|
|
|
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
|
|
|
|
|
|
|
log_set_max_level(t);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-04-06 23:38:32 +02:00
|
|
|
void log_parse_environment(void) {
|
|
|
|
const char *e;
|
2013-12-23 17:56:44 +01:00
|
|
|
|
2015-02-06 01:44:13 +01:00
|
|
|
if (get_ctty_devnr(0, NULL) < 0)
|
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
|
|
|
/* Only try to read the command line in daemons. We assume that anything that has a controlling tty is
|
|
|
|
user stuff. */
|
|
|
|
(void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
|
2010-04-06 23:38:32 +02:00
|
|
|
|
2012-09-17 00:21:25 +02:00
|
|
|
e = secure_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
|
|
|
|
2012-09-17 00:21:25 +02:00
|
|
|
e = secure_getenv("SYSTEMD_LOG_LEVEL");
|
2012-08-23 18:47:01 +02:00
|
|
|
if (e && log_set_max_level_from_string(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
|
|
|
|
2012-09-17 00:21:25 +02:00
|
|
|
e = secure_getenv("SYSTEMD_LOG_COLOR");
|
2012-08-23 18:47:01 +02:00
|
|
|
if (e && log_show_color_from_string(e) < 0)
|
2014-07-21 01:47:42 +02:00
|
|
|
log_warning("Failed to parse bool '%s'. Ignoring.", e);
|
2010-06-17 22:52:55 +02:00
|
|
|
|
2012-09-17 00:21:25 +02:00
|
|
|
e = secure_getenv("SYSTEMD_LOG_LOCATION");
|
2012-08-23 18:47:01 +02:00
|
|
|
if (e && log_show_location_from_string(e) < 0)
|
2014-07-21 01:47:42 +02:00
|
|
|
log_warning("Failed to parse bool '%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;
|
|
|
|
}
|
|
|
|
|
|
|
|
int log_get_max_level(void) {
|
|
|
|
return log_max_level;
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
return show_color;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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",
|
2012-05-22 22:00:37 +02:00
|
|
|
[LOG_TARGET_SAFE] = "safe",
|
2012-01-12 04:34:31 +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) {
|
|
|
|
if (si->ssi_pid > 0) {
|
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
|
|
|
|
get_process_comm(si->ssi_pid, &p);
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
void log_set_upgrade_syslog_to_journal(bool b) {
|
|
|
|
upgrade_syslog_to_journal = b;
|
|
|
|
}
|
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
|
|
|
|
|
|
|
if (error < 0)
|
|
|
|
error = -error;
|
|
|
|
|
|
|
|
if (_likely_(LOG_PRI(level) > log_max_level))
|
|
|
|
return -error;
|
|
|
|
|
|
|
|
if (log_target == LOG_TARGET_NULL)
|
|
|
|
return -error;
|
|
|
|
|
|
|
|
if (error != 0)
|
|
|
|
errno = error;
|
|
|
|
|
|
|
|
va_start(ap, format);
|
|
|
|
vsnprintf(buffer, sizeof(buffer), format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
if (unit)
|
2016-12-11 20:34:45 +01:00
|
|
|
unit_fmt = getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
|
|
|
|
|
|
|
|
return log_struct_internal(
|
|
|
|
level, error,
|
|
|
|
file, line, func,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
|
2016-12-11 20:34:45 +01:00
|
|
|
"CONFIG_FILE=%s", config_file,
|
|
|
|
"CONFIG_LINE=%u", config_line,
|
2016-12-11 20:37:12 +01:00
|
|
|
LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),
|
2016-12-11 20:34:45 +01:00
|
|
|
unit_fmt, unit,
|
|
|
|
NULL);
|
2015-04-21 17:26:04 +02:00
|
|
|
}
|