2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_SELINUX
|
2015-05-29 20:14:11 +02:00
|
|
|
#include <selinux/selinux.h>
|
|
|
|
#endif
|
2015-10-02 23:21:59 +02:00
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/signalfd.h>
|
|
|
|
#include <sys/statvfs.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <linux/sockios.h>
|
2015-05-29 20:14:11 +02:00
|
|
|
|
2015-10-02 23:21:59 +02:00
|
|
|
#include "sd-daemon.h"
|
2013-11-06 03:15:16 +01:00
|
|
|
#include "sd-journal.h"
|
|
|
|
#include "sd-messages.h"
|
2015-10-02 23:21:59 +02:00
|
|
|
|
|
|
|
#include "acl-util.h"
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-10-26 23:32:16 +01:00
|
|
|
#include "audit-util.h"
|
2012-11-12 17:29:07 +01:00
|
|
|
#include "cgroup-util.h"
|
|
|
|
#include "conf-parser.h"
|
2015-10-26 20:07:55 +01:00
|
|
|
#include "dirent-util.h"
|
2015-10-26 13:12:30 +01:00
|
|
|
#include "extract-word.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-11-12 11:17:01 +01:00
|
|
|
#include "fileio.h"
|
2016-11-07 16:14:59 +01:00
|
|
|
#include "format-util.h"
|
2015-10-26 21:16:26 +01:00
|
|
|
#include "fs-util.h"
|
2015-10-02 23:21:59 +02:00
|
|
|
#include "hashmap.h"
|
2015-05-18 17:10:07 +02:00
|
|
|
#include "hostname-util.h"
|
2016-08-30 23:18:46 +02:00
|
|
|
#include "id128-util.h"
|
2015-10-27 01:02:30 +01:00
|
|
|
#include "io-util.h"
|
2015-10-02 23:21:59 +02:00
|
|
|
#include "journal-authenticate.h"
|
|
|
|
#include "journal-file.h"
|
2012-11-12 17:29:07 +01:00
|
|
|
#include "journal-internal.h"
|
|
|
|
#include "journal-vacuum.h"
|
2015-10-02 23:21:59 +02:00
|
|
|
#include "journald-audit.h"
|
2017-07-17 23:36:35 +02:00
|
|
|
#include "journald-context.h"
|
2012-11-12 17:29:07 +01:00
|
|
|
#include "journald-kmsg.h"
|
|
|
|
#include "journald-native.h"
|
2015-10-02 23:21:59 +02:00
|
|
|
#include "journald-rate-limit.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "journald-server.h"
|
2015-10-02 23:21:59 +02:00
|
|
|
#include "journald-stream.h"
|
|
|
|
#include "journald-syslog.h"
|
2016-08-30 23:18:46 +02:00
|
|
|
#include "log.h"
|
2019-10-31 03:07:23 +01:00
|
|
|
#include "missing_audit.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "mkdir.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2019-11-25 15:00:38 +01:00
|
|
|
#include "path-util.h"
|
2015-10-27 00:06:29 +01:00
|
|
|
#include "proc-cmdline.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "process-util.h"
|
|
|
|
#include "rm-rf.h"
|
|
|
|
#include "selinux-util.h"
|
|
|
|
#include "signal-util.h"
|
|
|
|
#include "socket-util.h"
|
2015-11-11 13:54:50 +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"
|
2016-10-22 01:40:55 +02:00
|
|
|
#include "syslog-util.h"
|
2017-07-17 23:36:35 +02:00
|
|
|
#include "user-util.h"
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
#define USER_JOURNALS_MAX 1024
|
|
|
|
|
2013-03-25 17:49:03 +01:00
|
|
|
#define DEFAULT_SYNC_INTERVAL_USEC (5*USEC_PER_MINUTE)
|
2013-06-21 15:56:45 +02:00
|
|
|
#define DEFAULT_RATE_LIMIT_INTERVAL (30*USEC_PER_SEC)
|
2018-04-05 13:06:59 +02:00
|
|
|
#define DEFAULT_RATE_LIMIT_BURST 10000
|
2014-06-26 22:11:35 +02:00
|
|
|
#define DEFAULT_MAX_FILE_USEC USEC_PER_MONTH
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-10-02 23:21:59 +02:00
|
|
|
#define RECHECK_SPACE_USEC (30*USEC_PER_SEC)
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-11-01 21:50:24 +01:00
|
|
|
#define NOTIFY_SNDBUF_SIZE (8*1024*1024)
|
|
|
|
|
2015-12-11 07:42:22 +01:00
|
|
|
/* The period to insert between posting changes for coalescing */
|
|
|
|
#define POST_CHANGE_TIMER_INTERVAL_USEC (250*USEC_PER_MSEC)
|
|
|
|
|
journald: make maximum size of stream log lines configurable and bump it to 48K (#6838)
This adds a new setting LineMax= to journald.conf, and sets it by
default to 48K. When we convert stream-based stdout/stderr logging into
record-based log entries, read up to the specified amount of bytes
before forcing a line-break.
This also makes three related changes:
- When a NUL byte is read we'll not recognize this as alternative line
break, instead of silently dropping everything after it. (see #4863)
- The reason for a line-break is now encoded in the log record, if it
wasn't a plain newline. Specifically, we distuingish "nul",
"line-max" and "eof", for line breaks due to NUL byte, due to the
maximum line length as configured with LineMax= or due to end of
stream. This data is stored in the new implicit _LINE_BREAK= field.
It's not synthesized for plain \n line breaks.
- A randomized 128bit ID is assigned to each log stream.
With these three changes in place it's (mostly) possible to reconstruct
the original byte streams from log data, as (most) of the context of
the conversion from the byte stream to log records is saved now. (So,
the only bits we still drop are empty lines. Which might be something to
look into in a future change, and which is outside of the scope of this
work)
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=86465
See: #4863
Replaces: #4875
2017-09-22 10:22:24 +02:00
|
|
|
/* Pick a good default that is likely to fit into AF_UNIX and AF_INET SOCK_DGRAM datagrams, and even leaves some room
|
|
|
|
* for a bit of additional metadata. */
|
|
|
|
#define DEFAULT_LINE_MAX (48*1024)
|
|
|
|
|
2018-10-25 18:39:27 +02:00
|
|
|
#define DEFERRED_CLOSES_MAX (4096)
|
|
|
|
|
2019-11-27 14:45:24 +01:00
|
|
|
#define IDLE_TIMEOUT_USEC (30*USEC_PER_SEC)
|
|
|
|
|
2019-11-25 12:50:36 +01:00
|
|
|
static int determine_path_usage(
|
|
|
|
Server *s,
|
|
|
|
const char *path,
|
|
|
|
uint64_t *ret_used,
|
|
|
|
uint64_t *ret_free) {
|
|
|
|
|
2016-10-03 18:12:41 +02:00
|
|
|
_cleanup_closedir_ DIR *d = NULL;
|
|
|
|
struct dirent *de;
|
|
|
|
struct statvfs ss;
|
|
|
|
|
2019-11-25 12:50:36 +01:00
|
|
|
assert(s);
|
|
|
|
assert(path);
|
2016-10-03 18:12:41 +02:00
|
|
|
assert(ret_used);
|
|
|
|
assert(ret_free);
|
|
|
|
|
2016-10-04 17:13:21 +02:00
|
|
|
d = opendir(path);
|
2016-10-03 18:12:41 +02:00
|
|
|
if (!d)
|
|
|
|
return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
|
2016-10-04 17:13:21 +02:00
|
|
|
errno, "Failed to open %s: %m", path);
|
2016-10-03 18:12:41 +02:00
|
|
|
|
|
|
|
if (fstatvfs(dirfd(d), &ss) < 0)
|
2016-10-04 17:13:21 +02:00
|
|
|
return log_error_errno(errno, "Failed to fstatvfs(%s): %m", path);
|
2016-10-03 18:12:41 +02:00
|
|
|
|
|
|
|
*ret_free = ss.f_bsize * ss.f_bavail;
|
|
|
|
*ret_used = 0;
|
|
|
|
FOREACH_DIRENT_ALL(de, d, break) {
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (!endswith(de->d_name, ".journal") &&
|
|
|
|
!endswith(de->d_name, ".journal~"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
|
2016-10-04 17:13:21 +02:00
|
|
|
log_debug_errno(errno, "Failed to stat %s/%s, ignoring: %m", path, de->d_name);
|
2016-10-03 18:12:41 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISREG(st.st_mode))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
*ret_used += (uint64_t) st.st_blocks * 512UL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-12 09:05:55 +02:00
|
|
|
static void cache_space_invalidate(JournalStorageSpace *space) {
|
2017-12-14 19:47:46 +01:00
|
|
|
zero(*space);
|
2016-10-12 09:05:55 +02:00
|
|
|
}
|
|
|
|
|
2016-10-12 10:09:45 +02:00
|
|
|
static int cache_space_refresh(Server *s, JournalStorage *storage) {
|
2016-10-12 08:58:04 +02:00
|
|
|
JournalStorageSpace *space;
|
2016-10-04 17:13:21 +02:00
|
|
|
JournalMetrics *metrics;
|
2016-10-12 08:58:04 +02:00
|
|
|
uint64_t vfs_used, vfs_avail, avail;
|
2012-11-12 17:29:07 +01:00
|
|
|
usec_t ts;
|
2016-10-03 18:12:41 +02:00
|
|
|
int r;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-10-02 23:21:59 +02:00
|
|
|
assert(s);
|
2016-10-04 17:13:21 +02:00
|
|
|
|
|
|
|
metrics = &storage->metrics;
|
2016-10-12 08:58:04 +02:00
|
|
|
space = &storage->space;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-10-02 23:21:59 +02:00
|
|
|
ts = now(CLOCK_MONOTONIC);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2016-12-02 18:40:10 +01:00
|
|
|
if (space->timestamp != 0 && space->timestamp + RECHECK_SPACE_USEC > ts)
|
2012-11-12 17:29:07 +01:00
|
|
|
return 0;
|
|
|
|
|
2016-10-12 08:58:04 +02:00
|
|
|
r = determine_path_usage(s, storage->path, &vfs_used, &vfs_avail);
|
2016-10-03 18:12:41 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2016-10-12 08:58:04 +02:00
|
|
|
space->vfs_used = vfs_used;
|
|
|
|
space->vfs_available = vfs_avail;
|
|
|
|
|
|
|
|
avail = LESS_BY(vfs_avail, metrics->keep_free);
|
|
|
|
|
|
|
|
space->limit = MIN(MAX(vfs_used + avail, metrics->min_use), metrics->max_use);
|
|
|
|
space->available = LESS_BY(space->limit, vfs_used);
|
|
|
|
space->timestamp = ts;
|
2015-10-02 23:21:59 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-10-12 09:58:10 +02:00
|
|
|
static void patch_min_use(JournalStorage *storage) {
|
|
|
|
assert(storage);
|
|
|
|
|
|
|
|
/* Let's bump the min_use limit to the current usage on disk. We do
|
|
|
|
* this when starting up and first opening the journal files. This way
|
|
|
|
* sudden spikes in disk usage will not cause journald to vacuum files
|
|
|
|
* without bounds. Note that this means that only a restart of journald
|
|
|
|
* will make it reset this value. */
|
|
|
|
|
|
|
|
storage->metrics.min_use = MAX(storage->metrics.min_use, storage->space.vfs_used);
|
|
|
|
}
|
|
|
|
|
2019-11-22 16:11:20 +01:00
|
|
|
static JournalStorage* server_current_storage(Server *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
return s->system_journal ? &s->system_storage : &s->runtime_storage;
|
|
|
|
}
|
|
|
|
|
2016-10-12 09:58:10 +02:00
|
|
|
static int determine_space(Server *s, uint64_t *available, uint64_t *limit) {
|
2016-10-04 17:13:21 +02:00
|
|
|
JournalStorage *js;
|
2016-10-12 10:09:45 +02:00
|
|
|
int r;
|
2015-10-02 23:21:59 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2019-11-22 16:11:20 +01:00
|
|
|
js = server_current_storage(s);
|
2016-10-12 10:09:45 +02:00
|
|
|
|
|
|
|
r = cache_space_refresh(s, js);
|
|
|
|
if (r >= 0) {
|
|
|
|
if (available)
|
|
|
|
*available = js->space.available;
|
|
|
|
if (limit)
|
|
|
|
*limit = js->space.limit;
|
|
|
|
}
|
|
|
|
return r;
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2016-10-11 16:46:16 +02:00
|
|
|
void server_space_usage_message(Server *s, JournalStorage *storage) {
|
|
|
|
char fb1[FORMAT_BYTES_MAX], fb2[FORMAT_BYTES_MAX], fb3[FORMAT_BYTES_MAX],
|
|
|
|
fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX], fb6[FORMAT_BYTES_MAX];
|
|
|
|
JournalMetrics *metrics;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (!storage)
|
2019-11-22 16:11:20 +01:00
|
|
|
storage = server_current_storage(s);
|
2016-10-11 16:46:16 +02:00
|
|
|
|
2016-10-12 10:09:45 +02:00
|
|
|
if (cache_space_refresh(s, storage) < 0)
|
2016-10-11 16:46:16 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
metrics = &storage->metrics;
|
2016-10-12 08:58:04 +02:00
|
|
|
format_bytes(fb1, sizeof(fb1), storage->space.vfs_used);
|
2016-10-11 16:46:16 +02:00
|
|
|
format_bytes(fb2, sizeof(fb2), metrics->max_use);
|
|
|
|
format_bytes(fb3, sizeof(fb3), metrics->keep_free);
|
2016-10-12 08:58:04 +02:00
|
|
|
format_bytes(fb4, sizeof(fb4), storage->space.vfs_available);
|
2016-10-11 16:46:16 +02:00
|
|
|
format_bytes(fb5, sizeof(fb5), storage->space.limit);
|
|
|
|
format_bytes(fb6, sizeof(fb6), storage->space.available);
|
|
|
|
|
2017-10-30 20:01:50 +01:00
|
|
|
server_driver_message(s, 0,
|
|
|
|
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_USAGE_STR,
|
2016-10-11 16:46:16 +02:00
|
|
|
LOG_MESSAGE("%s (%s) is %s, max %s, %s free.",
|
|
|
|
storage->name, storage->path, fb1, fb5, fb6),
|
|
|
|
"JOURNAL_NAME=%s", storage->name,
|
|
|
|
"JOURNAL_PATH=%s", storage->path,
|
2016-10-12 08:58:04 +02:00
|
|
|
"CURRENT_USE=%"PRIu64, storage->space.vfs_used,
|
2016-10-11 16:46:16 +02:00
|
|
|
"CURRENT_USE_PRETTY=%s", fb1,
|
|
|
|
"MAX_USE=%"PRIu64, metrics->max_use,
|
|
|
|
"MAX_USE_PRETTY=%s", fb2,
|
|
|
|
"DISK_KEEP_FREE=%"PRIu64, metrics->keep_free,
|
|
|
|
"DISK_KEEP_FREE_PRETTY=%s", fb3,
|
2016-10-12 08:58:04 +02:00
|
|
|
"DISK_AVAILABLE=%"PRIu64, storage->space.vfs_available,
|
2016-10-11 16:46:16 +02:00
|
|
|
"DISK_AVAILABLE_PRETTY=%s", fb4,
|
|
|
|
"LIMIT=%"PRIu64, storage->space.limit,
|
|
|
|
"LIMIT_PRETTY=%s", fb5,
|
|
|
|
"AVAILABLE=%"PRIu64, storage->space.available,
|
|
|
|
"AVAILABLE_PRETTY=%s", fb6,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2017-12-30 15:17:39 +01:00
|
|
|
static bool uid_for_system_journal(uid_t uid) {
|
|
|
|
|
|
|
|
/* Returns true if the specified UID shall get its data stored in the system journal*/
|
|
|
|
|
|
|
|
return uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY;
|
|
|
|
}
|
|
|
|
|
2015-11-28 04:24:33 +01:00
|
|
|
static void server_add_acls(JournalFile *f, uid_t uid) {
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_ACL
|
2015-11-28 04:24:33 +01:00
|
|
|
int r;
|
2012-11-12 17:29:07 +01:00
|
|
|
#endif
|
|
|
|
assert(f);
|
|
|
|
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_ACL
|
2017-12-30 15:17:39 +01:00
|
|
|
if (uid_for_system_journal(uid))
|
2012-11-12 17:29:07 +01:00
|
|
|
return;
|
|
|
|
|
2015-11-28 04:24:33 +01:00
|
|
|
r = add_acls_for_user(f->fd, uid);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to set ACL on %s, ignoring: %m", f->path);
|
2012-11-12 17:29:07 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-12-11 07:42:22 +01:00
|
|
|
static int open_journal(
|
|
|
|
Server *s,
|
|
|
|
bool reliably,
|
|
|
|
const char *fname,
|
|
|
|
int flags,
|
|
|
|
bool seal,
|
|
|
|
JournalMetrics *metrics,
|
|
|
|
JournalFile **ret) {
|
2018-10-25 18:35:39 +02:00
|
|
|
|
2019-05-28 11:07:01 +02:00
|
|
|
_cleanup_(journal_file_closep) JournalFile *f = NULL;
|
2018-10-25 18:35:39 +02:00
|
|
|
int r;
|
2015-12-11 07:42:22 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(fname);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
if (reliably)
|
2018-02-27 18:37:23 +01:00
|
|
|
r = journal_file_open_reliably(fname, flags, 0640, s->compress.enabled, s->compress.threshold_bytes,
|
|
|
|
seal, metrics, s->mmap, s->deferred_closes, NULL, &f);
|
2015-12-11 07:42:22 +01:00
|
|
|
else
|
2018-02-27 18:37:23 +01:00
|
|
|
r = journal_file_open(-1, fname, flags, 0640, s->compress.enabled, s->compress.threshold_bytes, seal,
|
|
|
|
metrics, s->mmap, s->deferred_closes, NULL, &f);
|
|
|
|
|
2015-12-11 07:42:22 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-01-26 14:06:35 +01:00
|
|
|
r = journal_file_enable_post_change_timer(f, s->event, POST_CHANGE_TIMER_INTERVAL_USEC);
|
2019-05-28 11:07:01 +02:00
|
|
|
if (r < 0)
|
2015-12-11 07:42:22 +01:00
|
|
|
return r;
|
|
|
|
|
2019-05-28 11:07:01 +02:00
|
|
|
*ret = TAKE_PTR(f);
|
2015-12-11 07:42:22 +01:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
static bool flushed_flag_is_set(Server *s) {
|
|
|
|
const char *fn;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
/* We don't support the "flushing" concept for namespace instances, we assume them to always have
|
|
|
|
* access to /var */
|
|
|
|
if (s->namespace)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
fn = strjoina(s->runtime_directory, "/flushed");
|
|
|
|
return access(fn, F_OK) >= 0;
|
2016-08-26 17:51:13 +02:00
|
|
|
}
|
|
|
|
|
2019-04-05 18:20:25 +02:00
|
|
|
static int system_journal_open(Server *s, bool flush_requested, bool relinquish_requested) {
|
2016-08-17 14:51:07 +02:00
|
|
|
const char *fn;
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
if (!s->system_journal &&
|
2016-12-12 20:54:45 +01:00
|
|
|
IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) &&
|
2019-11-25 15:00:38 +01:00
|
|
|
(flush_requested || flushed_flag_is_set(s)) &&
|
2019-04-05 18:20:25 +02:00
|
|
|
!relinquish_requested) {
|
2016-08-17 14:51:07 +02:00
|
|
|
|
2019-11-25 12:52:42 +01:00
|
|
|
/* If in auto mode: first try to create the machine path, but not the prefix.
|
2016-08-17 14:51:07 +02:00
|
|
|
*
|
2019-11-25 12:52:42 +01:00
|
|
|
* If in persistent mode: create /var/log/journal and the machine path */
|
2016-08-17 14:51:07 +02:00
|
|
|
|
|
|
|
if (s->storage == STORAGE_PERSISTENT)
|
2019-11-25 12:52:42 +01:00
|
|
|
(void) mkdir_parents(s->system_storage.path, 0755);
|
2016-08-17 14:51:07 +02:00
|
|
|
|
2016-10-04 17:13:21 +02:00
|
|
|
(void) mkdir(s->system_storage.path, 0755);
|
2016-08-17 14:51:07 +02:00
|
|
|
|
2016-10-04 17:13:21 +02:00
|
|
|
fn = strjoina(s->system_storage.path, "/system.journal");
|
|
|
|
r = open_journal(s, true, fn, O_RDWR|O_CREAT, s->seal, &s->system_storage.metrics, &s->system_journal);
|
2016-08-17 14:51:07 +02:00
|
|
|
if (r >= 0) {
|
|
|
|
server_add_acls(s->system_journal, 0);
|
2016-10-12 10:09:45 +02:00
|
|
|
(void) cache_space_refresh(s, &s->system_storage);
|
2016-10-12 09:58:10 +02:00
|
|
|
patch_min_use(&s->system_storage);
|
2018-06-25 06:36:49 +02:00
|
|
|
} else {
|
2017-10-04 16:01:32 +02:00
|
|
|
if (!IN_SET(r, -ENOENT, -EROFS))
|
2016-08-17 14:51:07 +02:00
|
|
|
log_warning_errno(r, "Failed to open system journal: %m");
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
}
|
2016-08-25 17:37:57 +02:00
|
|
|
|
2019-11-25 12:52:42 +01:00
|
|
|
/* If the runtime journal is open, and we're post-flush, we're recovering from a failed
|
|
|
|
* system journal rotate (ENOSPC) for which the runtime journal was reopened.
|
2016-08-25 17:37:57 +02:00
|
|
|
*
|
2019-11-25 12:52:42 +01:00
|
|
|
* Perform an implicit flush to var, leaving the runtime journal closed, now that the system
|
|
|
|
* journal is back.
|
2016-08-25 17:37:57 +02:00
|
|
|
*/
|
2016-12-12 20:54:45 +01:00
|
|
|
if (!flush_requested)
|
|
|
|
(void) server_flush_to_var(s, true);
|
2016-08-17 14:51:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!s->runtime_journal &&
|
|
|
|
(s->storage != STORAGE_NONE)) {
|
|
|
|
|
2016-10-04 17:13:21 +02:00
|
|
|
fn = strjoina(s->runtime_storage.path, "/system.journal");
|
2016-08-17 14:51:07 +02:00
|
|
|
|
2019-04-05 18:20:25 +02:00
|
|
|
if (s->system_journal && !relinquish_requested) {
|
2016-08-17 14:51:07 +02:00
|
|
|
|
|
|
|
/* Try to open the runtime journal, but only
|
|
|
|
* if it already exists, so that we can flush
|
|
|
|
* it into the system journal */
|
|
|
|
|
2016-10-04 17:13:21 +02:00
|
|
|
r = open_journal(s, false, fn, O_RDWR, false, &s->runtime_storage.metrics, &s->runtime_journal);
|
2016-08-17 14:51:07 +02:00
|
|
|
if (r < 0) {
|
|
|
|
if (r != -ENOENT)
|
|
|
|
log_warning_errno(r, "Failed to open runtime journal: %m");
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
2019-11-25 12:52:42 +01:00
|
|
|
/* OK, we really need the runtime journal, so create it if necessary. */
|
2016-08-17 14:51:07 +02:00
|
|
|
|
2019-11-25 12:52:42 +01:00
|
|
|
(void) mkdir_parents(s->runtime_storage.path, 0755);
|
|
|
|
(void) mkdir(s->runtime_storage.path, 0750);
|
2016-08-17 14:51:07 +02:00
|
|
|
|
2016-10-04 17:13:21 +02:00
|
|
|
r = open_journal(s, true, fn, O_RDWR|O_CREAT, false, &s->runtime_storage.metrics, &s->runtime_journal);
|
2016-08-17 14:51:07 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open runtime journal: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->runtime_journal) {
|
|
|
|
server_add_acls(s->runtime_journal, 0);
|
2016-10-12 10:09:45 +02:00
|
|
|
(void) cache_space_refresh(s, &s->runtime_storage);
|
2016-10-12 09:58:10 +02:00
|
|
|
patch_min_use(&s->runtime_storage);
|
2016-08-17 14:51:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
static JournalFile* find_journal(Server *s, uid_t uid) {
|
2013-06-06 01:15:43 +02:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2012-11-12 17:29:07 +01:00
|
|
|
JournalFile *f;
|
2019-11-22 16:24:57 +01:00
|
|
|
int r;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2019-11-22 16:24:57 +01:00
|
|
|
/* A rotate that fails to create the new journal (ENOSPC) leaves the rotated journal as NULL. Unless
|
|
|
|
* we revisit opening, even after space is made available we'll continue to return NULL indefinitely.
|
2016-08-17 14:51:07 +02:00
|
|
|
*
|
2019-11-22 16:24:57 +01:00
|
|
|
* system_journal_open() is a noop if the journals are already open, so we can just call it here to
|
|
|
|
* recover from failed rotates (or anything else that's left the journals as NULL).
|
2016-08-17 14:51:07 +02:00
|
|
|
*
|
|
|
|
* Fixes https://github.com/systemd/systemd/issues/3968 */
|
2019-04-05 18:20:25 +02:00
|
|
|
(void) system_journal_open(s, false, false);
|
2016-08-17 14:51:07 +02:00
|
|
|
|
2019-11-22 16:24:57 +01:00
|
|
|
/* We split up user logs only on /var, not on /run. If the runtime file is open, we write to it
|
|
|
|
* exclusively, in order to guarantee proper order as soon as we flush /run to /var and close the
|
|
|
|
* runtime file. */
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
if (s->runtime_journal)
|
|
|
|
return s->runtime_journal;
|
|
|
|
|
2017-12-30 15:17:39 +01:00
|
|
|
if (uid_for_system_journal(uid))
|
2012-11-12 17:29:07 +01:00
|
|
|
return s->system_journal;
|
|
|
|
|
2015-11-17 00:00:32 +01:00
|
|
|
f = ordered_hashmap_get(s->user_journals, UID_TO_PTR(uid));
|
2012-11-12 17:29:07 +01:00
|
|
|
if (f)
|
|
|
|
return f;
|
|
|
|
|
2019-11-22 16:24:57 +01:00
|
|
|
if (asprintf(&p, "%s/user-" UID_FMT ".journal", s->system_storage.path, uid) < 0) {
|
2018-10-25 18:35:55 +02:00
|
|
|
log_oom();
|
2012-11-12 17:29:07 +01:00
|
|
|
return s->system_journal;
|
2018-10-25 18:35:55 +02:00
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-11-22 16:24:57 +01:00
|
|
|
/* Too many open? Then let's close one (or more) */
|
2014-08-22 13:44:14 +02:00
|
|
|
while (ordered_hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) {
|
2019-11-22 16:24:57 +01:00
|
|
|
assert_se(f = ordered_hashmap_steal_first(s->user_journals));
|
2016-02-20 01:51:41 +01:00
|
|
|
(void) journal_file_close(f);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2016-10-04 17:13:21 +02:00
|
|
|
r = open_journal(s, true, p, O_RDWR|O_CREAT, s->seal, &s->system_storage.metrics, &f);
|
2012-11-12 17:29:07 +01:00
|
|
|
if (r < 0)
|
|
|
|
return s->system_journal;
|
|
|
|
|
2015-11-17 00:00:32 +01:00
|
|
|
r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f);
|
2012-11-12 17:29:07 +01:00
|
|
|
if (r < 0) {
|
2016-02-20 01:51:41 +01:00
|
|
|
(void) journal_file_close(f);
|
2012-11-12 17:29:07 +01:00
|
|
|
return s->system_journal;
|
|
|
|
}
|
|
|
|
|
2019-11-22 16:24:57 +01:00
|
|
|
server_add_acls(f, uid);
|
2012-11-12 17:29:07 +01:00
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2015-01-05 00:13:26 +01:00
|
|
|
static int do_rotate(
|
|
|
|
Server *s,
|
|
|
|
JournalFile **f,
|
|
|
|
const char* name,
|
|
|
|
bool seal,
|
|
|
|
uint32_t uid) {
|
|
|
|
|
2012-11-01 22:26:22 +01:00
|
|
|
int r;
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (!*f)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-02-27 18:37:23 +01:00
|
|
|
r = journal_file_rotate(f, s->compress.enabled, s->compress.threshold_bytes, seal, s->deferred_closes);
|
2018-01-15 15:53:05 +01:00
|
|
|
if (r < 0) {
|
2012-11-01 22:26:22 +01:00
|
|
|
if (*f)
|
2018-01-15 15:53:05 +01:00
|
|
|
return log_error_errno(r, "Failed to rotate %s: %m", (*f)->path);
|
2012-11-01 22:26:22 +01:00
|
|
|
else
|
2018-01-15 15:53:05 +01:00
|
|
|
return log_error_errno(r, "Failed to create new %s journal: %m", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
server_add_acls(*f, uid);
|
2012-11-01 22:26:22 +01:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2018-10-25 17:42:30 +02:00
|
|
|
static void server_process_deferred_closes(Server *s) {
|
|
|
|
JournalFile *f;
|
|
|
|
Iterator i;
|
|
|
|
|
|
|
|
/* Perform any deferred closes which aren't still offlining. */
|
2018-10-25 18:39:27 +02:00
|
|
|
SET_FOREACH(f, s->deferred_closes, i) {
|
|
|
|
if (journal_file_is_offlining(f))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
(void) set_remove(s->deferred_closes, f);
|
|
|
|
(void) journal_file_close(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void server_vacuum_deferred_closes(Server *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
/* Make some room in the deferred closes list, so that it doesn't grow without bounds */
|
|
|
|
if (set_size(s->deferred_closes) < DEFERRED_CLOSES_MAX)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Let's first remove all journal files that might already have completed closing */
|
|
|
|
server_process_deferred_closes(s);
|
|
|
|
|
|
|
|
/* And now, let's close some more until we reach the limit again. */
|
|
|
|
while (set_size(s->deferred_closes) >= DEFERRED_CLOSES_MAX) {
|
|
|
|
JournalFile *f;
|
|
|
|
|
|
|
|
assert_se(f = set_steal_first(s->deferred_closes));
|
|
|
|
journal_file_close(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-22 16:39:18 +01:00
|
|
|
static int vacuum_offline_user_journals(Server *s) {
|
|
|
|
_cleanup_closedir_ DIR *d = NULL;
|
2018-10-25 18:39:27 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2019-11-22 16:39:18 +01:00
|
|
|
d = opendir(s->system_storage.path);
|
|
|
|
if (!d) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return log_error_errno(errno, "Failed to open %s: %m", s->system_storage.path);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
_cleanup_free_ char *u = NULL, *full = NULL;
|
|
|
|
_cleanup_close_ int fd = -1;
|
|
|
|
const char *a, *b;
|
|
|
|
struct dirent *de;
|
|
|
|
JournalFile *f;
|
|
|
|
uid_t uid;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
de = readdir_no_dot(d);
|
|
|
|
if (!de) {
|
|
|
|
if (errno != 0)
|
|
|
|
log_warning_errno(errno, "Failed to enumerate %s, ignoring: %m", s->system_storage.path);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
a = startswith(de->d_name, "user-");
|
|
|
|
if (!a)
|
|
|
|
continue;
|
|
|
|
b = endswith(de->d_name, ".journal");
|
|
|
|
if (!b)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
u = strndup(a, b-a);
|
|
|
|
if (!u)
|
|
|
|
return log_oom();
|
2018-10-25 18:39:27 +02:00
|
|
|
|
2019-11-22 16:39:18 +01:00
|
|
|
r = parse_uid(u, &uid);
|
|
|
|
if (r < 0) {
|
|
|
|
log_debug_errno(r, "Failed to parse UID from file name '%s', ignoring: %m", de->d_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Already rotated in the above loop? i.e. is it an open user journal? */
|
|
|
|
if (ordered_hashmap_contains(s->user_journals, UID_TO_PTR(uid)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
full = path_join(s->system_storage.path, de->d_name);
|
|
|
|
if (!full)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
fd = openat(dirfd(d), de->d_name, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
|
|
|
|
if (fd < 0) {
|
|
|
|
log_full_errno(IN_SET(errno, ELOOP, ENOENT) ? LOG_DEBUG : LOG_WARNING, errno,
|
|
|
|
"Failed to open journal file '%s' for rotation: %m", full);
|
|
|
|
continue;
|
|
|
|
}
|
2018-10-25 18:39:27 +02:00
|
|
|
|
2019-11-22 16:39:18 +01:00
|
|
|
/* Make some room in the set of deferred close()s */
|
|
|
|
server_vacuum_deferred_closes(s);
|
|
|
|
|
|
|
|
/* Open the file briefly, so that we can archive it */
|
|
|
|
r = journal_file_open(fd,
|
|
|
|
full,
|
|
|
|
O_RDWR,
|
|
|
|
0640,
|
|
|
|
s->compress.enabled,
|
|
|
|
s->compress.threshold_bytes,
|
|
|
|
s->seal,
|
|
|
|
&s->system_storage.metrics,
|
|
|
|
s->mmap,
|
|
|
|
s->deferred_closes,
|
|
|
|
NULL,
|
|
|
|
&f);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "Failed to read journal file %s for rotation, trying to move it out of the way: %m", full);
|
|
|
|
|
|
|
|
r = journal_file_dispose(dirfd(d), de->d_name);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to move %s out of the way, ignoring: %m", full);
|
|
|
|
else
|
|
|
|
log_debug("Successfully moved %s out of the way.", full);
|
2018-10-25 18:39:27 +02:00
|
|
|
|
2019-11-22 16:39:18 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
TAKE_FD(fd); /* Donated to journal_file_open() */
|
|
|
|
|
|
|
|
r = journal_file_archive(f);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to archive journal file '%s', ignoring: %m", full);
|
|
|
|
|
|
|
|
f = journal_initiate_close(f, s->deferred_closes);
|
|
|
|
}
|
2018-10-25 18:39:27 +02:00
|
|
|
|
|
|
|
return 0;
|
2018-10-25 17:42:30 +02:00
|
|
|
}
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
void server_rotate(Server *s) {
|
|
|
|
JournalFile *f;
|
|
|
|
Iterator i;
|
2018-10-25 18:39:27 +02:00
|
|
|
void *k;
|
2012-11-12 17:29:07 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
log_debug("Rotating...");
|
|
|
|
|
2018-10-25 18:39:27 +02:00
|
|
|
/* First, rotate the system journal (either in its runtime flavour or in its runtime flavour) */
|
2015-10-02 23:21:59 +02:00
|
|
|
(void) do_rotate(s, &s->runtime_journal, "runtime", false, 0);
|
|
|
|
(void) do_rotate(s, &s->system_journal, "system", s->seal, 0);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2018-10-25 18:39:27 +02:00
|
|
|
/* Then, rotate all user journals we have open (keeping them open) */
|
2014-08-22 13:44:14 +02:00
|
|
|
ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
|
2015-11-17 00:00:32 +01:00
|
|
|
r = do_rotate(s, &f, "user", s->seal, PTR_TO_UID(k));
|
2012-11-01 22:26:22 +01:00
|
|
|
if (r >= 0)
|
2014-08-22 13:44:14 +02:00
|
|
|
ordered_hashmap_replace(s->user_journals, k, f);
|
2012-11-01 22:26:22 +01:00
|
|
|
else if (!f)
|
|
|
|
/* Old file has been closed and deallocated */
|
2014-08-22 13:44:14 +02:00
|
|
|
ordered_hashmap_remove(s->user_journals, k);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
2016-02-18 02:37:10 +01:00
|
|
|
|
2019-11-22 16:39:18 +01:00
|
|
|
/* Finally, also rotate all user journals we currently do not have open. (But do so only if we
|
|
|
|
* actually have access to /var, i.e. are not in the log-to-runtime-journal mode). */
|
|
|
|
if (!s->runtime_journal)
|
|
|
|
(void) vacuum_offline_user_journals(s);
|
2018-10-25 18:39:27 +02:00
|
|
|
|
2018-10-25 17:42:30 +02:00
|
|
|
server_process_deferred_closes(s);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2013-03-25 17:49:03 +01:00
|
|
|
void server_sync(Server *s) {
|
|
|
|
JournalFile *f;
|
|
|
|
Iterator i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (s->system_journal) {
|
2016-02-12 13:59:57 +01:00
|
|
|
r = journal_file_set_offline(s->system_journal, false);
|
2013-03-25 17:49:03 +01:00
|
|
|
if (r < 0)
|
2015-10-02 23:19:00 +02:00
|
|
|
log_warning_errno(r, "Failed to sync system journal, ignoring: %m");
|
2013-03-25 17:49:03 +01:00
|
|
|
}
|
|
|
|
|
2015-11-17 00:02:43 +01:00
|
|
|
ORDERED_HASHMAP_FOREACH(f, s->user_journals, i) {
|
2016-02-12 13:59:57 +01:00
|
|
|
r = journal_file_set_offline(f, false);
|
2013-03-25 17:49:03 +01:00
|
|
|
if (r < 0)
|
2015-10-02 23:19:00 +02:00
|
|
|
log_warning_errno(r, "Failed to sync user journal, ignoring: %m");
|
2013-03-25 17:49:03 +01:00
|
|
|
}
|
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
if (s->sync_event_source) {
|
|
|
|
r = sd_event_source_set_enabled(s->sync_event_source, SD_EVENT_OFF);
|
|
|
|
if (r < 0)
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to disable sync timer source: %m");
|
2013-12-11 20:13:44 +01:00
|
|
|
}
|
2013-03-25 17:49:03 +01:00
|
|
|
|
|
|
|
s->sync_scheduled = false;
|
|
|
|
}
|
|
|
|
|
2016-10-12 09:58:10 +02:00
|
|
|
static void do_vacuum(Server *s, JournalStorage *storage, bool verbose) {
|
2015-01-05 00:13:26 +01:00
|
|
|
|
2012-11-01 22:36:52 +01:00
|
|
|
int r;
|
|
|
|
|
2015-10-02 23:21:59 +02:00
|
|
|
assert(s);
|
2016-10-04 17:13:21 +02:00
|
|
|
assert(storage);
|
2015-10-02 23:21:59 +02:00
|
|
|
|
2016-10-12 10:09:45 +02:00
|
|
|
(void) cache_space_refresh(s, storage);
|
2016-10-11 16:51:37 +02:00
|
|
|
|
|
|
|
if (verbose)
|
|
|
|
server_space_usage_message(s, storage);
|
2015-10-02 23:21:59 +02:00
|
|
|
|
2016-10-12 10:09:45 +02:00
|
|
|
r = journal_directory_vacuum(storage->path, storage->space.limit,
|
|
|
|
storage->metrics.n_max_files, s->max_retention_usec,
|
|
|
|
&s->oldest_file_usec, verbose);
|
2012-11-01 22:36:52 +01:00
|
|
|
if (r < 0 && r != -ENOENT)
|
2016-10-04 17:13:21 +02:00
|
|
|
log_warning_errno(r, "Failed to vacuum %s, ignoring: %m", storage->path);
|
|
|
|
|
2016-10-12 09:05:55 +02:00
|
|
|
cache_space_invalidate(&storage->space);
|
2012-11-01 22:36:52 +01:00
|
|
|
}
|
|
|
|
|
2016-10-12 09:58:10 +02:00
|
|
|
int server_vacuum(Server *s, bool verbose) {
|
2015-10-02 23:21:59 +02:00
|
|
|
assert(s);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
log_debug("Vacuuming...");
|
|
|
|
|
|
|
|
s->oldest_file_usec = 0;
|
|
|
|
|
2016-10-04 17:13:21 +02:00
|
|
|
if (s->system_journal)
|
2016-10-12 09:58:10 +02:00
|
|
|
do_vacuum(s, &s->system_storage, verbose);
|
2016-10-04 17:13:21 +02:00
|
|
|
if (s->runtime_journal)
|
2016-10-12 09:58:10 +02:00
|
|
|
do_vacuum(s, &s->runtime_storage, verbose);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-10-02 23:21:59 +02:00
|
|
|
return 0;
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2013-12-11 22:55:57 +01:00
|
|
|
static void server_cache_machine_id(Server *s) {
|
|
|
|
sd_id128_t id;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
r = sd_id128_get_machine(&id);
|
|
|
|
if (r < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sd_id128_to_string(id, stpcpy(s->machine_id_field, "_MACHINE_ID="));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void server_cache_boot_id(Server *s) {
|
|
|
|
sd_id128_t id;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
r = sd_id128_get_boot(&id);
|
|
|
|
if (r < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sd_id128_to_string(id, stpcpy(s->boot_id_field, "_BOOT_ID="));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void server_cache_hostname(Server *s) {
|
|
|
|
_cleanup_free_ char *t = NULL;
|
|
|
|
char *x;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
t = gethostname_malloc();
|
|
|
|
if (!t)
|
|
|
|
return;
|
|
|
|
|
2019-07-11 19:14:16 +02:00
|
|
|
x = strjoin("_HOSTNAME=", t);
|
2013-12-11 22:55:57 +01:00
|
|
|
if (!x)
|
|
|
|
return;
|
|
|
|
|
2019-11-22 14:09:35 +01:00
|
|
|
free_and_replace(s->hostname_field, x);
|
2013-12-11 22:55:57 +01:00
|
|
|
}
|
|
|
|
|
2015-01-04 22:09:07 +01:00
|
|
|
static bool shall_try_append_again(JournalFile *f, int r) {
|
2016-04-17 00:31:42 +02:00
|
|
|
switch(r) {
|
2016-10-12 18:53:35 +02:00
|
|
|
|
2016-04-17 00:31:42 +02:00
|
|
|
case -E2BIG: /* Hit configured limit */
|
|
|
|
case -EFBIG: /* Hit fs limit */
|
|
|
|
case -EDQUOT: /* Quota limit hit */
|
|
|
|
case -ENOSPC: /* Disk full */
|
2012-11-12 17:29:07 +01:00
|
|
|
log_debug("%s: Allocation limit reached, rotating.", f->path);
|
2016-04-17 00:31:42 +02:00
|
|
|
return true;
|
2016-10-12 18:53:35 +02:00
|
|
|
|
2016-04-17 00:31:42 +02:00
|
|
|
case -EIO: /* I/O error of some kind (mmap) */
|
|
|
|
log_warning("%s: IO error, rotating.", f->path);
|
|
|
|
return true;
|
2016-10-12 18:53:35 +02:00
|
|
|
|
2016-04-17 00:31:42 +02:00
|
|
|
case -EHOSTDOWN: /* Other machine */
|
2012-11-12 17:29:07 +01:00
|
|
|
log_info("%s: Journal file from other machine, rotating.", f->path);
|
2016-04-17 00:31:42 +02:00
|
|
|
return true;
|
2016-10-12 18:53:35 +02:00
|
|
|
|
2016-04-17 00:31:42 +02:00
|
|
|
case -EBUSY: /* Unclean shutdown */
|
2012-11-12 17:29:07 +01:00
|
|
|
log_info("%s: Unclean shutdown, rotating.", f->path);
|
2016-04-17 00:31:42 +02:00
|
|
|
return true;
|
2016-10-12 18:53:35 +02:00
|
|
|
|
2016-04-17 00:31:42 +02:00
|
|
|
case -EPROTONOSUPPORT: /* Unsupported feature */
|
2012-11-12 17:29:07 +01:00
|
|
|
log_info("%s: Unsupported feature, rotating.", f->path);
|
2016-04-17 00:31:42 +02:00
|
|
|
return true;
|
2016-10-12 18:53:35 +02:00
|
|
|
|
2016-04-17 00:31:42 +02:00
|
|
|
case -EBADMSG: /* Corrupted */
|
|
|
|
case -ENODATA: /* Truncated */
|
|
|
|
case -ESHUTDOWN: /* Already archived */
|
2012-11-12 17:29:07 +01:00
|
|
|
log_warning("%s: Journal file corrupted, rotating.", f->path);
|
2016-04-17 00:31:42 +02:00
|
|
|
return true;
|
2016-10-12 18:53:35 +02:00
|
|
|
|
2016-04-17 00:31:42 +02:00
|
|
|
case -EIDRM: /* Journal file has been deleted */
|
2015-01-05 02:09:01 +01:00
|
|
|
log_warning("%s: Journal file has been deleted, rotating.", f->path);
|
2016-04-17 00:31:42 +02:00
|
|
|
return true;
|
2016-10-12 18:53:35 +02:00
|
|
|
|
|
|
|
case -ETXTBSY: /* Journal file is from the future */
|
2016-10-13 13:42:39 +02:00
|
|
|
log_warning("%s: Journal file is from the future, rotating.", f->path);
|
2016-10-12 18:53:35 +02:00
|
|
|
return true;
|
|
|
|
|
2019-05-22 18:48:02 +02:00
|
|
|
case -EAFNOSUPPORT:
|
|
|
|
log_warning("%s: underlying file system does not support memory mapping or another required file system feature.", f->path);
|
|
|
|
return false;
|
|
|
|
|
2016-04-17 00:31:42 +02:00
|
|
|
default:
|
2012-11-12 17:29:07 +01:00
|
|
|
return false;
|
2016-04-17 00:31:42 +02:00
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
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
|
|
|
static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n, int priority) {
|
2016-10-12 18:49:51 +02:00
|
|
|
bool vacuumed = false, rotate = false;
|
2016-10-12 18:46:07 +02:00
|
|
|
struct dual_timestamp ts;
|
2012-11-12 17:29:07 +01:00
|
|
|
JournalFile *f;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(iovec);
|
|
|
|
assert(n > 0);
|
|
|
|
|
2016-10-12 18:46:07 +02:00
|
|
|
/* Get the closest, linearized time we have for this log event from the event loop. (Note that we do not use
|
|
|
|
* the source time, and not even the time the event was originally seen, but instead simply the time we started
|
|
|
|
* processing it, as we want strictly linear ordering in what we write out.) */
|
|
|
|
assert_se(sd_event_now(s->event, CLOCK_REALTIME, &ts.realtime) >= 0);
|
|
|
|
assert_se(sd_event_now(s->event, CLOCK_MONOTONIC, &ts.monotonic) >= 0);
|
|
|
|
|
2016-10-12 18:49:51 +02:00
|
|
|
if (ts.realtime < s->last_realtime_clock) {
|
|
|
|
/* When the time jumps backwards, let's immediately rotate. Of course, this should not happen during
|
|
|
|
* regular operation. However, when it does happen, then we should make sure that we start fresh files
|
|
|
|
* to ensure that the entries in the journal files are strictly ordered by time, in order to ensure
|
|
|
|
* bisection works correctly. */
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2016-10-12 18:49:51 +02:00
|
|
|
log_debug("Time jumped backwards, rotating.");
|
|
|
|
rotate = true;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
f = find_journal(s, uid);
|
|
|
|
if (!f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (journal_file_rotate_suggested(f, s->max_file_usec)) {
|
|
|
|
log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path);
|
|
|
|
rotate = true;
|
|
|
|
}
|
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2016-10-12 18:49:51 +02:00
|
|
|
if (rotate) {
|
2012-11-12 17:29:07 +01:00
|
|
|
server_rotate(s);
|
2016-10-12 09:58:10 +02:00
|
|
|
server_vacuum(s, false);
|
2012-11-12 17:29:07 +01:00
|
|
|
vacuumed = true;
|
|
|
|
|
|
|
|
f = find_journal(s, uid);
|
|
|
|
if (!f)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-12 18:49:51 +02:00
|
|
|
s->last_realtime_clock = ts.realtime;
|
|
|
|
|
2018-05-27 11:27:58 +02:00
|
|
|
r = journal_file_append_entry(f, &ts, NULL, iovec, n, &s->seqnum, NULL, NULL);
|
2013-03-25 17:49:03 +01:00
|
|
|
if (r >= 0) {
|
2013-07-24 08:08:57 +02:00
|
|
|
server_schedule_sync(s, priority);
|
2012-11-12 17:29:07 +01:00
|
|
|
return;
|
2013-03-25 17:49:03 +01:00
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
if (vacuumed || !shall_try_append_again(f, r)) {
|
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
|
|
|
log_error_errno(r, "Failed to write entry (%zu items, %zu bytes), ignoring: %m", n, IOVEC_TOTAL_SIZE(iovec, n));
|
2012-11-12 17:29:07 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
server_rotate(s);
|
2016-10-12 09:58:10 +02:00
|
|
|
server_vacuum(s, false);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
f = find_journal(s, uid);
|
|
|
|
if (!f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
log_debug("Retrying write.");
|
2018-05-27 11:27:58 +02:00
|
|
|
r = journal_file_append_entry(f, &ts, NULL, iovec, n, &s->seqnum, NULL, NULL);
|
2015-01-05 02:48:50 +01:00
|
|
|
if (r < 0)
|
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
|
|
|
log_error_errno(r, "Failed to write entry (%zu items, %zu bytes) despite vacuuming, ignoring: %m", n, IOVEC_TOTAL_SIZE(iovec, n));
|
2015-01-05 02:48:50 +01:00
|
|
|
else
|
2013-07-24 08:08:57 +02:00
|
|
|
server_schedule_sync(s, priority);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
#define IOVEC_ADD_NUMERIC_FIELD(iovec, n, value, type, isset, format, field) \
|
|
|
|
if (isset(value)) { \
|
|
|
|
char *k; \
|
2017-12-14 19:02:29 +01:00
|
|
|
k = newa(char, STRLEN(field "=") + DECIMAL_STR_MAX(type) + 1); \
|
2017-07-17 23:36:35 +02:00
|
|
|
sprintf(k, field "=" format, value); \
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(k); \
|
2017-07-17 23:36:35 +02:00
|
|
|
}
|
2016-08-30 23:18:46 +02:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
#define IOVEC_ADD_STRING_FIELD(iovec, n, value, field) \
|
|
|
|
if (!isempty(value)) { \
|
|
|
|
char *k; \
|
|
|
|
k = strjoina(field "=", value); \
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(k); \
|
2017-07-17 23:36:35 +02:00
|
|
|
}
|
2016-08-30 23:18:46 +02:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
#define IOVEC_ADD_ID128_FIELD(iovec, n, value, field) \
|
|
|
|
if (!sd_id128_is_null(value)) { \
|
|
|
|
char *k; \
|
2017-12-14 19:02:29 +01:00
|
|
|
k = newa(char, STRLEN(field "=") + SD_ID128_STRING_MAX); \
|
2017-07-17 23:36:35 +02:00
|
|
|
sd_id128_to_string(value, stpcpy(k, field "=")); \
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(k); \
|
2017-07-17 23:36:35 +02:00
|
|
|
}
|
2016-08-30 23:18:46 +02:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
#define IOVEC_ADD_SIZED_FIELD(iovec, n, value, value_size, field) \
|
|
|
|
if (value_size > 0) { \
|
|
|
|
char *k; \
|
2017-12-14 19:02:29 +01:00
|
|
|
k = newa(char, STRLEN(field "=") + value_size + 1); \
|
2017-07-17 23:36:35 +02:00
|
|
|
*((char*) mempcpy(stpcpy(k, field "="), value, value_size)) = 0; \
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(k); \
|
2017-07-17 23:36:35 +02:00
|
|
|
} \
|
2016-08-30 23:18:46 +02:00
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
static void dispatch_message_real(
|
|
|
|
Server *s,
|
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
|
|
|
struct iovec *iovec, size_t n, size_t m,
|
2017-07-17 23:36:35 +02:00
|
|
|
const ClientContext *c,
|
2014-11-02 21:46:42 +01:00
|
|
|
const struct timeval *tv,
|
2013-07-24 08:08:57 +02:00
|
|
|
int priority,
|
2017-07-17 23:36:35 +02:00
|
|
|
pid_t object_pid) {
|
|
|
|
|
|
|
|
char source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)];
|
2018-12-05 18:38:39 +01:00
|
|
|
_cleanup_free_ char *cmdline1 = NULL, *cmdline2 = NULL;
|
2017-07-17 23:36:35 +02:00
|
|
|
uid_t journal_uid;
|
|
|
|
ClientContext *o;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(iovec);
|
|
|
|
assert(n > 0);
|
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
|
|
|
assert(n +
|
|
|
|
N_IOVEC_META_FIELDS +
|
|
|
|
(pid_is_valid(object_pid) ? N_IOVEC_OBJECT_FIELDS : 0) +
|
|
|
|
client_context_extra_fields_n_iovec(c) <= m);
|
2013-07-19 19:52:30 +02:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
if (c) {
|
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->pid, pid_t, pid_is_valid, PID_FMT, "_PID");
|
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->uid, uid_t, uid_is_valid, UID_FMT, "_UID");
|
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->gid, gid_t, gid_is_valid, GID_FMT, "_GID");
|
2016-08-30 23:18:46 +02:00
|
|
|
|
2018-12-05 18:38:39 +01:00
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, c->comm, "_COMM"); /* At most TASK_COMM_LENGTH (16 bytes) */
|
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, c->exe, "_EXE"); /* A path, so at most PATH_MAX (4096 bytes) */
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2018-12-05 18:38:39 +01:00
|
|
|
if (c->cmdline)
|
|
|
|
/* At most _SC_ARG_MAX (2MB usually), which is too much to put on stack.
|
|
|
|
* Let's use a heap allocation for this one. */
|
|
|
|
cmdline1 = set_iovec_string_field(iovec, &n, "_CMDLINE=", c->cmdline);
|
2013-04-23 04:10:13 +02:00
|
|
|
|
2018-12-05 18:38:39 +01:00
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, c->capeff, "_CAP_EFFECTIVE"); /* Read from /proc/.../status */
|
|
|
|
IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT");
|
2017-07-17 23:36:35 +02:00
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "_AUDIT_SESSION");
|
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->loginuid, uid_t, uid_is_valid, UID_FMT, "_AUDIT_LOGINUID");
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2018-12-05 18:38:39 +01:00
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, c->cgroup, "_SYSTEMD_CGROUP"); /* A path */
|
2017-07-17 23:36:35 +02:00
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, c->session, "_SYSTEMD_SESSION");
|
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->owner_uid, uid_t, uid_is_valid, UID_FMT, "_SYSTEMD_OWNER_UID");
|
2018-12-05 18:38:39 +01:00
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, c->unit, "_SYSTEMD_UNIT"); /* Unit names are bounded by UNIT_NAME_MAX */
|
2017-07-17 23:36:35 +02:00
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, c->user_unit, "_SYSTEMD_USER_UNIT");
|
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, c->slice, "_SYSTEMD_SLICE");
|
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, c->user_slice, "_SYSTEMD_USER_SLICE");
|
2013-04-24 22:04:27 +02:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
IOVEC_ADD_ID128_FIELD(iovec, n, c->invocation_id, "_SYSTEMD_INVOCATION_ID");
|
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
|
|
|
|
|
|
|
if (c->extra_fields_n_iovec > 0) {
|
|
|
|
memcpy(iovec + n, c->extra_fields_iovec, c->extra_fields_n_iovec * sizeof(struct iovec));
|
|
|
|
n += c->extra_fields_n_iovec;
|
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
journal: allow callers to specify OBJECT_PID=
When journald encounters a message with OBJECT_PID= set
coming from a priviledged process (UID==0), additional fields
will be added to the message:
OBJECT_UID=,
OBJECT_GID=,
OBJECT_COMM=,
OBJECT_EXE=,
OBJECT_CMDLINE=,
OBJECT_AUDIT_SESSION=,
OBJECT_AUDIT_LOGINUID=,
OBJECT_SYSTEMD_CGROUP=,
OBJECT_SYSTEMD_SESSION=,
OBJECT_SYSTEMD_OWNER_UID=,
OBJECT_SYSTEMD_UNIT= or OBJECT_SYSTEMD_USER_UNIT=.
This is for other logging daemons, like setroubleshoot, to be able to
augment their logs with data about the process.
https://bugzilla.redhat.com/show_bug.cgi?id=951627
2013-06-12 06:24:34 +02:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
assert(n <= m);
|
journal: allow callers to specify OBJECT_PID=
When journald encounters a message with OBJECT_PID= set
coming from a priviledged process (UID==0), additional fields
will be added to the message:
OBJECT_UID=,
OBJECT_GID=,
OBJECT_COMM=,
OBJECT_EXE=,
OBJECT_CMDLINE=,
OBJECT_AUDIT_SESSION=,
OBJECT_AUDIT_LOGINUID=,
OBJECT_SYSTEMD_CGROUP=,
OBJECT_SYSTEMD_SESSION=,
OBJECT_SYSTEMD_OWNER_UID=,
OBJECT_SYSTEMD_UNIT= or OBJECT_SYSTEMD_USER_UNIT=.
This is for other logging daemons, like setroubleshoot, to be able to
augment their logs with data about the process.
https://bugzilla.redhat.com/show_bug.cgi?id=951627
2013-06-12 06:24:34 +02:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
if (pid_is_valid(object_pid) && client_context_get(s, object_pid, NULL, NULL, 0, NULL, &o) >= 0) {
|
journal: allow callers to specify OBJECT_PID=
When journald encounters a message with OBJECT_PID= set
coming from a priviledged process (UID==0), additional fields
will be added to the message:
OBJECT_UID=,
OBJECT_GID=,
OBJECT_COMM=,
OBJECT_EXE=,
OBJECT_CMDLINE=,
OBJECT_AUDIT_SESSION=,
OBJECT_AUDIT_LOGINUID=,
OBJECT_SYSTEMD_CGROUP=,
OBJECT_SYSTEMD_SESSION=,
OBJECT_SYSTEMD_OWNER_UID=,
OBJECT_SYSTEMD_UNIT= or OBJECT_SYSTEMD_USER_UNIT=.
This is for other logging daemons, like setroubleshoot, to be able to
augment their logs with data about the process.
https://bugzilla.redhat.com/show_bug.cgi?id=951627
2013-06-12 06:24:34 +02:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->pid, pid_t, pid_is_valid, PID_FMT, "OBJECT_PID");
|
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->uid, uid_t, uid_is_valid, UID_FMT, "OBJECT_UID");
|
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->gid, gid_t, gid_is_valid, GID_FMT, "OBJECT_GID");
|
journal: allow callers to specify OBJECT_PID=
When journald encounters a message with OBJECT_PID= set
coming from a priviledged process (UID==0), additional fields
will be added to the message:
OBJECT_UID=,
OBJECT_GID=,
OBJECT_COMM=,
OBJECT_EXE=,
OBJECT_CMDLINE=,
OBJECT_AUDIT_SESSION=,
OBJECT_AUDIT_LOGINUID=,
OBJECT_SYSTEMD_CGROUP=,
OBJECT_SYSTEMD_SESSION=,
OBJECT_SYSTEMD_OWNER_UID=,
OBJECT_SYSTEMD_UNIT= or OBJECT_SYSTEMD_USER_UNIT=.
This is for other logging daemons, like setroubleshoot, to be able to
augment their logs with data about the process.
https://bugzilla.redhat.com/show_bug.cgi?id=951627
2013-06-12 06:24:34 +02:00
|
|
|
|
2018-12-05 18:38:39 +01:00
|
|
|
/* See above for size limits, only ->cmdline may be large, so use a heap allocation for it. */
|
2017-07-17 23:36:35 +02:00
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, o->comm, "OBJECT_COMM");
|
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, o->exe, "OBJECT_EXE");
|
2018-12-05 18:38:39 +01:00
|
|
|
if (o->cmdline)
|
|
|
|
cmdline2 = set_iovec_string_field(iovec, &n, "OBJECT_CMDLINE=", o->cmdline);
|
journal: allow callers to specify OBJECT_PID=
When journald encounters a message with OBJECT_PID= set
coming from a priviledged process (UID==0), additional fields
will be added to the message:
OBJECT_UID=,
OBJECT_GID=,
OBJECT_COMM=,
OBJECT_EXE=,
OBJECT_CMDLINE=,
OBJECT_AUDIT_SESSION=,
OBJECT_AUDIT_LOGINUID=,
OBJECT_SYSTEMD_CGROUP=,
OBJECT_SYSTEMD_SESSION=,
OBJECT_SYSTEMD_OWNER_UID=,
OBJECT_SYSTEMD_UNIT= or OBJECT_SYSTEMD_USER_UNIT=.
This is for other logging daemons, like setroubleshoot, to be able to
augment their logs with data about the process.
https://bugzilla.redhat.com/show_bug.cgi?id=951627
2013-06-12 06:24:34 +02:00
|
|
|
|
2018-12-05 18:38:39 +01:00
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, o->capeff, "OBJECT_CAP_EFFECTIVE");
|
2017-07-17 23:36:35 +02:00
|
|
|
IOVEC_ADD_SIZED_FIELD(iovec, n, o->label, o->label_size, "OBJECT_SELINUX_CONTEXT");
|
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "OBJECT_AUDIT_SESSION");
|
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->loginuid, uid_t, uid_is_valid, UID_FMT, "OBJECT_AUDIT_LOGINUID");
|
2016-08-30 21:00:52 +02:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, o->cgroup, "OBJECT_SYSTEMD_CGROUP");
|
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, o->session, "OBJECT_SYSTEMD_SESSION");
|
|
|
|
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->owner_uid, uid_t, uid_is_valid, UID_FMT, "OBJECT_SYSTEMD_OWNER_UID");
|
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, o->unit, "OBJECT_SYSTEMD_UNIT");
|
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, o->user_unit, "OBJECT_SYSTEMD_USER_UNIT");
|
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, o->slice, "OBJECT_SYSTEMD_SLICE");
|
|
|
|
IOVEC_ADD_STRING_FIELD(iovec, n, o->user_slice, "OBJECT_SYSTEMD_USER_SLICE");
|
2016-08-30 21:00:52 +02:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
IOVEC_ADD_ID128_FIELD(iovec, n, o->invocation_id, "OBJECT_SYSTEMD_INVOCATION_ID=");
|
journal: allow callers to specify OBJECT_PID=
When journald encounters a message with OBJECT_PID= set
coming from a priviledged process (UID==0), additional fields
will be added to the message:
OBJECT_UID=,
OBJECT_GID=,
OBJECT_COMM=,
OBJECT_EXE=,
OBJECT_CMDLINE=,
OBJECT_AUDIT_SESSION=,
OBJECT_AUDIT_LOGINUID=,
OBJECT_SYSTEMD_CGROUP=,
OBJECT_SYSTEMD_SESSION=,
OBJECT_SYSTEMD_OWNER_UID=,
OBJECT_SYSTEMD_UNIT= or OBJECT_SYSTEMD_USER_UNIT=.
This is for other logging daemons, like setroubleshoot, to be able to
augment their logs with data about the process.
https://bugzilla.redhat.com/show_bug.cgi?id=951627
2013-06-12 06:24:34 +02:00
|
|
|
}
|
2017-07-17 23:36:35 +02:00
|
|
|
|
journal: allow callers to specify OBJECT_PID=
When journald encounters a message with OBJECT_PID= set
coming from a priviledged process (UID==0), additional fields
will be added to the message:
OBJECT_UID=,
OBJECT_GID=,
OBJECT_COMM=,
OBJECT_EXE=,
OBJECT_CMDLINE=,
OBJECT_AUDIT_SESSION=,
OBJECT_AUDIT_LOGINUID=,
OBJECT_SYSTEMD_CGROUP=,
OBJECT_SYSTEMD_SESSION=,
OBJECT_SYSTEMD_OWNER_UID=,
OBJECT_SYSTEMD_UNIT= or OBJECT_SYSTEMD_USER_UNIT=.
This is for other logging daemons, like setroubleshoot, to be able to
augment their logs with data about the process.
https://bugzilla.redhat.com/show_bug.cgi?id=951627
2013-06-12 06:24:34 +02:00
|
|
|
assert(n <= m);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
if (tv) {
|
2016-08-30 21:01:58 +02:00
|
|
|
sprintf(source_time, "_SOURCE_REALTIME_TIMESTAMP=" USEC_FMT, timeval_load(tv));
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(source_time);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Note that strictly speaking storing the boot id here is
|
|
|
|
* redundant since the entry includes this in-line
|
|
|
|
* anyway. However, we need this indexed, too. */
|
2013-12-11 22:55:57 +01:00
|
|
|
if (!isempty(s->boot_id_field))
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(s->boot_id_field);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-12-11 22:55:57 +01:00
|
|
|
if (!isempty(s->machine_id_field))
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(s->machine_id_field);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-12-11 22:55:57 +01:00
|
|
|
if (!isempty(s->hostname_field))
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(s->hostname_field);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
if (!isempty(s->namespace_field))
|
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(s->namespace_field);
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
assert(n <= m);
|
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
if (s->split_mode == SPLIT_UID && c && uid_is_valid(c->uid))
|
|
|
|
/* Split up strictly by (non-root) UID */
|
|
|
|
journal_uid = c->uid;
|
|
|
|
else if (s->split_mode == SPLIT_LOGIN && c && c->uid > 0 && uid_is_valid(c->owner_uid))
|
2014-06-19 12:36:35 +02:00
|
|
|
/* Split up by login UIDs. We do this only if the
|
|
|
|
* realuid is not root, in order not to accidentally
|
|
|
|
* leak privileged information to the user that is
|
|
|
|
* logged by a privileged process that is part of an
|
2014-12-10 20:00:06 +01:00
|
|
|
* unprivileged session. */
|
2017-07-17 23:36:35 +02:00
|
|
|
journal_uid = c->owner_uid;
|
2013-03-04 15:17:45 +01:00
|
|
|
else
|
|
|
|
journal_uid = 0;
|
2013-02-12 18:24:30 +01:00
|
|
|
|
2013-07-24 08:08:57 +02:00
|
|
|
write_to_journal(s, journal_uid, iovec, n, priority);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2017-10-30 20:01:50 +01:00
|
|
|
void server_driver_message(Server *s, pid_t object_pid, const char *message_id, const char *format, ...) {
|
2017-07-17 23:36:35 +02:00
|
|
|
|
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
|
|
|
struct iovec *iovec;
|
|
|
|
size_t n = 0, k, m;
|
2012-11-12 17:29:07 +01:00
|
|
|
va_list ap;
|
2017-07-17 23:36:35 +02:00
|
|
|
int r;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(format);
|
|
|
|
|
2017-11-29 11:36:22 +01:00
|
|
|
m = N_IOVEC_META_FIELDS + 5 + N_IOVEC_PAYLOAD_FIELDS + client_context_extra_fields_n_iovec(s->my_context) + N_IOVEC_OBJECT_FIELDS;
|
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
|
|
|
iovec = newa(struct iovec, m);
|
|
|
|
|
2016-01-26 13:48:57 +01:00
|
|
|
assert_cc(3 == LOG_FAC(LOG_DAEMON));
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING("SYSLOG_FACILITY=3");
|
|
|
|
iovec[n++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=systemd-journald");
|
2015-10-01 02:36:11 +02:00
|
|
|
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=driver");
|
2016-01-26 13:48:57 +01:00
|
|
|
assert_cc(6 == LOG_INFO);
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING("PRIORITY=6");
|
2012-11-12 17:29:07 +01:00
|
|
|
|
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
|
|
|
if (message_id)
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(message_id);
|
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
|
|
|
k = n;
|
2015-11-08 20:05:55 +01:00
|
|
|
|
|
|
|
va_start(ap, format);
|
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
|
|
|
r = log_format_iovec(iovec, m, &n, false, 0, format, ap);
|
2015-11-11 13:54:50 +01:00
|
|
|
/* Error handling below */
|
2015-11-08 20:05:55 +01:00
|
|
|
va_end(ap);
|
|
|
|
|
2015-11-11 13:54:50 +01:00
|
|
|
if (r >= 0)
|
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
|
|
|
dispatch_message_real(s, iovec, n, m, s->my_context, NULL, LOG_INFO, object_pid);
|
2015-11-08 20:05:55 +01:00
|
|
|
|
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
|
|
|
while (k < n)
|
|
|
|
free(iovec[k++].iov_base);
|
2015-11-11 13:54:50 +01:00
|
|
|
|
|
|
|
if (r < 0) {
|
|
|
|
/* We failed to format the message. Emit a warning instead. */
|
|
|
|
char buf[LINE_MAX];
|
|
|
|
|
2019-07-03 16:56:17 +02:00
|
|
|
xsprintf(buf, "MESSAGE=Entry printing failed: %s", strerror_safe(r));
|
2015-11-11 13:54:50 +01:00
|
|
|
|
|
|
|
n = 3;
|
2017-09-21 13:52:34 +02:00
|
|
|
iovec[n++] = IOVEC_MAKE_STRING("PRIORITY=4");
|
|
|
|
iovec[n++] = IOVEC_MAKE_STRING(buf);
|
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
|
|
|
dispatch_message_real(s, iovec, n, m, s->my_context, NULL, LOG_INFO, object_pid);
|
2015-11-11 13:54:50 +01:00
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void server_dispatch_message(
|
|
|
|
Server *s,
|
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
|
|
|
struct iovec *iovec, size_t n, size_t m,
|
2017-07-17 23:36:35 +02:00
|
|
|
ClientContext *c,
|
2014-11-02 21:46:42 +01:00
|
|
|
const struct timeval *tv,
|
journal: allow callers to specify OBJECT_PID=
When journald encounters a message with OBJECT_PID= set
coming from a priviledged process (UID==0), additional fields
will be added to the message:
OBJECT_UID=,
OBJECT_GID=,
OBJECT_COMM=,
OBJECT_EXE=,
OBJECT_CMDLINE=,
OBJECT_AUDIT_SESSION=,
OBJECT_AUDIT_LOGINUID=,
OBJECT_SYSTEMD_CGROUP=,
OBJECT_SYSTEMD_SESSION=,
OBJECT_SYSTEMD_OWNER_UID=,
OBJECT_SYSTEMD_UNIT= or OBJECT_SYSTEMD_USER_UNIT=.
This is for other logging daemons, like setroubleshoot, to be able to
augment their logs with data about the process.
https://bugzilla.redhat.com/show_bug.cgi?id=951627
2013-06-12 06:24:34 +02:00
|
|
|
int priority,
|
|
|
|
pid_t object_pid) {
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-10-02 23:21:59 +02:00
|
|
|
uint64_t available = 0;
|
2017-07-17 23:36:35 +02:00
|
|
|
int rl;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(iovec || n == 0);
|
|
|
|
|
|
|
|
if (n == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (LOG_PRI(priority) > s->max_level_store)
|
|
|
|
return;
|
|
|
|
|
2013-07-18 14:45:12 +02:00
|
|
|
/* Stop early in case the information will not be stored
|
|
|
|
* in a journal. */
|
|
|
|
if (s->storage == STORAGE_NONE)
|
|
|
|
return;
|
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
if (c && c->unit) {
|
|
|
|
(void) determine_space(s, &available, NULL);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-09-19 17:49:14 +02:00
|
|
|
rl = journal_ratelimit_test(s->ratelimit, c->unit, c->log_ratelimit_interval, c->log_ratelimit_burst, priority & LOG_PRIMASK, available);
|
2017-07-17 23:36:35 +02:00
|
|
|
if (rl == 0)
|
|
|
|
return;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
/* Write a suppression message if we suppressed something */
|
|
|
|
if (rl > 1)
|
2017-10-30 20:01:50 +01:00
|
|
|
server_driver_message(s, c->pid,
|
|
|
|
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_DROPPED_STR,
|
|
|
|
LOG_MESSAGE("Suppressed %i messages from %s", rl - 1, c->unit),
|
2017-11-29 22:11:59 +01:00
|
|
|
"N_DROPPED=%i", rl - 1,
|
2017-07-17 23:36:35 +02:00
|
|
|
NULL);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
dispatch_message_real(s, iovec, n, m, c, tv, priority, object_pid);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2016-12-12 20:54:45 +01:00
|
|
|
int server_flush_to_var(Server *s, bool require_flag_file) {
|
2013-11-27 01:54:25 +01:00
|
|
|
char ts[FORMAT_TIMESPAN_MAX];
|
2019-11-25 15:00:38 +01:00
|
|
|
sd_journal *j = NULL;
|
|
|
|
const char *fn;
|
2013-11-27 01:54:25 +01:00
|
|
|
unsigned n = 0;
|
2019-11-25 15:00:38 +01:00
|
|
|
usec_t start;
|
2019-04-05 18:20:25 +02:00
|
|
|
int r, k;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2016-12-12 20:54:45 +01:00
|
|
|
if (!IN_SET(s->storage, STORAGE_AUTO, STORAGE_PERSISTENT))
|
2012-11-12 17:29:07 +01:00
|
|
|
return 0;
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
if (s->namespace) /* Flushing concept does not exist for namespace instances */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!s->runtime_journal) /* Nothing to flush? */
|
2012-11-12 17:29:07 +01:00
|
|
|
return 0;
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
if (require_flag_file && !flushed_flag_is_set(s))
|
2016-12-12 20:54:45 +01:00
|
|
|
return 0;
|
|
|
|
|
2019-04-05 18:20:25 +02:00
|
|
|
(void) system_journal_open(s, true, false);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
if (!s->system_journal)
|
|
|
|
return 0;
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
log_debug("Flushing to %s...", s->system_storage.path);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-11-27 01:54:25 +01:00
|
|
|
start = now(CLOCK_MONOTONIC);
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
r = sd_journal_open(&j, SD_JOURNAL_RUNTIME_ONLY);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to read runtime journal: %m");
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2012-11-21 00:28:00 +01:00
|
|
|
sd_journal_set_data_threshold(j, 0);
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
SD_JOURNAL_FOREACH(j) {
|
|
|
|
Object *o = NULL;
|
|
|
|
JournalFile *f;
|
|
|
|
|
|
|
|
f = j->current_file;
|
|
|
|
assert(f && f->current_offset > 0);
|
|
|
|
|
2013-11-27 01:54:25 +01:00
|
|
|
n++;
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
|
|
|
|
if (r < 0) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Can't read entry: %m");
|
2012-11-12 17:29:07 +01:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2018-05-27 11:08:44 +02:00
|
|
|
r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset);
|
2012-11-12 17:29:07 +01:00
|
|
|
if (r >= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!shall_try_append_again(s->system_journal, r)) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Can't write entry: %m");
|
2012-11-12 17:29:07 +01:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
server_rotate(s);
|
2016-10-12 09:58:10 +02:00
|
|
|
server_vacuum(s, false);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-05-07 01:09:33 +02:00
|
|
|
if (!s->system_journal) {
|
|
|
|
log_notice("Didn't flush runtime journal since rotation of system journal wasn't successful.");
|
|
|
|
r = -EIO;
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
log_debug("Retrying write.");
|
2018-05-27 11:08:44 +02:00
|
|
|
r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset);
|
2012-11-12 17:29:07 +01:00
|
|
|
if (r < 0) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Can't write entry: %m");
|
2012-11-12 17:29:07 +01:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 22:36:33 +02:00
|
|
|
r = 0;
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
finish:
|
2018-09-03 05:42:39 +02:00
|
|
|
if (s->system_journal)
|
|
|
|
journal_file_post_change(s->system_journal);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-10-02 22:36:33 +02:00
|
|
|
s->runtime_journal = journal_file_close(s->runtime_journal);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
if (r >= 0)
|
2019-11-25 15:00:38 +01:00
|
|
|
(void) rm_rf(s->runtime_storage.path, REMOVE_ROOT);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-03-18 04:36:25 +01:00
|
|
|
sd_journal_close(j);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2017-10-30 20:01:50 +01:00
|
|
|
server_driver_message(s, 0, NULL,
|
2019-11-25 15:00:38 +01:00
|
|
|
LOG_MESSAGE("Time spent on flushing to %s is %s for %u entries.",
|
|
|
|
s->system_storage.path,
|
2015-11-08 20:05:55 +01:00
|
|
|
format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0),
|
|
|
|
n),
|
|
|
|
NULL);
|
2013-11-27 01:54:25 +01:00
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
fn = strjoina(s->runtime_directory, "/flushed");
|
|
|
|
k = touch(fn);
|
2019-04-05 18:20:25 +02:00
|
|
|
if (k < 0)
|
2019-11-25 15:00:38 +01:00
|
|
|
log_warning_errno(k, "Failed to touch %s, ignoring: %m", fn);
|
2019-04-05 18:20:25 +02:00
|
|
|
|
2019-11-27 14:45:24 +01:00
|
|
|
server_refresh_idle_timer(s);
|
2012-11-12 17:29:07 +01:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-04-05 18:20:25 +02:00
|
|
|
static int server_relinquish_var(Server *s) {
|
2019-11-25 15:00:38 +01:00
|
|
|
const char *fn;
|
2019-04-05 18:20:25 +02:00
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (s->storage == STORAGE_NONE)
|
|
|
|
return 0;
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
if (s->namespace) /* Concept does not exist for namespaced instances */
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2019-04-05 18:20:25 +02:00
|
|
|
if (s->runtime_journal && !s->system_journal)
|
|
|
|
return 0;
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
log_debug("Relinquishing %s...", s->system_storage.path);
|
2019-04-05 18:20:25 +02:00
|
|
|
|
|
|
|
(void) system_journal_open(s, false, true);
|
|
|
|
|
|
|
|
s->system_journal = journal_file_close(s->system_journal);
|
|
|
|
ordered_hashmap_clear_with_destructor(s->user_journals, journal_file_close);
|
|
|
|
set_clear_with_destructor(s->deferred_closes, journal_file_close);
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
fn = strjoina(s->runtime_directory, "/flushed");
|
|
|
|
if (unlink(fn) < 0 && errno != ENOENT)
|
|
|
|
log_warning_errno(errno, "Failed to unlink %s, ignoring: %m", fn);
|
2019-04-05 18:20:25 +02:00
|
|
|
|
2019-11-27 14:45:24 +01:00
|
|
|
server_refresh_idle_timer(s);
|
2019-04-05 18:20:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-27 14:45:24 +01:00
|
|
|
int server_process_datagram(
|
|
|
|
sd_event_source *es,
|
|
|
|
int fd,
|
|
|
|
uint32_t revents,
|
|
|
|
void *userdata) {
|
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
Server *s = userdata;
|
2015-06-10 19:24:58 +02:00
|
|
|
struct ucred *ucred = NULL;
|
|
|
|
struct timeval *tv = NULL;
|
|
|
|
struct cmsghdr *cmsg;
|
|
|
|
char *label = NULL;
|
|
|
|
size_t label_len = 0, m;
|
|
|
|
struct iovec iovec;
|
|
|
|
ssize_t n;
|
|
|
|
int *fds = NULL, v = 0;
|
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_fds = 0;
|
2015-06-10 19:24:58 +02:00
|
|
|
|
2020-04-24 23:54:25 +02:00
|
|
|
/* We use NAME_MAX space for the SELinux label here. The kernel currently enforces no limit, but
|
|
|
|
* according to suggestions from the SELinux people this will change and it will probably be
|
|
|
|
* identical to NAME_MAX. For now we use that, but this should be updated one day when the final
|
|
|
|
* limit is known. */
|
|
|
|
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
|
|
|
|
CMSG_SPACE(sizeof(struct timeval)) +
|
|
|
|
CMSG_SPACE(sizeof(int)) + /* fd */
|
|
|
|
CMSG_SPACE(NAME_MAX) /* selinux label */) control;
|
2015-06-10 19:24:58 +02:00
|
|
|
|
|
|
|
union sockaddr_union sa = {};
|
|
|
|
|
|
|
|
struct msghdr msghdr = {
|
|
|
|
.msg_iov = &iovec,
|
|
|
|
.msg_iovlen = 1,
|
|
|
|
.msg_control = &control,
|
|
|
|
.msg_controllen = sizeof(control),
|
|
|
|
.msg_name = &sa,
|
|
|
|
.msg_namelen = sizeof(sa),
|
|
|
|
};
|
2013-12-11 20:13:44 +01:00
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
assert(s);
|
2014-11-03 20:58:24 +01:00
|
|
|
assert(fd == s->native_fd || fd == s->syslog_fd || fd == s->audit_fd);
|
2013-12-11 20:13:44 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (revents != EPOLLIN)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
|
|
|
"Got invalid event from epoll for datagram fd: %" PRIx32,
|
|
|
|
revents);
|
2013-12-11 20:13:44 +01:00
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
/* Try to get the right size, if we can. (Not all sockets support SIOCINQ, hence we just try, but don't rely on
|
|
|
|
* it.) */
|
2015-06-10 19:24:58 +02:00
|
|
|
(void) ioctl(fd, SIOCINQ, &v);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-06-10 19:24:58 +02:00
|
|
|
/* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful! */
|
|
|
|
m = PAGE_ALIGN(MAX3((size_t) v + 1,
|
|
|
|
(size_t) LINE_MAX,
|
|
|
|
ALIGN(sizeof(struct nlmsghdr)) + ALIGN((size_t) MAX_AUDIT_MESSAGE_LENGTH)) + 1);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-06-10 19:24:58 +02:00
|
|
|
if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m))
|
|
|
|
return log_oom();
|
2014-11-03 20:58:24 +01:00
|
|
|
|
2018-11-26 21:52:36 +01:00
|
|
|
iovec = IOVEC_MAKE(s->buffer, s->buffer_size - 1); /* Leave room for trailing NUL we add later */
|
2012-11-12 17:29:07 +01:00
|
|
|
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
|
|
|
|
if (IN_SET(n, -EINTR, -EAGAIN))
|
|
|
|
return 0;
|
|
|
|
if (n == -EXFULL) {
|
|
|
|
log_warning("Got message with truncated control data (too many fds sent?), ignoring.");
|
|
|
|
return 0;
|
2015-06-10 19:24:58 +02:00
|
|
|
}
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
if (n < 0)
|
|
|
|
return log_error_errno(n, "recvmsg() failed: %m");
|
2014-11-03 20:58:24 +01:00
|
|
|
|
2018-12-05 17:53:50 +01:00
|
|
|
CMSG_FOREACH(cmsg, &msghdr)
|
2015-06-10 19:24:58 +02:00
|
|
|
if (cmsg->cmsg_level == SOL_SOCKET &&
|
|
|
|
cmsg->cmsg_type == SCM_CREDENTIALS &&
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
|
|
|
|
assert(!ucred);
|
2015-06-10 19:24:58 +02:00
|
|
|
ucred = (struct ucred*) CMSG_DATA(cmsg);
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
} else if (cmsg->cmsg_level == SOL_SOCKET &&
|
2015-06-10 19:24:58 +02:00
|
|
|
cmsg->cmsg_type == SCM_SECURITY) {
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
assert(!label);
|
2015-06-10 19:24:58 +02:00
|
|
|
label = (char*) CMSG_DATA(cmsg);
|
|
|
|
label_len = cmsg->cmsg_len - CMSG_LEN(0);
|
|
|
|
} else if (cmsg->cmsg_level == SOL_SOCKET &&
|
|
|
|
cmsg->cmsg_type == SO_TIMESTAMP &&
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) {
|
|
|
|
assert(!tv);
|
2015-06-10 19:24:58 +02:00
|
|
|
tv = (struct timeval*) CMSG_DATA(cmsg);
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
} else if (cmsg->cmsg_level == SOL_SOCKET &&
|
2015-06-10 19:24:58 +02:00
|
|
|
cmsg->cmsg_type == SCM_RIGHTS) {
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
assert(!fds);
|
2015-06-10 19:24:58 +02:00
|
|
|
fds = (int*) CMSG_DATA(cmsg);
|
|
|
|
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2015-06-10 19:24:58 +02:00
|
|
|
/* And a trailing NUL, just in case */
|
|
|
|
s->buffer[n] = 0;
|
|
|
|
|
|
|
|
if (fd == s->syslog_fd) {
|
|
|
|
if (n > 0 && n_fds == 0)
|
2018-05-30 16:27:22 +02:00
|
|
|
server_process_syslog_message(s, s->buffer, n, ucred, tv, label, label_len);
|
2015-06-10 19:24:58 +02:00
|
|
|
else if (n_fds > 0)
|
|
|
|
log_warning("Got file descriptors via syslog socket. Ignoring.");
|
|
|
|
|
|
|
|
} else if (fd == s->native_fd) {
|
|
|
|
if (n > 0 && n_fds == 0)
|
|
|
|
server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len);
|
|
|
|
else if (n == 0 && n_fds == 1)
|
|
|
|
server_process_native_file(s, fds[0], ucred, tv, label, label_len);
|
|
|
|
else if (n_fds > 0)
|
|
|
|
log_warning("Got too many file descriptors via native socket. Ignoring.");
|
|
|
|
|
|
|
|
} else {
|
|
|
|
assert(fd == s->audit_fd);
|
|
|
|
|
|
|
|
if (n > 0 && n_fds == 0)
|
|
|
|
server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen);
|
|
|
|
else if (n_fds > 0)
|
|
|
|
log_warning("Got file descriptors via audit socket. Ignoring.");
|
2013-12-11 20:13:44 +01:00
|
|
|
}
|
2015-06-10 19:24:58 +02:00
|
|
|
|
|
|
|
close_many(fds, n_fds);
|
2019-11-27 14:45:24 +01:00
|
|
|
|
|
|
|
server_refresh_idle_timer(s);
|
2015-06-10 19:24:58 +02:00
|
|
|
return 0;
|
2013-12-11 20:13:44 +01:00
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-04-04 19:38:18 +02:00
|
|
|
static void server_full_flush(Server *s) {
|
2013-12-11 20:13:44 +01:00
|
|
|
assert(s);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2016-12-12 20:54:45 +01:00
|
|
|
(void) server_flush_to_var(s, false);
|
2013-12-11 20:13:44 +01:00
|
|
|
server_sync(s);
|
2016-10-12 09:58:10 +02:00
|
|
|
server_vacuum(s, false);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2016-10-11 16:51:37 +02:00
|
|
|
server_space_usage_message(s, NULL);
|
2019-11-27 14:45:24 +01:00
|
|
|
|
|
|
|
server_refresh_idle_timer(s);
|
2013-12-11 20:13:44 +01:00
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-04-04 19:38:18 +02:00
|
|
|
static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
|
2013-12-11 20:13:44 +01:00
|
|
|
Server *s = userdata;
|
2019-04-04 19:38:18 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
if (s->namespace) {
|
|
|
|
log_error("Received SIGUSR1 signal from PID " PID_FMT ", but flushing runtime journals not supported for namespaced instances.", si->ssi_pid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-04-05 18:20:25 +02:00
|
|
|
log_info("Received SIGUSR1 signal from PID " PID_FMT ", as request to flush runtime journal.", si->ssi_pid);
|
2019-04-04 19:38:18 +02:00
|
|
|
server_full_flush(s);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void server_full_rotate(Server *s) {
|
2019-11-25 15:00:38 +01:00
|
|
|
const char *fn;
|
2015-11-12 11:17:01 +01:00
|
|
|
int r;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
assert(s);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
server_rotate(s);
|
2016-10-12 09:58:10 +02:00
|
|
|
server_vacuum(s, true);
|
|
|
|
|
|
|
|
if (s->system_journal)
|
|
|
|
patch_min_use(&s->system_storage);
|
|
|
|
if (s->runtime_journal)
|
|
|
|
patch_min_use(&s->runtime_storage);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-11-11 13:56:54 +01:00
|
|
|
/* Let clients know when the most recent rotation happened. */
|
2019-11-25 15:00:38 +01:00
|
|
|
fn = strjoina(s->runtime_directory, "/rotated");
|
|
|
|
r = write_timestamp_file_atomic(fn, now(CLOCK_MONOTONIC));
|
2015-11-12 11:17:01 +01:00
|
|
|
if (r < 0)
|
2019-11-25 15:00:38 +01:00
|
|
|
log_warning_errno(r, "Failed to write %s, ignoring: %m", fn);
|
2019-04-04 19:38:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2019-04-05 18:20:25 +02:00
|
|
|
log_info("Received SIGUSR2 signal from PID " PID_FMT ", as request to rotate journal.", si->ssi_pid);
|
2019-04-04 19:38:18 +02:00
|
|
|
server_full_rotate(s);
|
2015-11-11 13:56:54 +01:00
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
|
|
|
|
Server *s = userdata;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
assert(s);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2014-02-10 02:08:55 +01:00
|
|
|
log_received_signal(LOG_INFO, si);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-12-12 22:21:25 +01:00
|
|
|
sd_event_exit(s->event, 0);
|
2012-11-12 17:29:07 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-04-04 19:38:18 +02:00
|
|
|
static void server_full_sync(Server *s) {
|
2019-11-25 15:00:38 +01:00
|
|
|
const char *fn;
|
2015-11-12 11:17:01 +01:00
|
|
|
int r;
|
2015-11-11 12:59:09 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
server_sync(s);
|
|
|
|
|
|
|
|
/* Let clients know when the most recent sync happened. */
|
2019-11-25 15:00:38 +01:00
|
|
|
fn = strjoina(s->runtime_directory, "/synced");
|
|
|
|
r = write_timestamp_file_atomic(fn, now(CLOCK_MONOTONIC));
|
2015-11-12 11:17:01 +01:00
|
|
|
if (r < 0)
|
2019-11-25 15:00:38 +01:00
|
|
|
log_warning_errno(r, "Failed to write %s, ignoring: %m", fn);
|
2015-11-11 12:59:09 +01:00
|
|
|
|
2019-04-04 19:38:18 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2019-04-05 18:20:25 +02:00
|
|
|
log_debug("Received SIGRTMIN1 signal from PID " PID_FMT ", as request to sync.", si->ssi_pid );
|
2019-04-04 19:38:18 +02:00
|
|
|
server_full_sync(s);
|
|
|
|
|
2015-11-11 12:59:09 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
static int setup_signals(Server *s) {
|
|
|
|
int r;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2016-11-25 11:24:58 +01:00
|
|
|
assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s);
|
2013-12-11 20:13:44 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_event_add_signal(s->event, &s->sigusr2_event_source, SIGUSR2, dispatch_sigusr2, s);
|
2013-12-11 20:13:44 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_event_add_signal(s->event, &s->sigterm_event_source, SIGTERM, dispatch_sigterm, s);
|
2013-12-11 20:13:44 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-04-05 15:31:18 +02:00
|
|
|
/* Let's process SIGTERM late, so that we flush all queued messages to disk before we exit */
|
2015-11-10 16:53:00 +01:00
|
|
|
r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_NORMAL+20);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-04-05 15:31:18 +02:00
|
|
|
/* When journald is invoked on the terminal (when debugging), it's useful if C-c is handled
|
|
|
|
* equivalent to SIGTERM. */
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s);
|
2013-12-11 20:13:44 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-11-10 16:53:00 +01:00
|
|
|
r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_NORMAL+20);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-04-05 15:31:18 +02:00
|
|
|
/* SIGRTMIN+1 causes an immediate sync. We process this very late, so that everything else queued at
|
|
|
|
* this point is really written to disk. Clients can watch /run/systemd/journal/synced with inotify
|
|
|
|
* until its mtime changes to see when a sync happened. */
|
2015-11-11 12:59:09 +01:00
|
|
|
r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+1, dispatch_sigrtmin1, s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_event_source_set_priority(s->sigrtmin1_event_source, SD_EVENT_PRIORITY_NORMAL+15);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
|
|
|
Server *s = data;
|
2013-11-06 03:15:16 +01:00
|
|
|
int r;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
assert(s);
|
2012-11-12 17:29:07 +01: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 (proc_cmdline_key_streq(key, "systemd.journald.forward_to_syslog")) {
|
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
r = value ? parse_boolean(value) : true;
|
2015-10-26 10:58:03 +01:00
|
|
|
if (r < 0)
|
2016-10-22 20:25:30 +02:00
|
|
|
log_warning("Failed to parse forward to syslog switch \"%s\". Ignoring.", value);
|
|
|
|
else
|
|
|
|
s->forward_to_syslog = r;
|
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.journald.forward_to_kmsg")) {
|
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
r = value ? parse_boolean(value) : true;
|
|
|
|
if (r < 0)
|
|
|
|
log_warning("Failed to parse forward to kmsg switch \"%s\". Ignoring.", value);
|
|
|
|
else
|
|
|
|
s->forward_to_kmsg = r;
|
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.journald.forward_to_console")) {
|
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
r = value ? parse_boolean(value) : true;
|
|
|
|
if (r < 0)
|
|
|
|
log_warning("Failed to parse forward to console switch \"%s\". Ignoring.", value);
|
|
|
|
else
|
|
|
|
s->forward_to_console = r;
|
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.journald.forward_to_wall")) {
|
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
r = value ? parse_boolean(value) : true;
|
|
|
|
if (r < 0)
|
|
|
|
log_warning("Failed to parse forward to wall switch \"%s\". Ignoring.", value);
|
|
|
|
else
|
|
|
|
s->forward_to_wall = r;
|
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.journald.max_level_console")) {
|
|
|
|
|
|
|
|
if (proc_cmdline_value_missing(key, value))
|
|
|
|
return 0;
|
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
r = log_level_from_string(value);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning("Failed to parse max level console value \"%s\". Ignoring.", value);
|
|
|
|
else
|
|
|
|
s->max_level_console = r;
|
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.journald.max_level_store")) {
|
|
|
|
|
|
|
|
if (proc_cmdline_value_missing(key, value))
|
|
|
|
return 0;
|
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
r = log_level_from_string(value);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning("Failed to parse max level store value \"%s\". Ignoring.", value);
|
|
|
|
else
|
|
|
|
s->max_level_store = r;
|
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.journald.max_level_syslog")) {
|
|
|
|
|
|
|
|
if (proc_cmdline_value_missing(key, value))
|
|
|
|
return 0;
|
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
r = log_level_from_string(value);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning("Failed to parse max level syslog value \"%s\". Ignoring.", value);
|
|
|
|
else
|
|
|
|
s->max_level_syslog = r;
|
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.journald.max_level_kmsg")) {
|
|
|
|
|
|
|
|
if (proc_cmdline_value_missing(key, value))
|
|
|
|
return 0;
|
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
r = log_level_from_string(value);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning("Failed to parse max level kmsg value \"%s\". Ignoring.", value);
|
|
|
|
else
|
|
|
|
s->max_level_kmsg = r;
|
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.journald.max_level_wall")) {
|
|
|
|
|
|
|
|
if (proc_cmdline_value_missing(key, value))
|
|
|
|
return 0;
|
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
r = log_level_from_string(value);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning("Failed to parse max level wall value \"%s\". Ignoring.", value);
|
|
|
|
else
|
|
|
|
s->max_level_wall = r;
|
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
|
|
|
|
2016-10-22 20:25:30 +02:00
|
|
|
} else if (startswith(key, "systemd.journald"))
|
|
|
|
log_warning("Unknown journald kernel command line option \"%s\". Ignoring.", key);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-10-02 22:36:33 +02:00
|
|
|
/* do not warn about state here, since probably systemd already did */
|
2013-01-10 01:14:32 +01:00
|
|
|
return 0;
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int server_parse_config_file(Server *s) {
|
2019-11-25 15:00:38 +01:00
|
|
|
int r;
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
assert(s);
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
if (s->namespace) {
|
|
|
|
const char *namespaced;
|
|
|
|
|
|
|
|
/* If we are running in namespace mode, load the namespace specific configuration file, and nothing else */
|
|
|
|
namespaced = strjoina(PKGSYSCONFDIR "/journald@", s->namespace, ".conf");
|
|
|
|
|
|
|
|
r = config_parse(
|
|
|
|
NULL,
|
|
|
|
namespaced, NULL,
|
|
|
|
"Journal\0",
|
|
|
|
config_item_perf_lookup, journald_gperf_lookup,
|
|
|
|
CONFIG_PARSE_WARN, s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-10 12:02:40 +02:00
|
|
|
return config_parse_many_nulstr(PKGSYSCONFDIR "/journald.conf",
|
2017-04-19 08:48:29 +02:00
|
|
|
CONF_PATHS_NULSTR("systemd/journald.conf.d"),
|
|
|
|
"Journal\0",
|
|
|
|
config_item_perf_lookup, journald_gperf_lookup,
|
2017-11-09 00:26:11 +01:00
|
|
|
CONFIG_PARSE_WARN, s);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) {
|
|
|
|
Server *s = userdata;
|
2013-03-25 17:49:03 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
server_sync(s);
|
2013-03-25 17:49:03 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-24 08:08:57 +02:00
|
|
|
int server_schedule_sync(Server *s, int priority) {
|
2013-03-25 17:49:03 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2013-07-24 08:08:57 +02:00
|
|
|
if (priority <= LOG_CRIT) {
|
|
|
|
/* Immediately sync to disk when this is of priority CRIT, ALERT, EMERG */
|
|
|
|
server_sync(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-25 17:49:03 +01:00
|
|
|
if (s->sync_scheduled)
|
|
|
|
return 0;
|
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
if (s->sync_interval_usec > 0) {
|
|
|
|
usec_t when;
|
2013-05-15 11:28:58 +02:00
|
|
|
|
2014-03-24 02:49:09 +01:00
|
|
|
r = sd_event_now(s->event, CLOCK_MONOTONIC, &when);
|
2013-12-11 20:13:44 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-03-25 17:49:03 +01:00
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
when += s->sync_interval_usec;
|
|
|
|
|
|
|
|
if (!s->sync_event_source) {
|
2014-03-24 02:49:09 +01:00
|
|
|
r = sd_event_add_time(
|
|
|
|
s->event,
|
|
|
|
&s->sync_event_source,
|
|
|
|
CLOCK_MONOTONIC,
|
|
|
|
when, 0,
|
|
|
|
server_dispatch_sync, s);
|
2013-12-11 20:13:44 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_event_source_set_priority(s->sync_event_source, SD_EVENT_PRIORITY_IMPORTANT);
|
|
|
|
} else {
|
|
|
|
r = sd_event_source_set_time(s->sync_event_source, when);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_event_source_set_enabled(s->sync_event_source, SD_EVENT_ONESHOT);
|
|
|
|
}
|
2013-03-25 17:49:03 +01:00
|
|
|
if (r < 0)
|
2013-12-11 20:13:44 +01:00
|
|
|
return r;
|
2013-03-25 17:49:03 +01:00
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
s->sync_scheduled = true;
|
|
|
|
}
|
2013-03-25 17:49:03 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-11 22:55:57 +01:00
|
|
|
static int dispatch_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
server_cache_hostname(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int server_open_hostname(Server *s) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2018-01-24 11:09:29 +01:00
|
|
|
s->hostname_fd = open("/proc/sys/kernel/hostname",
|
|
|
|
O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
|
2014-11-28 19:57:32 +01:00
|
|
|
if (s->hostname_fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to open /proc/sys/kernel/hostname: %m");
|
2013-12-11 22:55:57 +01:00
|
|
|
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_event_add_io(s->event, &s->hostname_event_source, s->hostname_fd, 0, dispatch_hostname_change, s);
|
2013-12-11 22:55:57 +01:00
|
|
|
if (r < 0) {
|
2014-02-21 16:31:26 +01:00
|
|
|
/* kernels prior to 3.2 don't support polling this file. Ignore
|
|
|
|
* the failure. */
|
|
|
|
if (r == -EPERM) {
|
2015-09-30 22:16:17 +02:00
|
|
|
log_warning_errno(r, "Failed to register hostname fd in event loop, ignoring: %m");
|
2014-03-18 19:22:43 +01:00
|
|
|
s->hostname_fd = safe_close(s->hostname_fd);
|
2014-02-21 16:31:26 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-28 18:23:20 +01:00
|
|
|
return log_error_errno(r, "Failed to register hostname fd in event loop: %m");
|
2013-12-11 22:55:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_event_source_set_priority(s->hostname_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
2020-04-14 10:37:40 +02:00
|
|
|
return log_error_errno(r, "Failed to adjust priority of hostname event source: %m");
|
2013-12-11 22:55:57 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-01 21:50:24 +01:00
|
|
|
static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(s->notify_event_source == es);
|
|
|
|
assert(s->notify_fd == fd);
|
|
|
|
|
|
|
|
/* The $NOTIFY_SOCKET is writable again, now send exactly one
|
2016-09-18 11:14:50 +02:00
|
|
|
* message on it. Either it's the watchdog event, the initial
|
2015-11-03 12:28:19 +01:00
|
|
|
* READY=1 event or an stdout stream event. If there's nothing
|
|
|
|
* to write anymore, turn our event source off. The next time
|
|
|
|
* there's something to send it will be turned on again. */
|
2015-11-01 21:50:24 +01:00
|
|
|
|
|
|
|
if (!s->sent_notify_ready) {
|
|
|
|
static const char p[] =
|
|
|
|
"READY=1\n"
|
|
|
|
"STATUS=Processing requests...";
|
|
|
|
ssize_t l;
|
|
|
|
|
|
|
|
l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT);
|
|
|
|
if (l < 0) {
|
|
|
|
if (errno == EAGAIN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return log_error_errno(errno, "Failed to send READY=1 notification message: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
s->sent_notify_ready = true;
|
|
|
|
log_debug("Sent READY=1 notification.");
|
|
|
|
|
2015-11-03 12:28:19 +01:00
|
|
|
} else if (s->send_watchdog) {
|
|
|
|
|
|
|
|
static const char p[] =
|
|
|
|
"WATCHDOG=1";
|
|
|
|
|
|
|
|
ssize_t l;
|
|
|
|
|
|
|
|
l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT);
|
|
|
|
if (l < 0) {
|
|
|
|
if (errno == EAGAIN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return log_error_errno(errno, "Failed to send WATCHDOG=1 notification message: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
s->send_watchdog = false;
|
|
|
|
log_debug("Sent WATCHDOG=1 notification.");
|
|
|
|
|
2015-11-01 21:50:24 +01:00
|
|
|
} else if (s->stdout_streams_notify_queue)
|
|
|
|
/* Dispatch one stream notification event */
|
|
|
|
stdout_stream_send_notify(s->stdout_streams_notify_queue);
|
|
|
|
|
2016-07-10 14:48:23 +02:00
|
|
|
/* Leave us enabled if there's still more to do. */
|
2015-11-03 12:28:19 +01:00
|
|
|
if (s->send_watchdog || s->stdout_streams_notify_queue)
|
2015-11-01 21:50:24 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* There was nothing to do anymore, let's turn ourselves off. */
|
|
|
|
r = sd_event_source_set_enabled(es, SD_EVENT_OFF);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to turn off notify event source: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-03 12:28:19 +01:00
|
|
|
static int dispatch_watchdog(sd_event_source *es, uint64_t usec, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
s->send_watchdog = true;
|
|
|
|
|
|
|
|
r = sd_event_source_set_enabled(s->notify_event_source, SD_EVENT_ON);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to turn on notify event source: %m");
|
|
|
|
|
|
|
|
r = sd_event_source_set_time(s->watchdog_event_source, usec + s->watchdog_usec / 2);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to restart watchdog event source: %m");
|
|
|
|
|
|
|
|
r = sd_event_source_set_enabled(s->watchdog_event_source, SD_EVENT_ON);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to enable watchdog event source: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-01 21:50:24 +01:00
|
|
|
static int server_connect_notify(Server *s) {
|
2020-03-02 15:51:31 +01:00
|
|
|
union sockaddr_union sa;
|
|
|
|
socklen_t sa_len;
|
2015-11-01 21:50:24 +01:00
|
|
|
const char *e;
|
2020-03-02 15:51:31 +01:00
|
|
|
int r;
|
2015-11-01 21:50:24 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(s->notify_fd < 0);
|
|
|
|
assert(!s->notify_event_source);
|
|
|
|
|
|
|
|
/*
|
2019-04-05 15:31:18 +02:00
|
|
|
* So here's the problem: we'd like to send notification messages to PID 1, but we cannot do that via
|
|
|
|
* sd_notify(), since that's synchronous, and we might end up blocking on it. Specifically: given
|
|
|
|
* that PID 1 might block on dbus-daemon during IPC, and dbus-daemon is logging to us, and might
|
|
|
|
* hence block on us, we might end up in a deadlock if we block on sending PID 1 notification
|
|
|
|
* messages — by generating a full blocking circle. To avoid this, let's create a non-blocking
|
|
|
|
* socket, and connect it to the notification socket, and then wait for POLLOUT before we send
|
|
|
|
* anything. This should efficiently avoid any deadlocks, as we'll never block on PID 1, hence PID 1
|
|
|
|
* can safely block on dbus-daemon which can safely block on us again.
|
|
|
|
*
|
|
|
|
* Don't think that this issue is real? It is, see: https://github.com/systemd/systemd/issues/1505
|
|
|
|
*/
|
2015-11-01 21:50:24 +01:00
|
|
|
|
|
|
|
e = getenv("NOTIFY_SOCKET");
|
|
|
|
if (!e)
|
|
|
|
return 0;
|
|
|
|
|
2020-03-02 15:51:31 +01:00
|
|
|
r = sockaddr_un_set_path(&sa.un, e);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "NOTIFY_SOCKET set to invalid value '%s': %m", e);
|
|
|
|
sa_len = r;
|
2015-11-01 21:50:24 +01:00
|
|
|
|
|
|
|
s->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
|
|
|
if (s->notify_fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to create notify socket: %m");
|
|
|
|
|
|
|
|
(void) fd_inc_sndbuf(s->notify_fd, NOTIFY_SNDBUF_SIZE);
|
|
|
|
|
2020-03-02 15:51:31 +01:00
|
|
|
r = connect(s->notify_fd, &sa.sa, sa_len);
|
2015-11-01 21:50:24 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(errno, "Failed to connect to notify socket: %m");
|
|
|
|
|
|
|
|
r = sd_event_add_io(s->event, &s->notify_event_source, s->notify_fd, EPOLLOUT, dispatch_notify_event, s);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to watch notification socket: %m");
|
|
|
|
|
2015-11-03 12:28:19 +01:00
|
|
|
if (sd_watchdog_enabled(false, &s->watchdog_usec) > 0) {
|
|
|
|
s->send_watchdog = true;
|
|
|
|
|
2015-11-12 12:33:10 +01:00
|
|
|
r = sd_event_add_time(s->event, &s->watchdog_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + s->watchdog_usec/2, s->watchdog_usec/4, dispatch_watchdog, s);
|
2015-11-03 12:28:19 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add watchdog time event: %m");
|
|
|
|
}
|
|
|
|
|
2019-04-05 15:31:18 +02:00
|
|
|
/* This should fire pretty soon, which we'll use to send the READY=1 event. */
|
2015-11-01 21:50:24 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-04-04 19:41:33 +02:00
|
|
|
static int synchronize_second_half(sd_event_source *event_source, void *userdata) {
|
|
|
|
Varlink *link = userdata;
|
|
|
|
Server *s;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert_se(s = varlink_get_userdata(link));
|
|
|
|
|
|
|
|
/* This is the "second half" of the Synchronize() varlink method. This function is called as deferred
|
|
|
|
* event source at a low priority to ensure the synchronization completes after all queued log
|
|
|
|
* messages are processed. */
|
|
|
|
server_full_sync(s);
|
|
|
|
|
|
|
|
/* Let's get rid of the event source now, by marking it as non-floating again. It then has no ref
|
|
|
|
* anymore and is immediately destroyed after we return from this function, i.e. from this event
|
|
|
|
* source handler at the end. */
|
|
|
|
r = sd_event_source_set_floating(event_source, false);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to mark event source as non-floating: %m");
|
|
|
|
|
|
|
|
return varlink_reply(link, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void synchronize_destroy(void *userdata) {
|
|
|
|
varlink_unref(userdata);
|
|
|
|
}
|
|
|
|
|
2019-04-04 19:38:18 +02:00
|
|
|
static int vl_method_synchronize(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
2019-04-04 19:41:33 +02:00
|
|
|
_cleanup_(sd_event_source_unrefp) sd_event_source *event_source = NULL;
|
2019-04-04 19:38:18 +02:00
|
|
|
Server *s = userdata;
|
2019-04-04 19:41:33 +02:00
|
|
|
int r;
|
2019-04-04 19:38:18 +02:00
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (json_variant_elements(parameters) > 0)
|
|
|
|
return varlink_error_invalid_parameter(link, parameters);
|
|
|
|
|
|
|
|
log_info("Received client request to rotate journal.");
|
|
|
|
|
2019-04-04 19:41:33 +02:00
|
|
|
/* We don't do the main work now, but instead enqueue a deferred event loop job which will do
|
|
|
|
* it. That job is scheduled at low priority, so that we return from this method call only after all
|
|
|
|
* queued but not processed log messages are written to disk, so that this method call returning can
|
|
|
|
* be used as nice synchronization point. */
|
|
|
|
r = sd_event_add_defer(s->event, &event_source, synchronize_second_half, link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate defer event source: %m");
|
|
|
|
|
|
|
|
r = sd_event_source_set_destroy_callback(event_source, synchronize_destroy);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to set event source destroy callback: %m");
|
|
|
|
|
2020-04-16 17:50:21 +02:00
|
|
|
varlink_ref(link); /* The varlink object is now left to the destroy callback to unref */
|
2019-04-04 19:41:33 +02:00
|
|
|
|
|
|
|
r = sd_event_source_set_priority(event_source, SD_EVENT_PRIORITY_NORMAL+15);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to set defer event source priority: %m");
|
|
|
|
|
|
|
|
/* Give up ownership of this event source. It will now be destroyed along with event loop itself,
|
|
|
|
* unless it destroys itself earlier. */
|
|
|
|
r = sd_event_source_set_floating(event_source, true);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to mark event source as floating: %m");
|
|
|
|
|
|
|
|
(void) sd_event_source_set_description(event_source, "deferred-sync");
|
|
|
|
|
|
|
|
return 0;
|
2019-04-04 19:38:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int vl_method_rotate(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (json_variant_elements(parameters) > 0)
|
|
|
|
return varlink_error_invalid_parameter(link, parameters);
|
|
|
|
|
|
|
|
log_info("Received client request to rotate journal.");
|
|
|
|
server_full_rotate(s);
|
|
|
|
|
|
|
|
return varlink_reply(link, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vl_method_flush_to_var(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (json_variant_elements(parameters) > 0)
|
|
|
|
return varlink_error_invalid_parameter(link, parameters);
|
2019-11-25 15:00:38 +01:00
|
|
|
if (s->namespace)
|
|
|
|
return varlink_error(link, "io.systemd.Journal.NotSupportedByNamespaces", NULL);
|
2019-04-04 19:38:18 +02:00
|
|
|
|
|
|
|
log_info("Received client request to flush runtime journal.");
|
|
|
|
server_full_flush(s);
|
|
|
|
|
|
|
|
return varlink_reply(link, NULL);
|
|
|
|
}
|
|
|
|
|
2019-04-05 18:20:25 +02:00
|
|
|
static int vl_method_relinquish_var(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (json_variant_elements(parameters) > 0)
|
|
|
|
return varlink_error_invalid_parameter(link, parameters);
|
2019-11-25 15:00:38 +01:00
|
|
|
if (s->namespace)
|
|
|
|
return varlink_error(link, "io.systemd.Journal.NotSupportedByNamespaces", NULL);
|
2019-04-05 18:20:25 +02:00
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
log_info("Received client request to relinquish %s access.", s->system_storage.path);
|
2019-04-05 18:20:25 +02:00
|
|
|
server_relinquish_var(s);
|
|
|
|
|
|
|
|
return varlink_reply(link, NULL);
|
|
|
|
}
|
|
|
|
|
2019-11-27 14:45:24 +01:00
|
|
|
static int vl_connect(VarlinkServer *server, Varlink *link, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
|
|
|
|
assert(server);
|
|
|
|
assert(link);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
(void) server_start_or_stop_idle_timer(s); /* maybe we are no longer idle */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vl_disconnect(VarlinkServer *server, Varlink *link, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
|
|
|
|
assert(server);
|
|
|
|
assert(link);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
(void) server_start_or_stop_idle_timer(s); /* maybe we are idle now */
|
|
|
|
}
|
|
|
|
|
2019-11-27 14:47:37 +01:00
|
|
|
static int server_open_varlink(Server *s, const char *socket, int fd) {
|
2019-04-04 19:38:18 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
r = varlink_server_new(&s->varlink_server, VARLINK_SERVER_ROOT_ONLY);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
varlink_server_set_userdata(s->varlink_server, s);
|
|
|
|
|
|
|
|
r = varlink_server_bind_method_many(
|
|
|
|
s->varlink_server,
|
2019-04-05 18:20:25 +02:00
|
|
|
"io.systemd.Journal.Synchronize", vl_method_synchronize,
|
|
|
|
"io.systemd.Journal.Rotate", vl_method_rotate,
|
|
|
|
"io.systemd.Journal.FlushToVar", vl_method_flush_to_var,
|
|
|
|
"io.systemd.Journal.RelinquishVar", vl_method_relinquish_var);
|
2019-04-04 19:38:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-11-27 14:45:24 +01:00
|
|
|
r = varlink_server_bind_connect(s->varlink_server, vl_connect);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = varlink_server_bind_disconnect(s->varlink_server, vl_disconnect);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-11-27 14:47:37 +01:00
|
|
|
if (fd < 0)
|
|
|
|
r = varlink_server_listen_address(s->varlink_server, socket, 0600);
|
|
|
|
else
|
|
|
|
r = varlink_server_listen_fd(s->varlink_server, fd);
|
2019-04-04 19:38:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = varlink_server_attach_event(s->varlink_server, s->event, SD_EVENT_PRIORITY_NORMAL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-27 14:45:24 +01:00
|
|
|
static bool server_is_idle(Server *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
/* The server for the main namespace is never idle */
|
|
|
|
if (!s->namespace)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* If a retention maximum is set larger than the idle time we need to be running to enforce it, hence
|
|
|
|
* turn off the idle logic. */
|
|
|
|
if (s->max_retention_usec > IDLE_TIMEOUT_USEC)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* We aren't idle if we have a varlink client */
|
|
|
|
if (varlink_server_current_connections(s->varlink_server) > 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* If we have stdout streams we aren't idle */
|
|
|
|
if (s->n_stdout_streams > 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int server_idle_handler(sd_event_source *source, uint64_t usec, void *userdata) {
|
|
|
|
Server *s = userdata;
|
|
|
|
|
|
|
|
assert(source);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
log_debug("Server is idle, exiting.");
|
|
|
|
sd_event_exit(s->event, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int server_start_or_stop_idle_timer(Server *s) {
|
|
|
|
_cleanup_(sd_event_source_unrefp) sd_event_source *source = NULL;
|
|
|
|
usec_t when;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (!server_is_idle(s)) {
|
|
|
|
s->idle_event_source = sd_event_source_disable_unref(s->idle_event_source);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->idle_event_source)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
r = sd_event_now(s->event, CLOCK_MONOTONIC, &when);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to determine current time: %m");
|
|
|
|
|
|
|
|
r = sd_event_add_time(s->event, &source, CLOCK_MONOTONIC, usec_add(when, IDLE_TIMEOUT_USEC), 0, server_idle_handler, s);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate idle timer: %m");
|
|
|
|
|
|
|
|
r = sd_event_source_set_priority(source, SD_EVENT_PRIORITY_IDLE);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to set idle timer priority: %m");
|
|
|
|
|
|
|
|
(void) sd_event_source_set_description(source, "idle-timer");
|
|
|
|
|
|
|
|
s->idle_event_source = TAKE_PTR(source);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int server_refresh_idle_timer(Server *s) {
|
|
|
|
usec_t when;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (!s->idle_event_source)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_event_now(s->event, CLOCK_MONOTONIC, &when);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to determine current time: %m");
|
|
|
|
|
|
|
|
r = sd_event_source_set_time(s->idle_event_source, usec_add(when, IDLE_TIMEOUT_USEC));
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to refresh idle timer: %m");
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
static int set_namespace(Server *s, const char *namespace) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (!namespace)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!log_namespace_name_valid(namespace))
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specified namespace name not valid, refusing: %s", namespace);
|
|
|
|
|
|
|
|
s->namespace = strdup(namespace);
|
|
|
|
if (!s->namespace)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
s->namespace_field = strjoin("_NAMESPACE=", namespace);
|
|
|
|
if (!s->namespace_field)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int server_init(Server *s, const char *namespace) {
|
2019-11-27 14:47:37 +01:00
|
|
|
const char *native_socket, *syslog_socket, *stdout_socket, *varlink_socket, *e;
|
2015-01-06 00:30:25 +01:00
|
|
|
_cleanup_fdset_free_ FDSet *fds = NULL;
|
2019-11-27 14:47:37 +01:00
|
|
|
int n, r, fd, varlink_fd = -1;
|
2015-08-02 19:55:57 +02:00
|
|
|
bool no_sockets;
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2019-04-04 17:30:51 +02:00
|
|
|
*s = (Server) {
|
|
|
|
.syslog_fd = -1,
|
|
|
|
.native_fd = -1,
|
|
|
|
.stdout_fd = -1,
|
|
|
|
.dev_kmsg_fd = -1,
|
|
|
|
.audit_fd = -1,
|
|
|
|
.hostname_fd = -1,
|
|
|
|
.notify_fd = -1,
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-04-04 17:30:51 +02:00
|
|
|
.compress.enabled = true,
|
|
|
|
.compress.threshold_bytes = (uint64_t) -1,
|
|
|
|
.seal = true,
|
2015-11-03 12:28:19 +01:00
|
|
|
|
2020-04-16 12:04:03 +02:00
|
|
|
.set_audit = true,
|
|
|
|
|
2019-04-04 17:30:51 +02:00
|
|
|
.watchdog_usec = USEC_INFINITY,
|
|
|
|
|
|
|
|
.sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC,
|
|
|
|
.sync_scheduled = false,
|
2013-03-25 17:49:03 +01:00
|
|
|
|
2019-09-19 17:49:14 +02:00
|
|
|
.ratelimit_interval = DEFAULT_RATE_LIMIT_INTERVAL,
|
|
|
|
.ratelimit_burst = DEFAULT_RATE_LIMIT_BURST,
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-04-04 17:30:51 +02:00
|
|
|
.forward_to_wall = true,
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-04-04 17:30:51 +02:00
|
|
|
.max_file_usec = DEFAULT_MAX_FILE_USEC,
|
2014-06-26 22:11:35 +02:00
|
|
|
|
2019-04-04 17:30:51 +02:00
|
|
|
.max_level_store = LOG_DEBUG,
|
|
|
|
.max_level_syslog = LOG_DEBUG,
|
|
|
|
.max_level_kmsg = LOG_NOTICE,
|
|
|
|
.max_level_console = LOG_INFO,
|
|
|
|
.max_level_wall = LOG_EMERG,
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-04-04 17:30:51 +02:00
|
|
|
.line_max = DEFAULT_LINE_MAX,
|
|
|
|
|
|
|
|
.runtime_storage.name = "Runtime Journal",
|
|
|
|
.system_storage.name = "System Journal",
|
|
|
|
};
|
journald: make maximum size of stream log lines configurable and bump it to 48K (#6838)
This adds a new setting LineMax= to journald.conf, and sets it by
default to 48K. When we convert stream-based stdout/stderr logging into
record-based log entries, read up to the specified amount of bytes
before forcing a line-break.
This also makes three related changes:
- When a NUL byte is read we'll not recognize this as alternative line
break, instead of silently dropping everything after it. (see #4863)
- The reason for a line-break is now encoded in the log record, if it
wasn't a plain newline. Specifically, we distuingish "nul",
"line-max" and "eof", for line breaks due to NUL byte, due to the
maximum line length as configured with LineMax= or due to end of
stream. This data is stored in the new implicit _LINE_BREAK= field.
It's not synthesized for plain \n line breaks.
- A randomized 128bit ID is assigned to each log stream.
With these three changes in place it's (mostly) possible to reconstruct
the original byte streams from log data, as (most) of the context of
the conversion from the byte stream to log records is saved now. (So,
the only bits we still drop are empty lines. Which might be something to
look into in a future change, and which is outside of the scope of this
work)
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=86465
See: #4863
Replaces: #4875
2017-09-22 10:22:24 +02:00
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
r = set_namespace(s, namespace);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
/* By default, only read from /dev/kmsg if are the main namespace */
|
|
|
|
s->read_kmsg = !s->namespace;
|
|
|
|
s->storage = s->namespace ? STORAGE_PERSISTENT : STORAGE_AUTO;
|
|
|
|
|
2016-10-04 17:13:21 +02:00
|
|
|
journal_reset_metrics(&s->system_storage.metrics);
|
|
|
|
journal_reset_metrics(&s->runtime_storage.metrics);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
server_parse_config_file(s);
|
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
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
if (!s->namespace) {
|
|
|
|
/* Parse kernel command line, but only if we are not a namespace instance */
|
|
|
|
r = proc_cmdline_parse(parse_proc_cmdline_item, s, PROC_CMDLINE_STRIP_RD_PREFIX);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
|
|
|
}
|
2015-10-02 23:21:59 +02:00
|
|
|
|
2019-11-22 13:59:59 +01:00
|
|
|
if (!!s->ratelimit_interval != !!s->ratelimit_burst) { /* One set to 0 and the other not? */
|
2014-10-11 17:37:37 +02:00
|
|
|
log_debug("Setting both rate limit interval and burst from "USEC_FMT",%u to 0,0",
|
2019-09-19 17:49:14 +02:00
|
|
|
s->ratelimit_interval, s->ratelimit_burst);
|
|
|
|
s->ratelimit_interval = s->ratelimit_burst = 0;
|
2013-03-03 02:14:21 +01:00
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
e = getenv("RUNTIME_DIRECTORY");
|
|
|
|
if (e)
|
|
|
|
s->runtime_directory = strdup(e);
|
|
|
|
else if (s->namespace)
|
|
|
|
s->runtime_directory = strjoin("/run/systemd/journal.", s->namespace);
|
|
|
|
else
|
|
|
|
s->runtime_directory = strdup("/run/systemd/journal");
|
|
|
|
if (!s->runtime_directory)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
(void) mkdir_p(s->runtime_directory, 0755);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2014-08-22 13:44:14 +02:00
|
|
|
s->user_journals = ordered_hashmap_new(NULL);
|
2012-11-12 17:29:07 +01:00
|
|
|
if (!s->user_journals)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
s->mmap = mmap_cache_new();
|
|
|
|
if (!s->mmap)
|
|
|
|
return log_oom();
|
|
|
|
|
2016-02-18 02:37:10 +01:00
|
|
|
s->deferred_closes = set_new(NULL);
|
|
|
|
if (!s->deferred_closes)
|
|
|
|
return log_oom();
|
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
r = sd_event_default(&s->event);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to create event loop: %m");
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
n = sd_listen_fds(true);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (n < 0)
|
|
|
|
return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
native_socket = strjoina(s->runtime_directory, "/socket");
|
|
|
|
stdout_socket = strjoina(s->runtime_directory, "/stdout");
|
|
|
|
syslog_socket = strjoina(s->runtime_directory, "/dev-log");
|
2019-11-27 14:47:37 +01:00
|
|
|
varlink_socket = strjoina(s->runtime_directory, "/io.systemd.journal");
|
2019-11-25 15:00:38 +01:00
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, native_socket, 0) > 0) {
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (s->native_fd >= 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Too many native sockets passed.");
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
s->native_fd = fd;
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
} else if (sd_is_socket_unix(fd, SOCK_STREAM, 1, stdout_socket, 0) > 0) {
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (s->stdout_fd >= 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Too many stdout sockets passed.");
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
s->stdout_fd = fd;
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
} else if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, syslog_socket, 0) > 0) {
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (s->syslog_fd >= 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Too many /dev/log sockets passed.");
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
s->syslog_fd = fd;
|
|
|
|
|
2019-11-27 14:47:37 +01:00
|
|
|
} else if (sd_is_socket_unix(fd, SOCK_STREAM, 1, varlink_socket, 0) > 0) {
|
|
|
|
|
|
|
|
if (varlink_fd >= 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Too many varlink sockets passed.");
|
|
|
|
|
|
|
|
varlink_fd = fd;
|
2014-11-03 20:58:24 +01:00
|
|
|
} else if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
|
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (s->audit_fd >= 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Too many audit sockets passed.");
|
2014-11-03 20:58:24 +01:00
|
|
|
|
|
|
|
s->audit_fd = fd;
|
|
|
|
|
2014-11-30 00:51:45 +01:00
|
|
|
} else {
|
|
|
|
|
2015-01-06 00:30:25 +01:00
|
|
|
if (!fds) {
|
|
|
|
fds = fdset_new();
|
|
|
|
if (!fds)
|
|
|
|
return log_oom();
|
|
|
|
}
|
2014-11-30 00:51:45 +01:00
|
|
|
|
2015-01-06 00:30:25 +01:00
|
|
|
r = fdset_put(fds, fd);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
2014-11-30 00:51:45 +01:00
|
|
|
}
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
2015-08-02 01:53:03 +02:00
|
|
|
/* Try to restore streams, but don't bother if this fails */
|
|
|
|
(void) server_restore_streams(s, fds);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2015-01-06 00:30:25 +01:00
|
|
|
if (fdset_size(fds) > 0) {
|
|
|
|
log_warning("%u unknown file descriptors passed, closing.", fdset_size(fds));
|
|
|
|
fds = fdset_free(fds);
|
|
|
|
}
|
|
|
|
|
2019-11-27 14:47:37 +01:00
|
|
|
no_sockets = s->native_fd < 0 && s->stdout_fd < 0 && s->syslog_fd < 0 && s->audit_fd < 0 && varlink_fd < 0;
|
2015-08-02 19:55:57 +02:00
|
|
|
|
|
|
|
/* always open stdout, syslog, native, and kmsg sockets */
|
2015-10-12 05:25:43 +02:00
|
|
|
|
|
|
|
/* systemd-journald.socket: /run/systemd/journal/stdout */
|
2019-11-25 15:00:38 +01:00
|
|
|
r = server_open_stdout_socket(s, stdout_socket);
|
2015-08-02 01:53:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-10-12 05:25:43 +02:00
|
|
|
/* systemd-journald-dev-log.socket: /run/systemd/journal/dev-log */
|
2019-11-25 15:00:38 +01:00
|
|
|
r = server_open_syslog_socket(s, syslog_socket);
|
2012-11-12 17:29:07 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-10-12 05:25:43 +02:00
|
|
|
/* systemd-journald.socket: /run/systemd/journal/socket */
|
2019-11-25 15:00:38 +01:00
|
|
|
r = server_open_native_socket(s, native_socket);
|
2012-11-12 17:29:07 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-07-15 13:57:52 +02:00
|
|
|
/* /dev/kmsg */
|
2012-11-12 17:29:07 +01:00
|
|
|
r = server_open_dev_kmsg(s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-08-02 19:55:57 +02:00
|
|
|
/* Unless we got *some* sockets and not audit, open audit socket */
|
|
|
|
if (s->audit_fd >= 0 || no_sockets) {
|
|
|
|
r = server_open_audit(s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2014-11-03 20:58:24 +01:00
|
|
|
|
2019-11-27 14:47:37 +01:00
|
|
|
r = server_open_varlink(s, varlink_socket, varlink_fd);
|
2019-04-04 19:38:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
r = server_open_kernel_seqnum(s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2013-12-11 22:55:57 +01:00
|
|
|
r = server_open_hostname(s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
r = setup_signals(s);
|
2012-11-12 17:29:07 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-19 17:49:14 +02:00
|
|
|
s->ratelimit = journal_ratelimit_new();
|
|
|
|
if (!s->ratelimit)
|
2019-11-22 14:00:40 +01:00
|
|
|
return log_oom();
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2013-12-11 23:31:07 +01:00
|
|
|
r = cg_get_root_path(&s->cgroup_root);
|
|
|
|
if (r < 0)
|
2019-11-22 14:00:40 +01:00
|
|
|
return log_error_errno(r, "Failed to acquire cgroup root path: %m");
|
2013-12-11 23:31:07 +01:00
|
|
|
|
2013-12-11 22:55:57 +01:00
|
|
|
server_cache_hostname(s);
|
|
|
|
server_cache_boot_id(s);
|
|
|
|
server_cache_machine_id(s);
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
if (s->namespace)
|
|
|
|
s->runtime_storage.path = strjoin("/run/log/journal/", SERVER_MACHINE_ID(s), ".", s->namespace);
|
|
|
|
else
|
|
|
|
s->runtime_storage.path = strjoin("/run/log/journal/", SERVER_MACHINE_ID(s));
|
|
|
|
if (!s->runtime_storage.path)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
e = getenv("LOGS_DIRECTORY");
|
|
|
|
if (e)
|
|
|
|
s->system_storage.path = strdup(e);
|
|
|
|
else if (s->namespace)
|
|
|
|
s->system_storage.path = strjoin("/var/log/journal/", SERVER_MACHINE_ID(s), ".", s->namespace);
|
|
|
|
else
|
|
|
|
s->system_storage.path = strjoin("/var/log/journal/", SERVER_MACHINE_ID(s));
|
|
|
|
if (!s->system_storage.path)
|
2019-11-22 14:00:40 +01:00
|
|
|
return log_oom();
|
2016-10-04 17:13:21 +02:00
|
|
|
|
2015-11-01 21:50:24 +01:00
|
|
|
(void) server_connect_notify(s);
|
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
(void) client_context_acquire_default(s);
|
|
|
|
|
2019-11-27 14:45:24 +01:00
|
|
|
r = system_journal_open(s, false, false);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
server_start_or_stop_idle_timer(s);
|
|
|
|
return 0;
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void server_maybe_append_tags(Server *s) {
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_GCRYPT
|
2012-11-12 17:29:07 +01:00
|
|
|
JournalFile *f;
|
|
|
|
Iterator i;
|
|
|
|
usec_t n;
|
|
|
|
|
|
|
|
n = now(CLOCK_REALTIME);
|
|
|
|
|
|
|
|
if (s->system_journal)
|
|
|
|
journal_file_maybe_append_tag(s->system_journal, n);
|
|
|
|
|
2014-08-22 13:44:14 +02:00
|
|
|
ORDERED_HASHMAP_FOREACH(f, s->user_journals, i)
|
2012-11-12 17:29:07 +01:00
|
|
|
journal_file_maybe_append_tag(f, n);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void server_done(Server *s) {
|
|
|
|
assert(s);
|
|
|
|
|
2019-11-25 15:00:38 +01:00
|
|
|
free(s->namespace);
|
|
|
|
free(s->namespace_field);
|
|
|
|
|
2017-11-28 12:40:14 +01:00
|
|
|
set_free_with_destructor(s->deferred_closes, journal_file_close);
|
2016-02-18 02:37:10 +01:00
|
|
|
|
2012-11-12 17:29:07 +01:00
|
|
|
while (s->stdout_streams)
|
|
|
|
stdout_stream_free(s->stdout_streams);
|
|
|
|
|
2017-07-17 23:36:35 +02:00
|
|
|
client_context_flush_all(s);
|
|
|
|
|
2019-05-28 05:40:17 +02:00
|
|
|
(void) journal_file_close(s->system_journal);
|
|
|
|
(void) journal_file_close(s->runtime_journal);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2017-11-28 12:40:14 +01:00
|
|
|
ordered_hashmap_free_with_destructor(s->user_journals, journal_file_close);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-04-04 19:38:18 +02:00
|
|
|
varlink_server_unref(s->varlink_server);
|
|
|
|
|
2013-12-11 20:13:44 +01:00
|
|
|
sd_event_source_unref(s->syslog_event_source);
|
|
|
|
sd_event_source_unref(s->native_event_source);
|
|
|
|
sd_event_source_unref(s->stdout_event_source);
|
|
|
|
sd_event_source_unref(s->dev_kmsg_event_source);
|
2014-11-03 20:58:24 +01:00
|
|
|
sd_event_source_unref(s->audit_event_source);
|
2013-12-11 20:13:44 +01:00
|
|
|
sd_event_source_unref(s->sync_event_source);
|
|
|
|
sd_event_source_unref(s->sigusr1_event_source);
|
|
|
|
sd_event_source_unref(s->sigusr2_event_source);
|
|
|
|
sd_event_source_unref(s->sigterm_event_source);
|
|
|
|
sd_event_source_unref(s->sigint_event_source);
|
2015-11-11 12:59:09 +01:00
|
|
|
sd_event_source_unref(s->sigrtmin1_event_source);
|
2013-12-11 22:55:57 +01:00
|
|
|
sd_event_source_unref(s->hostname_event_source);
|
2015-11-01 21:50:24 +01:00
|
|
|
sd_event_source_unref(s->notify_event_source);
|
2015-11-03 12:28:19 +01:00
|
|
|
sd_event_source_unref(s->watchdog_event_source);
|
2019-11-27 14:45:24 +01:00
|
|
|
sd_event_source_unref(s->idle_event_source);
|
2013-12-11 20:13:44 +01:00
|
|
|
sd_event_unref(s->event);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2014-03-18 19:22:43 +01:00
|
|
|
safe_close(s->syslog_fd);
|
|
|
|
safe_close(s->native_fd);
|
|
|
|
safe_close(s->stdout_fd);
|
|
|
|
safe_close(s->dev_kmsg_fd);
|
2014-11-03 20:58:24 +01:00
|
|
|
safe_close(s->audit_fd);
|
2014-03-18 19:22:43 +01:00
|
|
|
safe_close(s->hostname_fd);
|
2015-11-01 21:50:24 +01:00
|
|
|
safe_close(s->notify_fd);
|
2013-12-11 22:55:57 +01:00
|
|
|
|
2019-09-19 17:49:14 +02:00
|
|
|
if (s->ratelimit)
|
|
|
|
journal_ratelimit_free(s->ratelimit);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
|
|
|
if (s->kernel_seqnum)
|
|
|
|
munmap(s->kernel_seqnum, sizeof(uint64_t));
|
|
|
|
|
|
|
|
free(s->buffer);
|
|
|
|
free(s->tty_path);
|
2013-12-11 23:31:07 +01:00
|
|
|
free(s->cgroup_root);
|
2014-11-03 21:11:16 +01:00
|
|
|
free(s->hostname_field);
|
2017-05-19 18:52:05 +02:00
|
|
|
free(s->runtime_storage.path);
|
|
|
|
free(s->system_storage.path);
|
2019-11-25 15:00:38 +01:00
|
|
|
free(s->runtime_directory);
|
2012-11-12 17:29:07 +01:00
|
|
|
|
2019-04-05 15:37:20 +02:00
|
|
|
mmap_cache_unref(s->mmap);
|
2012-11-12 17:29:07 +01:00
|
|
|
}
|
2015-10-02 23:21:59 +02:00
|
|
|
|
|
|
|
static const char* const storage_table[_STORAGE_MAX] = {
|
|
|
|
[STORAGE_AUTO] = "auto",
|
|
|
|
[STORAGE_VOLATILE] = "volatile",
|
|
|
|
[STORAGE_PERSISTENT] = "persistent",
|
|
|
|
[STORAGE_NONE] = "none"
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(storage, Storage);
|
|
|
|
DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
|
|
|
|
|
|
|
|
static const char* const split_mode_table[_SPLIT_MAX] = {
|
|
|
|
[SPLIT_LOGIN] = "login",
|
|
|
|
[SPLIT_UID] = "uid",
|
|
|
|
[SPLIT_NONE] = "none",
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
|
|
|
|
DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting");
|
journald: make maximum size of stream log lines configurable and bump it to 48K (#6838)
This adds a new setting LineMax= to journald.conf, and sets it by
default to 48K. When we convert stream-based stdout/stderr logging into
record-based log entries, read up to the specified amount of bytes
before forcing a line-break.
This also makes three related changes:
- When a NUL byte is read we'll not recognize this as alternative line
break, instead of silently dropping everything after it. (see #4863)
- The reason for a line-break is now encoded in the log record, if it
wasn't a plain newline. Specifically, we distuingish "nul",
"line-max" and "eof", for line breaks due to NUL byte, due to the
maximum line length as configured with LineMax= or due to end of
stream. This data is stored in the new implicit _LINE_BREAK= field.
It's not synthesized for plain \n line breaks.
- A randomized 128bit ID is assigned to each log stream.
With these three changes in place it's (mostly) possible to reconstruct
the original byte streams from log data, as (most) of the context of
the conversion from the byte stream to log records is saved now. (So,
the only bits we still drop are empty lines. Which might be something to
look into in a future change, and which is outside of the scope of this
work)
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=86465
See: #4863
Replaces: #4875
2017-09-22 10:22:24 +02:00
|
|
|
|
|
|
|
int config_parse_line_max(
|
|
|
|
const char* unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
|
|
|
size_t *sz = data;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
if (isempty(rvalue))
|
|
|
|
/* Empty assignment means default */
|
|
|
|
*sz = DEFAULT_LINE_MAX;
|
|
|
|
else {
|
|
|
|
uint64_t v;
|
|
|
|
|
|
|
|
r = parse_size(rvalue, 1024, &v);
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse LineMax= value, ignoring: %s", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v < 79) {
|
|
|
|
/* Why specify 79 here as minimum line length? Simply, because the most common traditional
|
|
|
|
* terminal size is 80ch, and it might make sense to break one character before the natural
|
|
|
|
* line break would occur on that. */
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too small, clamping to 79: %s", rvalue);
|
|
|
|
*sz = 79;
|
|
|
|
} else if (v > (uint64_t) (SSIZE_MAX-1)) {
|
|
|
|
/* So, why specify SSIZE_MAX-1 here? Because that's one below the largest size value read()
|
|
|
|
* can return, and we need one extra byte for the trailing NUL byte. Of course IRL such large
|
|
|
|
* memory allocations will fail anyway, hence this limit is mostly theoretical anyway, as we'll
|
|
|
|
* fail much earlier anyway. */
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too large, clamping to %" PRIu64 ": %s", (uint64_t) (SSIZE_MAX-1), rvalue);
|
|
|
|
*sz = SSIZE_MAX-1;
|
|
|
|
} else
|
|
|
|
*sz = (size_t) v;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-02-27 18:37:23 +01:00
|
|
|
|
2019-04-05 18:20:06 +02:00
|
|
|
int config_parse_compress(
|
|
|
|
const char* unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
2018-02-27 18:37:23 +01:00
|
|
|
JournalCompressOptions* compress = data;
|
|
|
|
int r;
|
|
|
|
|
2019-04-05 18:20:06 +02:00
|
|
|
if (isempty(rvalue)) {
|
|
|
|
compress->enabled = true;
|
|
|
|
compress->threshold_bytes = (uint64_t) -1;
|
|
|
|
} else if (streq(rvalue, "1")) {
|
2018-02-27 18:37:23 +01:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
|
|
|
"Compress= ambiguously specified as 1, enabling compression with default threshold");
|
|
|
|
compress->enabled = true;
|
|
|
|
} else if (streq(rvalue, "0")) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
|
|
|
"Compress= ambiguously specified as 0, disabling compression");
|
|
|
|
compress->enabled = false;
|
2019-04-05 18:20:06 +02:00
|
|
|
} else {
|
|
|
|
r = parse_boolean(rvalue);
|
|
|
|
if (r < 0) {
|
|
|
|
r = parse_size(rvalue, 1024, &compress->threshold_bytes);
|
|
|
|
if (r < 0)
|
|
|
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
|
|
|
"Failed to parse Compress= value, ignoring: %s", rvalue);
|
|
|
|
else
|
|
|
|
compress->enabled = true;
|
|
|
|
} else
|
|
|
|
compress->enabled = r;
|
|
|
|
}
|
2018-02-27 18:37:23 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|