journald-server.c revision 13790add4bf648fed816361794d8277a75253410
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff/***
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff This file is part of systemd.
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff Copyright 2011 Lennart Poettering
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff systemd is free software; you can redistribute it and/or modify it
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff under the terms of the GNU Lesser General Public License as published by
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff the Free Software Foundation; either version 2.1 of the License, or
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff (at your option) any later version.
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff systemd is distributed in the hope that it will be useful, but
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff WITHOUT ANY WARRANTY; without even the implied warranty of
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff Lesser General Public License for more details.
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff You should have received a copy of the GNU Lesser General Public License
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff along with systemd; If not, see <http://www.gnu.org/licenses/>.
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff***/
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include <sys/signalfd.h>
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include <sys/ioctl.h>
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include <linux/sockios.h>
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include <sys/statvfs.h>
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include <sys/mman.h>
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include <sys/timerfd.h>
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff#include <libudev.h>
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "sd-journal.h"
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff#include "sd-messages.h"
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff#include "sd-daemon.h"
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include "fileio.h"
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff#include "mkdir.h"
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff#include "hashmap.h"
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include "journal-file.h"
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include "socket-util.h"
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include "cgroup-util.h"
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff#include "list.h"
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "missing.h"
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "conf-parser.h"
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "selinux-util.h"
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "journal-internal.h"
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "journal-vacuum.h"
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "journal-authenticate.h"
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "journald-rate-limit.h"
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "journald-kmsg.h"
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "journald-syslog.h"
31fab17bcdbe302592a6c0dc5374ef56333ee879Michael Graff#include "journald-stream.h"
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff#include "journald-console.h"
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include "journald-native.h"
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include "journald-audit.h"
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include "journald-server.h"
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#ifdef HAVE_ACL
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include <sys/acl.h>
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include <acl/libacl.h>
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#include "acl-util.h"
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff#endif
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff#ifdef HAVE_SELINUX
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff#include <selinux/selinux.h>
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff#endif
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff#define USER_JOURNALS_MAX 1024
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff#define DEFAULT_SYNC_INTERVAL_USEC (5*USEC_PER_MINUTE)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff#define DEFAULT_RATE_LIMIT_INTERVAL (30*USEC_PER_SEC)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff#define DEFAULT_RATE_LIMIT_BURST 1000
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff#define DEFAULT_MAX_FILE_USEC USEC_PER_MONTH
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graffstatic const char* const storage_table[_STORAGE_MAX] = {
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff [STORAGE_AUTO] = "auto",
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff [STORAGE_VOLATILE] = "volatile",
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff [STORAGE_PERSISTENT] = "persistent",
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff [STORAGE_NONE] = "none"
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff};
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael GraffDEFINE_STRING_TABLE_LOOKUP(storage, Storage);
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael GraffDEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graffstatic const char* const split_mode_table[_SPLIT_MAX] = {
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff [SPLIT_LOGIN] = "login",
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff [SPLIT_UID] = "uid",
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff [SPLIT_NONE] = "none",
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff};
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael GraffDEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael GraffDEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting");
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graffstatic uint64_t available_space(Server *s, bool verbose) {
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff char ids[33];
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff _cleanup_free_ char *p = NULL;
213973a334f92d4aef4ef62b4538fc2e4d0e8082Michael Graff sd_id128_t machine;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff struct statvfs ss;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff uint64_t sum = 0, ss_avail = 0, avail = 0;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff int r;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff _cleanup_closedir_ DIR *d = NULL;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff usec_t ts;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff const char *f;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff JournalMetrics *m;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff ts = now(CLOCK_MONOTONIC);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff && !verbose)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff return s->cached_available_space;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff r = sd_id128_get_machine(&machine);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (r < 0)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff return 0;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (s->system_journal) {
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff f = "/var/log/journal/";
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff m = &s->system_metrics;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff } else {
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff f = "/run/log/journal/";
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff m = &s->runtime_metrics;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff }
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff assert(m);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff p = strappend(f, sd_id128_to_string(machine, ids));
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (!p)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff return 0;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff d = opendir(p);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (!d)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff return 0;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (fstatvfs(dirfd(d), &ss) < 0)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff return 0;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff for (;;) {
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff struct stat st;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff struct dirent *de;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff errno = 0;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff de = readdir(d);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (!de && errno != 0)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff return 0;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (!de)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff break;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (!endswith(de->d_name, ".journal") &&
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff !endswith(de->d_name, ".journal~"))
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff continue;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff continue;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (!S_ISREG(st.st_mode))
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff continue;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sum += (uint64_t) st.st_blocks * 512UL;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff ss_avail = ss.f_bsize * ss.f_bavail;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff /* If we reached a high mark, we will always allow this much
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff * again, unless usage goes above max_use. This watermark
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff * value is cached so that we don't give up space on pressure,
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff * but hover below the maximum usage. */
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (m->use < sum)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff m->use = sum;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff avail = LESS_BY(ss_avail, m->keep_free);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff s->cached_available_space_timestamp = ts;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (verbose) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff char fb1[FORMAT_BYTES_MAX], fb2[FORMAT_BYTES_MAX], fb3[FORMAT_BYTES_MAX],
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX];
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE,
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff "%s journal is using %s (max allowed %s, "
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff "trying to leave %s free of %s available → current limit %s).",
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff s->system_journal ? "Permanent" : "Runtime",
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff format_bytes(fb1, sizeof(fb1), sum),
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff format_bytes(fb2, sizeof(fb2), m->max_use),
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff format_bytes(fb3, sizeof(fb3), m->keep_free),
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff format_bytes(fb4, sizeof(fb4), ss_avail),
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum));
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return s->cached_available_space;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff}
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graffvoid server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff int r;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#ifdef HAVE_ACL
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff acl_t acl;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff acl_entry_t entry;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff acl_permset_t permset;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#endif
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(f);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = fchmod(f->fd, 0640);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r < 0)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_warning_errno(r, "Failed to fix access mode on %s, ignoring: %m", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#ifdef HAVE_ACL
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (uid <= SYSTEM_UID_MAX)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff acl = acl_get_fd(f->fd);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (!acl) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_warning_errno(errno, "Failed to read ACL on %s, ignoring: %m", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = acl_find_uid(acl, uid, &entry);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r <= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (acl_create_entry(&acl, &entry) < 0 ||
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff acl_set_tag_type(entry, ACL_USER) < 0 ||
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff acl_set_qualifier(entry, &uid) < 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff goto finish;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff /* We do not recalculate the mask unconditionally here,
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff * so that the fchmod() mask above stays intact. */
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (acl_get_permset(entry, &permset) < 0 ||
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff acl_add_perm(permset, ACL_READ) < 0 ||
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff calc_acl_mask_if_needed(&acl) < 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff goto finish;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (acl_set_fd(f->fd, acl) < 0)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Grafffinish:
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff acl_free(acl);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#endif
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff}
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graffstatic JournalFile* find_journal(Server *s, uid_t uid) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff _cleanup_free_ char *p = NULL;
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff int r;
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff JournalFile *f;
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff sd_id128_t machine;
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(s);
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff /* We split up user logs only on /var, not on /run. If the
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff * runtime file is open, we write to it exclusively, in order
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff * to guarantee proper order as soon as we flush /run to
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff * /var and close the runtime file. */
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff if (s->runtime_journal)
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff return s->runtime_journal;
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff if (uid <= SYSTEM_UID_MAX)
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff return s->system_journal;
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = sd_id128_get_machine(&machine);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r < 0)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return s->system_journal;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff f = ordered_hashmap_get(s->user_journals, UINT32_TO_PTR(uid));
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (f)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return f;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
519b4a1a27c8b767a57a981dda69a3c6394bd49dMichael Graff if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/user-"UID_FMT".journal",
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff SD_ID128_FORMAT_VAL(machine), uid) < 0)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return s->system_journal;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff while (ordered_hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff /* Too many open? Then let's close one */
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff f = ordered_hashmap_steal_first(s->user_journals);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(f);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff journal_file_close(f);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &f);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r < 0)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return s->system_journal;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff server_fix_perms(s, f, uid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = ordered_hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r < 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff journal_file_close(f);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return s->system_journal;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return f;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff}
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graffstatic int do_rotate(
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff Server *s,
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff JournalFile **f,
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff const char* name,
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff bool seal,
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff uint32_t uid) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff int r;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(s);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (!*f)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return -EINVAL;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = journal_file_rotate(f, s->compress, seal);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r < 0)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (*f)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_error_errno(r, "Failed to rotate %s: %m", (*f)->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff else
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_error_errno(r, "Failed to create new %s journal: %m", name);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff else
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff server_fix_perms(s, *f, uid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return r;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff}
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graffvoid server_rotate(Server *s) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff JournalFile *f;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff void *k;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff Iterator i;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff int r;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_debug("Rotating...");
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff do_rotate(s, &s->runtime_journal, "runtime", false, 0);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff do_rotate(s, &s->system_journal, "system", s->seal, 0);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = do_rotate(s, &f, "user", s->seal, PTR_TO_UINT32(k));
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r >= 0)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff ordered_hashmap_replace(s->user_journals, k, f);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff else if (!f)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff /* Old file has been closed and deallocated */
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff ordered_hashmap_remove(s->user_journals, k);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff}
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graffvoid server_sync(Server *s) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff JournalFile *f;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff void *k;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff Iterator i;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff int r;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (s->system_journal) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = journal_file_set_offline(s->system_journal);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (r < 0)
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff log_error_errno(r, "Failed to sync system journal: %m");
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff }
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff r = journal_file_set_offline(f);
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff if (r < 0)
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff log_error_errno(r, "Failed to sync user journal: %m");
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff }
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff if (s->sync_event_source) {
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff r = sd_event_source_set_enabled(s->sync_event_source, SD_EVENT_OFF);
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff if (r < 0)
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff log_error_errno(r, "Failed to disable sync timer source: %m");
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff }
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff s->sync_scheduled = false;
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff}
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graffstatic void do_vacuum(
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff Server *s,
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff const char *id,
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff JournalFile *f,
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff const char* path,
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff JournalMetrics *metrics) {
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff const char *p;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff int r;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff if (!f)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff p = strappenda(path, id);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec, false);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (r < 0 && r != -ENOENT)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff log_error_errno(r, "Failed to vacuum %s: %m", p);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff}
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graffvoid server_vacuum(Server *s) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff char ids[33];
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sd_id128_t machine;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff int r;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_debug("Vacuuming...");
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff s->oldest_file_usec = 0;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = sd_id128_get_machine(&machine);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r < 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_error_errno(r, "Failed to get machine ID: %m");
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sd_id128_to_string(machine, ids);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff do_vacuum(s, ids, s->system_journal, "/var/log/journal/", &s->system_metrics);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff do_vacuum(s, ids, s->runtime_journal, "/run/log/journal/", &s->runtime_metrics);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff s->cached_available_space_timestamp = 0;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff}
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graffstatic void server_cache_machine_id(Server *s) {
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff sd_id128_t id;
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff int r;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff assert(s);
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff r = sd_id128_get_machine(&id);
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff if (r < 0)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return;
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sd_id128_to_string(id, stpcpy(s->machine_id_field, "_MACHINE_ID="));
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff}
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graffstatic void server_cache_boot_id(Server *s) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sd_id128_t id;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff int r;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(s);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = sd_id128_get_boot(&id);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r < 0)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sd_id128_to_string(id, stpcpy(s->boot_id_field, "_BOOT_ID="));
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff}
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graffstatic void server_cache_hostname(Server *s) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff _cleanup_free_ char *t = NULL;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff char *x;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(s);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff t = gethostname_malloc();
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (!t)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappend("_HOSTNAME=", t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (!x)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff return;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff free(s->hostname_field);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff s->hostname_field = x;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff}
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graffstatic bool shall_try_append_again(JournalFile *f, int r) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff /* -E2BIG Hit configured limit
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff -EFBIG Hit fs limit
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff -EDQUOT Quota limit hit
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff -ENOSPC Disk full
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff -EIO I/O error of some kind (mmap)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff -EHOSTDOWN Other machine
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff -EBUSY Unclean shutdown
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff -EPROTONOSUPPORT Unsupported feature
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff -EBADMSG Corrupted
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff -ENODATA Truncated
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff -ESHUTDOWN Already archived
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff -EIDRM Journal file has been deleted */
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r == -E2BIG || r == -EFBIG || r == -EDQUOT || r == -ENOSPC)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_debug("%s: Allocation limit reached, rotating.", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff else if (r == -EHOSTDOWN)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_info("%s: Journal file from other machine, rotating.", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff else if (r == -EBUSY)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_info("%s: Unclean shutdown, rotating.", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff else if (r == -EPROTONOSUPPORT)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_info("%s: Unsupported feature, rotating.", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff else if (r == -EBADMSG || r == -ENODATA || r == ESHUTDOWN)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_warning("%s: Journal file corrupted, rotating.", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff else if (r == -EIO)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_warning("%s: IO error, rotating.", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff else if (r == -EIDRM)
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff log_warning("%s: Journal file has been deleted, rotating.", f->path);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff else
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff return false;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff return true;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff}
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graffstatic void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned n, int priority) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff JournalFile *f;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff bool vacuumed = false;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff int r;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(s);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(iovec);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(n > 0);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff f = find_journal(s, uid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (!f)
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff return;
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff if (journal_file_rotate_suggested(f, s->max_file_usec)) {
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff server_rotate(s);
3024dbecbac365171bc6de0f3fa04951d6558be3Michael Graff server_vacuum(s);
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff vacuumed = true;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff f = find_journal(s, uid);
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff if (!f)
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff return;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff }
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (r >= 0) {
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff server_schedule_sync(s, priority);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff return;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff }
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (vacuumed || !shall_try_append_again(f, r)) {
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff log_error_errno(r, "Failed to write entry (%d items, %zu bytes), ignoring: %m", n, IOVEC_TOTAL_SIZE(iovec, n));
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff return;
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff }
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff server_rotate(s);
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff server_vacuum(s);
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff f = find_journal(s, uid);
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff if (!f)
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff return;
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff log_debug("Retrying write.");
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL);
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff if (r < 0)
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff log_error_errno(r, "Failed to write entry (%d items, %zu bytes) despite vacuuming, ignoring: %m", n, IOVEC_TOTAL_SIZE(iovec, n));
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff else
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff server_schedule_sync(s, priority);
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff}
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graff
50b5857f1ad137624a18ce67b26b9941e316b007Michael Graffstatic void dispatch_message_real(
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff Server *s,
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff struct iovec *iovec, unsigned n, unsigned m,
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff const struct ucred *ucred,
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff const struct timeval *tv,
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff const char *label, size_t label_len,
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff const char *unit_id,
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff int priority,
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff pid_t object_pid) {
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff char pid[sizeof("_PID=") + DECIMAL_STR_MAX(pid_t)],
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff uid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)],
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff gid[sizeof("_GID=") + DECIMAL_STR_MAX(gid_t)],
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff owner_uid[sizeof("_SYSTEMD_OWNER_UID=") + DECIMAL_STR_MAX(uid_t)],
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)],
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff o_uid[sizeof("OBJECT_UID=") + DECIMAL_STR_MAX(uid_t)],
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff o_gid[sizeof("OBJECT_GID=") + DECIMAL_STR_MAX(gid_t)],
3c5148c4d98af51d6dcb449c6dbd45fe8c645f61Michael Graff o_owner_uid[sizeof("OBJECT_SYSTEMD_OWNER_UID=") + DECIMAL_STR_MAX(uid_t)];
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff uid_t object_uid;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff gid_t object_gid;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff char *x;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff int r;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff char *t, *c;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff uid_t realuid = 0, owner = 0, journal_uid;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff bool owner_valid = false;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#ifdef HAVE_AUDIT
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff char audit_session[sizeof("_AUDIT_SESSION=") + DECIMAL_STR_MAX(uint32_t)],
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff audit_loginuid[sizeof("_AUDIT_LOGINUID=") + DECIMAL_STR_MAX(uid_t)],
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff o_audit_session[sizeof("OBJECT_AUDIT_SESSION=") + DECIMAL_STR_MAX(uint32_t)],
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff o_audit_loginuid[sizeof("OBJECT_AUDIT_LOGINUID=") + DECIMAL_STR_MAX(uid_t)];
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff uint32_t audit;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff uid_t loginuid;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#endif
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(s);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(iovec);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(n > 0);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff assert(n + N_IOVEC_META_FIELDS + (object_pid ? N_IOVEC_OBJECT_FIELDS : 0) <= m);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (ucred) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff realuid = ucred->uid;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sprintf(pid, "_PID="PID_FMT, ucred->pid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], pid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sprintf(uid, "_UID="UID_FMT, ucred->uid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], uid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sprintf(gid, "_GID="GID_FMT, ucred->gid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], gid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = get_process_comm(ucred->pid, &t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_COMM=", t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff free(t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = get_process_exe(ucred->pid, &t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_EXE=", t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff free(t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = get_process_cmdline(ucred->pid, 0, false, &t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_CMDLINE=", t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff free(t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = get_process_capeff(ucred->pid, &t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_CAP_EFFECTIVE=", t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff free(t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#ifdef HAVE_AUDIT
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = audit_session_from_pid(ucred->pid, &audit);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sprintf(audit_session, "_AUDIT_SESSION=%"PRIu32, audit);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], audit_session);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = audit_loginuid_from_pid(ucred->pid, &loginuid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sprintf(audit_loginuid, "_AUDIT_LOGINUID="UID_FMT, loginuid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], audit_loginuid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff#endif
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = cg_pid_get_path_shifted(ucred->pid, s->cgroup_root, &c);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff char *session = NULL;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_SYSTEMD_CGROUP=", c);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff r = cg_path_get_session(c, &t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (r >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff session = strappenda("_SYSTEMD_SESSION=", t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff free(t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], session);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (cg_path_get_owner_uid(c, &owner) >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff owner_valid = true;
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff sprintf(owner_uid, "_SYSTEMD_OWNER_UID="UID_FMT, owner);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], owner_uid);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (cg_path_get_unit(c, &t) >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_SYSTEMD_UNIT=", t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff free(t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff } else if (unit_id && !session) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_SYSTEMD_UNIT=", unit_id);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (cg_path_get_user_unit(c, &t) >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_SYSTEMD_USER_UNIT=", t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff free(t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff } else if (unit_id && session) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_SYSTEMD_USER_UNIT=", unit_id);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff if (cg_path_get_slice(c, &t) >= 0) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_SYSTEMD_SLICE=", t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff free(t);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff free(c);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff } else if (unit_id) {
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff x = strappenda("_SYSTEMD_UNIT=", unit_id);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff IOVEC_SET_STRING(iovec[n++], x);
ad3a5c4b7e21af04d1b872f933c2e19e5c0a135bMichael Graff }
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff#ifdef HAVE_SELINUX
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff if (mac_selinux_use()) {
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff if (label) {
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff x = alloca(strlen("_SELINUX_CONTEXT=") + label_len + 1);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff *((char*) mempcpy(stpcpy(x, "_SELINUX_CONTEXT="), label, label_len)) = 0;
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff IOVEC_SET_STRING(iovec[n++], x);
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff } else {
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff security_context_t con;
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff if (getpidcon(ucred->pid, &con) >= 0) {
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff x = strappenda("_SELINUX_CONTEXT=", con);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff freecon(con);
11fcc67616fac1bc6a28b3d4fed24641137888e7Michael Graff IOVEC_SET_STRING(iovec[n++], x);
66bd3b3c6b171271c705b897823dcdcf29464698Michael Graff }
}
}
#endif
}
assert(n <= m);
if (object_pid) {
r = get_process_uid(object_pid, &object_uid);
if (r >= 0) {
sprintf(o_uid, "OBJECT_UID="UID_FMT, object_uid);
IOVEC_SET_STRING(iovec[n++], o_uid);
}
r = get_process_gid(object_pid, &object_gid);
if (r >= 0) {
sprintf(o_gid, "OBJECT_GID="GID_FMT, object_gid);
IOVEC_SET_STRING(iovec[n++], o_gid);
}
r = get_process_comm(object_pid, &t);
if (r >= 0) {
x = strappenda("OBJECT_COMM=", t);
free(t);
IOVEC_SET_STRING(iovec[n++], x);
}
r = get_process_exe(object_pid, &t);
if (r >= 0) {
x = strappenda("OBJECT_EXE=", t);
free(t);
IOVEC_SET_STRING(iovec[n++], x);
}
r = get_process_cmdline(object_pid, 0, false, &t);
if (r >= 0) {
x = strappenda("OBJECT_CMDLINE=", t);
free(t);
IOVEC_SET_STRING(iovec[n++], x);
}
#ifdef HAVE_AUDIT
r = audit_session_from_pid(object_pid, &audit);
if (r >= 0) {
sprintf(o_audit_session, "OBJECT_AUDIT_SESSION=%"PRIu32, audit);
IOVEC_SET_STRING(iovec[n++], o_audit_session);
}
r = audit_loginuid_from_pid(object_pid, &loginuid);
if (r >= 0) {
sprintf(o_audit_loginuid, "OBJECT_AUDIT_LOGINUID="UID_FMT, loginuid);
IOVEC_SET_STRING(iovec[n++], o_audit_loginuid);
}
#endif
r = cg_pid_get_path_shifted(object_pid, s->cgroup_root, &c);
if (r >= 0) {
x = strappenda("OBJECT_SYSTEMD_CGROUP=", c);
IOVEC_SET_STRING(iovec[n++], x);
r = cg_path_get_session(c, &t);
if (r >= 0) {
x = strappenda("OBJECT_SYSTEMD_SESSION=", t);
free(t);
IOVEC_SET_STRING(iovec[n++], x);
}
if (cg_path_get_owner_uid(c, &owner) >= 0) {
sprintf(o_owner_uid, "OBJECT_SYSTEMD_OWNER_UID="UID_FMT, owner);
IOVEC_SET_STRING(iovec[n++], o_owner_uid);
}
if (cg_path_get_unit(c, &t) >= 0) {
x = strappenda("OBJECT_SYSTEMD_UNIT=", t);
free(t);
IOVEC_SET_STRING(iovec[n++], x);
}
if (cg_path_get_user_unit(c, &t) >= 0) {
x = strappenda("OBJECT_SYSTEMD_USER_UNIT=", t);
free(t);
IOVEC_SET_STRING(iovec[n++], x);
}
free(c);
}
}
assert(n <= m);
if (tv) {
sprintf(source_time, "_SOURCE_REALTIME_TIMESTAMP=%llu", (unsigned long long) timeval_load(tv));
IOVEC_SET_STRING(iovec[n++], source_time);
}
/* 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. */
if (!isempty(s->boot_id_field))
IOVEC_SET_STRING(iovec[n++], s->boot_id_field);
if (!isempty(s->machine_id_field))
IOVEC_SET_STRING(iovec[n++], s->machine_id_field);
if (!isempty(s->hostname_field))
IOVEC_SET_STRING(iovec[n++], s->hostname_field);
assert(n <= m);
if (s->split_mode == SPLIT_UID && realuid > 0)
/* Split up strictly by any UID */
journal_uid = realuid;
else if (s->split_mode == SPLIT_LOGIN && realuid > 0 && owner_valid && owner > 0)
/* 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
* unprivileged session. */
journal_uid = owner;
else
journal_uid = 0;
write_to_journal(s, journal_uid, iovec, n, priority);
}
void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) {
char mid[11 + 32 + 1];
char buffer[16 + LINE_MAX + 1];
struct iovec iovec[N_IOVEC_META_FIELDS + 4];
int n = 0;
va_list ap;
struct ucred ucred = {};
assert(s);
assert(format);
IOVEC_SET_STRING(iovec[n++], "PRIORITY=6");
IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=driver");
memcpy(buffer, "MESSAGE=", 8);
va_start(ap, format);
vsnprintf(buffer + 8, sizeof(buffer) - 8, format, ap);
va_end(ap);
char_array_0(buffer);
IOVEC_SET_STRING(iovec[n++], buffer);
if (!sd_id128_equal(message_id, SD_ID128_NULL)) {
snprintf(mid, sizeof(mid), LOG_MESSAGE_ID(message_id));
char_array_0(mid);
IOVEC_SET_STRING(iovec[n++], mid);
}
ucred.pid = getpid();
ucred.uid = getuid();
ucred.gid = getgid();
dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL, LOG_INFO, 0);
}
void server_dispatch_message(
Server *s,
struct iovec *iovec, unsigned n, unsigned m,
const struct ucred *ucred,
const struct timeval *tv,
const char *label, size_t label_len,
const char *unit_id,
int priority,
pid_t object_pid) {
int rl, r;
_cleanup_free_ char *path = NULL;
char *c;
assert(s);
assert(iovec || n == 0);
if (n == 0)
return;
if (LOG_PRI(priority) > s->max_level_store)
return;
/* Stop early in case the information will not be stored
* in a journal. */
if (s->storage == STORAGE_NONE)
return;
if (!ucred)
goto finish;
r = cg_pid_get_path_shifted(ucred->pid, s->cgroup_root, &path);
if (r < 0)
goto finish;
/* example: /user/lennart/3/foobar
* /system/dbus.service/foobar
*
* So let's cut of everything past the third /, since that is
* where user directories start */
c = strchr(path, '/');
if (c) {
c = strchr(c+1, '/');
if (c) {
c = strchr(c+1, '/');
if (c)
*c = 0;
}
}
rl = journal_rate_limit_test(s->rate_limit, path,
priority & LOG_PRIMASK, available_space(s, false));
if (rl == 0)
return;
/* Write a suppression message if we suppressed something */
if (rl > 1)
server_driver_message(s, SD_MESSAGE_JOURNAL_DROPPED,
"Suppressed %u messages from %s", rl - 1, path);
finish:
dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, priority, object_pid);
}
static int system_journal_open(Server *s, bool flush_requested) {
int r;
char *fn;
sd_id128_t machine;
char ids[33];
r = sd_id128_get_machine(&machine);
if (r < 0)
return log_error_errno(r, "Failed to get machine id: %m");
sd_id128_to_string(machine, ids);
if (!s->system_journal &&
(s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) &&
(flush_requested
|| access("/run/systemd/journal/flushed", F_OK) >= 0)) {
/* If in auto mode: first try to create the machine
* path, but not the prefix.
*
* If in persistent mode: create /var/log/journal and
* the machine path */
if (s->storage == STORAGE_PERSISTENT)
(void) mkdir("/var/log/journal/", 0755);
fn = strappenda("/var/log/journal/", ids);
(void) mkdir(fn, 0755);
fn = strappenda(fn, "/system.journal");
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
if (r >= 0)
server_fix_perms(s, s->system_journal, 0);
else if (r < 0) {
if (r != -ENOENT && r != -EROFS)
log_warning_errno(r, "Failed to open system journal: %m");
r = 0;
}
}
if (!s->runtime_journal &&
(s->storage != STORAGE_NONE)) {
fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL);
if (!fn)
return -ENOMEM;
if (s->system_journal) {
/* Try to open the runtime journal, but only
* if it already exists, so that we can flush
* it into the system journal */
r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
free(fn);
if (r < 0) {
if (r != -ENOENT)
log_warning_errno(r, "Failed to open runtime journal: %m");
r = 0;
}
} else {
/* OK, we really need the runtime journal, so create
* it if necessary. */
(void) mkdir("/run/log", 0755);
(void) mkdir("/run/log/journal", 0755);
(void) mkdir_parents(fn, 0750);
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
free(fn);
if (r < 0)
return log_error_errno(r, "Failed to open runtime journal: %m");
}
if (s->runtime_journal)
server_fix_perms(s, s->runtime_journal, 0);
}
available_space(s, true);
return r;
}
int server_flush_to_var(Server *s) {
sd_id128_t machine;
sd_journal *j = NULL;
char ts[FORMAT_TIMESPAN_MAX];
usec_t start;
unsigned n = 0;
int r;
assert(s);
if (s->storage != STORAGE_AUTO &&
s->storage != STORAGE_PERSISTENT)
return 0;
if (!s->runtime_journal)
return 0;
system_journal_open(s, true);
if (!s->system_journal)
return 0;
log_debug("Flushing to /var...");
start = now(CLOCK_MONOTONIC);
r = sd_id128_get_machine(&machine);
if (r < 0)
return r;
r = sd_journal_open(&j, SD_JOURNAL_RUNTIME_ONLY);
if (r < 0)
return log_error_errno(r, "Failed to read runtime journal: %m");
sd_journal_set_data_threshold(j, 0);
SD_JOURNAL_FOREACH(j) {
Object *o = NULL;
JournalFile *f;
f = j->current_file;
assert(f && f->current_offset > 0);
n++;
r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
if (r < 0) {
log_error_errno(r, "Can't read entry: %m");
goto finish;
}
r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL);
if (r >= 0)
continue;
if (!shall_try_append_again(s->system_journal, r)) {
log_error_errno(r, "Can't write entry: %m");
goto finish;
}
server_rotate(s);
server_vacuum(s);
if (!s->system_journal) {
log_notice("Didn't flush runtime journal since rotation of system journal wasn't successful.");
r = -EIO;
goto finish;
}
log_debug("Retrying write.");
r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL);
if (r < 0) {
log_error_errno(r, "Can't write entry: %m");
goto finish;
}
}
finish:
journal_file_post_change(s->system_journal);
journal_file_close(s->runtime_journal);
s->runtime_journal = NULL;
if (r >= 0)
rm_rf("/run/log/journal", false, true, false);
sd_journal_close(j);
server_driver_message(s, SD_ID128_NULL, "Time spent on flushing to /var is %s for %u entries.", format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0), n);
return r;
}
int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
Server *s = userdata;
assert(s);
assert(fd == s->native_fd || fd == s->syslog_fd || fd == s->audit_fd);
if (revents != EPOLLIN) {
log_error("Got invalid event from epoll for datagram fd: %"PRIx32, revents);
return -EIO;
}
for (;;) {
struct ucred *ucred = NULL;
struct timeval *tv = NULL;
struct cmsghdr *cmsg;
char *label = NULL;
size_t label_len = 0;
struct iovec iovec;
union {
struct cmsghdr cmsghdr;
/* 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. */
uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
CMSG_SPACE(sizeof(struct timeval)) +
CMSG_SPACE(sizeof(int)) + /* fd */
CMSG_SPACE(NAME_MAX)]; /* selinux label */
} control = {};
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),
};
ssize_t n;
int *fds = NULL;
unsigned n_fds = 0;
int v = 0;
size_t m;
/* Try to get the right size, if we can. (Not all
* sockets support SIOCINQ, hence we just try, but
* don't rely on it. */
(void) ioctl(fd, SIOCINQ, &v);
/* 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);
if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m))
return log_oom();
iovec.iov_base = s->buffer;
iovec.iov_len = s->buffer_size - 1; /* Leave room for trailing NUL we add later */
n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
if (errno == EINTR || errno == EAGAIN)
return 0;
log_error_errno(errno, "recvmsg() failed: %m");
return -errno;
}
if (n == 0) {
log_error("Got EOF on socket.");
return -ECONNRESET;
}
for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
ucred = (struct ucred*) CMSG_DATA(cmsg);
else if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_SECURITY) {
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 &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
tv = (struct timeval*) CMSG_DATA(cmsg);
else if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS) {
fds = (int*) CMSG_DATA(cmsg);
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
}
}
/* And a trailing NUL, just in case */
s->buffer[n] = 0;
if (fd == s->syslog_fd) {
if (n > 0 && n_fds == 0)
server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len);
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.");
}
close_many(fds, n_fds);
}
}
static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
Server *s = userdata;
assert(s);
log_info("Received request to flush runtime journal from PID %"PRIu32, si->ssi_pid);
server_flush_to_var(s);
server_sync(s);
server_vacuum(s);
touch("/run/systemd/journal/flushed");
return 0;
}
static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
Server *s = userdata;
assert(s);
log_info("Received request to rotate journal from PID %"PRIu32, si->ssi_pid);
server_rotate(s);
server_vacuum(s);
return 0;
}
static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
Server *s = userdata;
assert(s);
log_received_signal(LOG_INFO, si);
sd_event_exit(s->event, 0);
return 0;
}
static int setup_signals(Server *s) {
sigset_t mask;
int r;
assert(s);
assert_se(sigemptyset(&mask) == 0);
sigset_add_many(&mask, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, -1);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s);
if (r < 0)
return r;
r = sd_event_add_signal(s->event, &s->sigusr2_event_source, SIGUSR2, dispatch_sigusr2, s);
if (r < 0)
return r;
r = sd_event_add_signal(s->event, &s->sigterm_event_source, SIGTERM, dispatch_sigterm, s);
if (r < 0)
return r;
r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s);
if (r < 0)
return r;
return 0;
}
static int server_parse_proc_cmdline(Server *s) {
_cleanup_free_ char *line = NULL;
const char *w, *state;
size_t l;
int r;
r = proc_cmdline(&line);
if (r < 0) {
log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m");
return 0;
}
FOREACH_WORD_QUOTED(w, l, line, state) {
_cleanup_free_ char *word;
word = strndup(w, l);
if (!word)
return -ENOMEM;
if (startswith(word, "systemd.journald.forward_to_syslog=")) {
r = parse_boolean(word + 35);
if (r < 0)
log_warning("Failed to parse forward to syslog switch %s. Ignoring.", word + 35);
else
s->forward_to_syslog = r;
} else if (startswith(word, "systemd.journald.forward_to_kmsg=")) {
r = parse_boolean(word + 33);
if (r < 0)
log_warning("Failed to parse forward to kmsg switch %s. Ignoring.", word + 33);
else
s->forward_to_kmsg = r;
} else if (startswith(word, "systemd.journald.forward_to_console=")) {
r = parse_boolean(word + 36);
if (r < 0)
log_warning("Failed to parse forward to console switch %s. Ignoring.", word + 36);
else
s->forward_to_console = r;
} else if (startswith(word, "systemd.journald.forward_to_wall=")) {
r = parse_boolean(word + 33);
if (r < 0)
log_warning("Failed to parse forward to wall switch %s. Ignoring.", word + 33);
else
s->forward_to_wall = r;
} else if (startswith(word, "systemd.journald"))
log_warning("Invalid systemd.journald parameter. Ignoring.");
}
/* do not warn about state here, since probably systemd already did */
return 0;
}
static int server_parse_config_file(Server *s) {
assert(s);
return config_parse_many("/etc/systemd/journald.conf",
CONF_DIRS_NULSTR("systemd/journald.conf"),
"Journal\0",
config_item_perf_lookup, journald_gperf_lookup,
false, s);
}
static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) {
Server *s = userdata;
assert(s);
server_sync(s);
return 0;
}
int server_schedule_sync(Server *s, int priority) {
int r;
assert(s);
if (priority <= LOG_CRIT) {
/* Immediately sync to disk when this is of priority CRIT, ALERT, EMERG */
server_sync(s);
return 0;
}
if (s->sync_scheduled)
return 0;
if (s->sync_interval_usec > 0) {
usec_t when;
r = sd_event_now(s->event, CLOCK_MONOTONIC, &when);
if (r < 0)
return r;
when += s->sync_interval_usec;
if (!s->sync_event_source) {
r = sd_event_add_time(
s->event,
&s->sync_event_source,
CLOCK_MONOTONIC,
when, 0,
server_dispatch_sync, s);
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);
}
if (r < 0)
return r;
s->sync_scheduled = true;
}
return 0;
}
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);
s->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
if (s->hostname_fd < 0)
return log_error_errno(errno, "Failed to open /proc/sys/kernel/hostname: %m");
r = sd_event_add_io(s->event, &s->hostname_event_source, s->hostname_fd, 0, dispatch_hostname_change, s);
if (r < 0) {
/* kernels prior to 3.2 don't support polling this file. Ignore
* the failure. */
if (r == -EPERM) {
log_warning("Failed to register hostname fd in event loop: %s. Ignoring.",
strerror(-r));
s->hostname_fd = safe_close(s->hostname_fd);
return 0;
}
return log_error_errno(r, "Failed to register hostname fd in event loop: %m");
}
r = sd_event_source_set_priority(s->hostname_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
if (r < 0)
return log_error_errno(r, "Failed to adjust priority of host name event source: %m");
return 0;
}
int server_init(Server *s) {
_cleanup_fdset_free_ FDSet *fds = NULL;
int n, r, fd;
assert(s);
zero(*s);
s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = -1;
s->compress = true;
s->seal = true;
s->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC;
s->sync_scheduled = false;
s->rate_limit_interval = DEFAULT_RATE_LIMIT_INTERVAL;
s->rate_limit_burst = DEFAULT_RATE_LIMIT_BURST;
s->forward_to_wall = true;
s->max_file_usec = DEFAULT_MAX_FILE_USEC;
s->max_level_store = LOG_DEBUG;
s->max_level_syslog = LOG_DEBUG;
s->max_level_kmsg = LOG_NOTICE;
s->max_level_console = LOG_INFO;
s->max_level_wall = LOG_EMERG;
memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics));
memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics));
server_parse_config_file(s);
server_parse_proc_cmdline(s);
if (!!s->rate_limit_interval ^ !!s->rate_limit_burst) {
log_debug("Setting both rate limit interval and burst from "USEC_FMT",%u to 0,0",
s->rate_limit_interval, s->rate_limit_burst);
s->rate_limit_interval = s->rate_limit_burst = 0;
}
mkdir_p("/run/systemd/journal", 0755);
s->user_journals = ordered_hashmap_new(NULL);
if (!s->user_journals)
return log_oom();
s->mmap = mmap_cache_new();
if (!s->mmap)
return log_oom();
r = sd_event_default(&s->event);
if (r < 0)
return log_error_errno(r, "Failed to create event loop: %m");
sd_event_set_watchdog(s->event, true);
n = sd_listen_fds(true);
if (n < 0)
return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/run/systemd/journal/socket", 0) > 0) {
if (s->native_fd >= 0) {
log_error("Too many native sockets passed.");
return -EINVAL;
}
s->native_fd = fd;
} else if (sd_is_socket_unix(fd, SOCK_STREAM, 1, "/run/systemd/journal/stdout", 0) > 0) {
if (s->stdout_fd >= 0) {
log_error("Too many stdout sockets passed.");
return -EINVAL;
}
s->stdout_fd = fd;
} else if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/dev/log", 0) > 0 ||
sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/run/systemd/journal/dev-log", 0) > 0) {
if (s->syslog_fd >= 0) {
log_error("Too many /dev/log sockets passed.");
return -EINVAL;
}
s->syslog_fd = fd;
} else if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
if (s->audit_fd >= 0) {
log_error("Too many audit sockets passed.");
return -EINVAL;
}
s->audit_fd = fd;
} else {
if (!fds) {
fds = fdset_new();
if (!fds)
return log_oom();
}
r = fdset_put(fds, fd);
if (r < 0)
return log_oom();
}
}
r = server_open_stdout_socket(s, fds);
if (r < 0)
return r;
if (fdset_size(fds) > 0) {
log_warning("%u unknown file descriptors passed, closing.", fdset_size(fds));
fds = fdset_free(fds);
}
r = server_open_syslog_socket(s);
if (r < 0)
return r;
r = server_open_native_socket(s);
if (r < 0)
return r;
r = server_open_dev_kmsg(s);
if (r < 0)
return r;
r = server_open_audit(s);
if (r < 0)
return r;
r = server_open_kernel_seqnum(s);
if (r < 0)
return r;
r = server_open_hostname(s);
if (r < 0)
return r;
r = setup_signals(s);
if (r < 0)
return r;
s->udev = udev_new();
if (!s->udev)
return -ENOMEM;
s->rate_limit = journal_rate_limit_new(s->rate_limit_interval, s->rate_limit_burst);
if (!s->rate_limit)
return -ENOMEM;
r = cg_get_root_path(&s->cgroup_root);
if (r < 0)
return r;
server_cache_hostname(s);
server_cache_boot_id(s);
server_cache_machine_id(s);
r = system_journal_open(s, false);
if (r < 0)
return r;
return 0;
}
void server_maybe_append_tags(Server *s) {
#ifdef HAVE_GCRYPT
JournalFile *f;
Iterator i;
usec_t n;
n = now(CLOCK_REALTIME);
if (s->system_journal)
journal_file_maybe_append_tag(s->system_journal, n);
ORDERED_HASHMAP_FOREACH(f, s->user_journals, i)
journal_file_maybe_append_tag(f, n);
#endif
}
void server_done(Server *s) {
JournalFile *f;
assert(s);
while (s->stdout_streams)
stdout_stream_free(s->stdout_streams);
if (s->system_journal)
journal_file_close(s->system_journal);
if (s->runtime_journal)
journal_file_close(s->runtime_journal);
while ((f = ordered_hashmap_steal_first(s->user_journals)))
journal_file_close(f);
ordered_hashmap_free(s->user_journals);
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);
sd_event_source_unref(s->audit_event_source);
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);
sd_event_source_unref(s->hostname_event_source);
sd_event_unref(s->event);
safe_close(s->syslog_fd);
safe_close(s->native_fd);
safe_close(s->stdout_fd);
safe_close(s->dev_kmsg_fd);
safe_close(s->audit_fd);
safe_close(s->hostname_fd);
if (s->rate_limit)
journal_rate_limit_free(s->rate_limit);
if (s->kernel_seqnum)
munmap(s->kernel_seqnum, sizeof(uint64_t));
free(s->buffer);
free(s->tty_path);
free(s->cgroup_root);
free(s->hostname_field);
if (s->mmap)
mmap_cache_unref(s->mmap);
if (s->udev)
udev_unref(s->udev);
}