journald.c revision 66a78c2b95ba6cc0be15dab68c5af816fb5b7a33
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering/***
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering This file is part of systemd.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering Copyright 2011 Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering systemd is free software; you can redistribute it and/or modify it
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering under the terms of the GNU Lesser General Public License as published by
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering (at your option) any later version.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering systemd is distributed in the hope that it will be useful, but
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering Lesser General Public License for more details.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering You should have received a copy of the GNU Lesser General Public License
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering***/
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <sys/epoll.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <sys/socket.h>
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering#include <errno.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <sys/signalfd.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <unistd.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <fcntl.h>
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen#include <stddef.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <sys/ioctl.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <linux/sockios.h>
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen#include <sys/statvfs.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <systemd/sd-journal.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <systemd/sd-messages.h>
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani#include <systemd/sd-daemon.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#ifdef HAVE_LOGIND
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen#include <systemd/sd-login.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#endif
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
db73295accbec0c6513817f0a64a92018592bb26Lennart Poettering#include "mkdir.h"
d8500c53789eafefe28d4ace088bf4b912280bf9Tom Gundersen#include "hashmap.h"
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen#include "journal-file.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "socket-util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "cgroup-util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "list.h"
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering#include "journal-rate-limit.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "journal-internal.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "conf-parser.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "journald.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "virt.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "missing.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#ifdef HAVE_ACL
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <sys/acl.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <acl/libacl.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "acl-util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#endif
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#ifdef HAVE_SELINUX
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <selinux/selinux.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#endif
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#define USER_JOURNALS_MAX 1024
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#define STDOUT_STREAMS_MAX 4096
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#define DEFAULT_RATE_LIMIT_INTERVAL (10*USEC_PER_SEC)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#define DEFAULT_RATE_LIMIT_BURST 200
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#define RECHECK_VAR_AVAILABLE_USEC (30*USEC_PER_SEC)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#define N_IOVEC_META_FIELDS 17
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#define ENTRY_SIZE_MAX (1024*1024*32)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringtypedef enum StdoutStreamState {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering STDOUT_STREAM_IDENTIFIER,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering STDOUT_STREAM_UNIT_ID,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering STDOUT_STREAM_PRIORITY,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering STDOUT_STREAM_LEVEL_PREFIX,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering STDOUT_STREAM_FORWARD_TO_SYSLOG,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering STDOUT_STREAM_FORWARD_TO_KMSG,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering STDOUT_STREAM_FORWARD_TO_CONSOLE,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering STDOUT_STREAM_RUNNING
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering} StdoutStreamState;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstruct StdoutStream {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering Server *server;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering StdoutStreamState state;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int fd;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering struct ucred ucred;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#ifdef HAVE_SELINUX
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering security_context_t security_context;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#endif
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering char *identifier;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering char *unit_id;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering int priority;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering bool level_prefix:1;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering bool forward_to_syslog:1;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering bool forward_to_kmsg:1;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering bool forward_to_console:1;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering char buffer[LINE_MAX+1];
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering size_t length;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering LIST_FIELDS(StdoutStream, stdout_stream);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering};
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poetteringstatic int server_flush_to_var(Server *s);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poetteringstatic uint64_t available_space(Server *s) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering char ids[33], *p;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering const char *f;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering sd_id128_t machine;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering struct statvfs ss;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering uint64_t sum = 0, avail = 0, ss_avail = 0;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering int r;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering DIR *d;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering usec_t ts;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering JournalMetrics *m;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering ts = now(CLOCK_MONOTONIC);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return s->cached_available_space;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = sd_id128_get_machine(&machine);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (r < 0)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return 0;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (s->system_journal) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering f = "/var/log/journal/";
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering m = &s->system_metrics;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering } else {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering f = "/run/log/journal/";
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering m = &s->runtime_metrics;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering }
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering assert(m);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering p = strappend(f, sd_id128_to_string(machine, ids));
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (!p)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return 0;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering d = opendir(p);
a6a4f528899b1dab47408733b4a423c66ea40f7aThomas Hindoe Paaboel Andersen free(p);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (!d)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return 0;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (fstatvfs(dirfd(d), &ss) < 0)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering goto finish;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering for (;;) {
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering struct stat st;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering struct dirent buf, *de;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering r = readdir_r(d, &buf, &de);
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering if (r != 0)
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering break;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering if (!de)
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering break;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering if (!endswith(de->d_name, ".journal") &&
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering !endswith(de->d_name, ".journal~"))
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering continue;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering continue;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering if (!S_ISREG(st.st_mode))
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering continue;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering sum += (uint64_t) st.st_blocks * 512UL;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering }
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering avail = sum >= m->max_use ? 0 : m->max_use - sum;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering ss_avail = ss.f_bsize * ss.f_bavail;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering ss_avail = ss_avail < m->keep_free ? 0 : ss_avail - m->keep_free;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering if (ss_avail < avail)
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen avail = ss_avail;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering s->cached_available_space = avail;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering s->cached_available_space_timestamp = ts;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poetteringfinish:
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering closedir(d);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return avail;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidtstatic void server_read_file_gid(Server *s) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *adm = "adm";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int r;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt assert(s);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (s->file_gid_valid)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = get_group_creds(&adm, &s->file_gid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_warning("Failed to resolve 'adm' group: %s", strerror(-r));
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* if we couldn't read the gid, then it will be 0, but that's
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * fine and we shouldn't try to resolve the group again, so
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt * let's just pretend it worked right-away. */
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt s->file_gid_valid = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
3e3db0ee860025ad663b13b0ace4e6d627611332Lennart Poetteringstatic void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int r;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering#ifdef HAVE_ACL
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering acl_t acl;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering acl_entry_t entry;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering acl_permset_t permset;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering#endif
ab1525bc2d92780b4dc64bc5b9cdb52594e2df7dLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(f);
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering server_read_file_gid(s);
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = fchmod_and_fchown(f->fd, 0640, 0, s->file_gid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0)
d6731e4c7964ee2860d4f5abdb0b52acd7a66960Tom Gundersen log_warning("Failed to fix access mode/rights on %s, ignoring: %s", f->path, strerror(-r));
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering#ifdef HAVE_ACL
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering if (uid <= 0)
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering return;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering acl = acl_get_fd(f->fd);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!acl) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_warning("Failed to read ACL on %s, ignoring: %m", f->path);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
3e3db0ee860025ad663b13b0ace4e6d627611332Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering r = acl_find_uid(acl, uid, &entry);
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering if (r <= 0) {
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (acl_create_entry(&acl, &entry) < 0 ||
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering acl_set_tag_type(entry, ACL_USER) < 0 ||
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering acl_set_qualifier(entry, &uid) < 0) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering goto finish;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (acl_get_permset(entry, &permset) < 0 ||
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen acl_add_perm(permset, ACL_READ) < 0 ||
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen acl_calc_mask(&acl) < 0) {
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen goto finish;
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen }
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (acl_set_fd(f->fd, acl) < 0)
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering log_warning("Failed to set ACL on %s, ignoring: %m", f->path);
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering
888943fc6246b2917168fff59380b58b678ba157Lennart Poetteringfinish:
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen acl_free(acl);
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen#endif
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen}
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersenstatic JournalFile* find_journal(Server *s, uid_t uid) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen char *p;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen int r;
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen JournalFile *f;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen char ids[33];
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen sd_id128_t machine;
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen assert(s);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen /* We split up user logs only on /var, not on /run. If the
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen * runtime file is open, we write to it exclusively, in order
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen * to guarantee proper order as soon as we flush /run to
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen * /var and close the runtime file. */
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen if (s->runtime_journal)
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen return s->runtime_journal;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (uid <= 0)
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering return s->system_journal;
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen r = sd_id128_get_machine(&machine);
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering if (r < 0)
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering return s->system_journal;
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering f = hashmap_get(s->user_journals, UINT32_TO_PTR(uid));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (f)
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen return f;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (asprintf(&p, "/var/log/journal/%s/user-%lu.journal", sd_id128_to_string(machine, ids), (unsigned long) uid) < 0)
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen return s->system_journal;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen while (hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen /* Too many open? Then let's close one */
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen f = hashmap_steal_first(s->user_journals);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen assert(f);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen journal_file_close(f);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen }
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->system_journal, &f);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen free(p);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (r < 0)
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen return s->system_journal;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen server_fix_perms(s, f, uid);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (r < 0) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen journal_file_close(f);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen return s->system_journal;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen }
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen return f;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen}
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersenstatic void server_rotate(Server *s) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen JournalFile *f;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen void *k;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen Iterator i;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen int r;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_info("Rotating...");
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (s->runtime_journal) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = journal_file_rotate(&s->runtime_journal);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (r < 0)
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (s->runtime_journal)
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_error("Failed to rotate %s: %s", s->runtime_journal->path, strerror(-r));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen else
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_error("Failed to create new runtime journal: %s", strerror(-r));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen else
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen server_fix_perms(s, s->runtime_journal, 0);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen }
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (s->system_journal) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = journal_file_rotate(&s->system_journal);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (r < 0)
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (s->system_journal)
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_error("Failed to rotate %s: %s", s->system_journal->path, strerror(-r));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen else
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_error("Failed to create new system journal: %s", strerror(-r));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen else
144232a8e0ea77eed8c5a456832758681b5b3511Torstein Husebø server_fix_perms(s, s->system_journal, 0);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen }
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = journal_file_rotate(&f);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (r < 0)
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (f->path)
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_error("Failed to rotate %s: %s", f->path, strerror(-r));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen else
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_error("Failed to create user journal: %s", strerror(-r));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen else {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen hashmap_replace(s->user_journals, k, f);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen server_fix_perms(s, s->system_journal, PTR_TO_UINT32(k));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen }
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen }
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen}
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersenstatic void server_vacuum(Server *s) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen char *p;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen char ids[33];
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen sd_id128_t machine;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen int r;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_info("Vacuuming...");
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = sd_id128_get_machine(&machine);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (r < 0) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_error("Failed to get machine ID: %s", strerror(-r));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen return;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen }
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen sd_id128_to_string(machine, ids);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (s->system_journal) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (asprintf(&p, "/var/log/journal/%s", ids) < 0) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_error("Out of memory.");
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen return;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen }
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (r < 0 && r != -ENOENT)
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering log_error("Failed to vacuum %s: %s", p, strerror(-r));
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering free(p);
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen }
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen if (s->runtime_journal) {
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen if (asprintf(&p, "/run/log/journal/%s", ids) < 0) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_error("Out of memory.");
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen return;
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen }
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free);
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen if (r < 0 && r != -ENOENT)
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen log_error("Failed to vacuum %s: %s", p, strerror(-r));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen free(p);
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen }
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen s->cached_available_space_timestamp = 0;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen}
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersenstatic char *shortened_cgroup_path(pid_t pid) {
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen int r;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen char *process_path, *init_path, *path;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering assert(pid > 0);
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &process_path);
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering if (r < 0)
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen return NULL;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &init_path);
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering if (r < 0) {
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering free(process_path);
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering return NULL;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering }
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering if (endswith(init_path, "/system"))
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering init_path[strlen(init_path) - 7] = 0;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering else if (streq(init_path, "/"))
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering init_path[0] = 0;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering if (startswith(process_path, init_path)) {
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering char *p;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen p = strdup(process_path + strlen(init_path));
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (!p) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen free(process_path);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen free(init_path);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen return NULL;
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering }
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering path = p;
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering } else {
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering path = process_path;
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering process_path = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(process_path);
1d050e1e0a7082e23ee9b31fa0b819cb332b3444Lennart Poettering free(init_path);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return path;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic void dispatch_message_real(
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering Server *s,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering struct iovec *iovec, unsigned n, unsigned m,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering struct ucred *ucred,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering struct timeval *tv,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *label, size_t label_len,
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering const char *unit_id) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char *pid = NULL, *uid = NULL, *gid = NULL,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *source_time = NULL, *boot_id = NULL, *machine_id = NULL,
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering *comm = NULL, *cmdline = NULL, *hostname = NULL,
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering *audit_session = NULL, *audit_loginuid = NULL,
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering *exe = NULL, *cgroup = NULL, *session = NULL,
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering *owner_uid = NULL, *unit = NULL, *selinux_context = NULL;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering char idbuf[33];
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering sd_id128_t id;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering int r;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering char *t;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering uid_t loginuid = 0, realuid = 0;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering JournalFile *f;
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering bool vacuumed = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(s);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(iovec);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(n > 0);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(n + N_IOVEC_META_FIELDS <= m);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (ucred) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering uint32_t audit;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#ifdef HAVE_LOGIND
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering uid_t owner;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#endif
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering realuid = ucred->uid;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (asprintf(&pid, "_PID=%lu", (unsigned long) ucred->pid) >= 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering IOVEC_SET_STRING(iovec[n++], pid);
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering if (asprintf(&uid, "_UID=%lu", (unsigned long) ucred->uid) >= 0)
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering IOVEC_SET_STRING(iovec[n++], uid);
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering if (asprintf(&gid, "_GID=%lu", (unsigned long) ucred->gid) >= 0)
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering IOVEC_SET_STRING(iovec[n++], gid);
2301cb9fdb774d0a1b3d8f5e95c5d358721ccacbLennart Poettering
6c03d27d9f7e831194dbd8bd6bcdeef9273edb6eThomas Hindoe Paaboel Andersen r = get_process_comm(ucred->pid, &t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r >= 0) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering comm = strappend("_COMM=", t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering free(t);
373d9f173f910d547159917401c4b1f84af85736Tom Gundersen
af5effc4220dab6c4c87a130bae7be441f6967caTom Gundersen if (comm)
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering IOVEC_SET_STRING(iovec[n++], comm);
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = get_process_exe(ucred->pid, &t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r >= 0) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering exe = strappend("_EXE=", t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering free(t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (exe)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering IOVEC_SET_STRING(iovec[n++], exe);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = get_process_cmdline(ucred->pid, LINE_MAX, false, &t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r >= 0) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering cmdline = strappend("_CMDLINE=", t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering free(t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (cmdline)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering IOVEC_SET_STRING(iovec[n++], cmdline);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = audit_session_from_pid(ucred->pid, &audit);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r >= 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (asprintf(&audit_session, "_AUDIT_SESSION=%lu", (unsigned long) audit) >= 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering IOVEC_SET_STRING(iovec[n++], audit_session);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt r = audit_loginuid_from_pid(ucred->pid, &loginuid);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (r >= 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (asprintf(&audit_loginuid, "_AUDIT_LOGINUID=%lu", (unsigned long) loginuid) >= 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering IOVEC_SET_STRING(iovec[n++], audit_loginuid);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering t = shortened_cgroup_path(ucred->pid);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (t) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering cgroup = strappend("_SYSTEMD_CGROUP=", t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering free(t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (cgroup)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering IOVEC_SET_STRING(iovec[n++], cgroup);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering#ifdef HAVE_LOGIND
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (sd_pid_get_session(ucred->pid, &t) >= 0) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering session = strappend("_SYSTEMD_SESSION=", t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering free(t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (session)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering IOVEC_SET_STRING(iovec[n++], session);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (sd_pid_get_owner_uid(ucred->uid, &owner) >= 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (asprintf(&owner_uid, "_SYSTEMD_OWNER_UID=%lu", (unsigned long) owner) >= 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering IOVEC_SET_STRING(iovec[n++], owner_uid);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering#endif
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (cg_pid_get_unit(ucred->pid, &t) >= 0) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering unit = strappend("_SYSTEMD_UNIT=", t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering free(t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering } else if (unit_id)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering unit = strappend("_SYSTEMD_UNIT=", unit_id);
d6731e4c7964ee2860d4f5abdb0b52acd7a66960Tom Gundersen
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering if (unit)
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering IOVEC_SET_STRING(iovec[n++], unit);
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering#ifdef HAVE_SELINUX
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (label) {
d6731e4c7964ee2860d4f5abdb0b52acd7a66960Tom Gundersen selinux_context = malloc(sizeof("_SELINUX_CONTEXT=") + label_len);
d6731e4c7964ee2860d4f5abdb0b52acd7a66960Tom Gundersen if (selinux_context) {
2301cb9fdb774d0a1b3d8f5e95c5d358721ccacbLennart Poettering memcpy(selinux_context, "_SELINUX_CONTEXT=", sizeof("_SELINUX_CONTEXT=")-1);
67272d157a35e5cda4e5c904eafdcc23d20541d1Tom Gundersen memcpy(selinux_context+sizeof("_SELINUX_CONTEXT=")-1, label, label_len);
67272d157a35e5cda4e5c904eafdcc23d20541d1Tom Gundersen selinux_context[sizeof("_SELINUX_CONTEXT=")-1+label_len] = 0;
67272d157a35e5cda4e5c904eafdcc23d20541d1Tom Gundersen IOVEC_SET_STRING(iovec[n++], selinux_context);
67272d157a35e5cda4e5c904eafdcc23d20541d1Tom Gundersen }
67272d157a35e5cda4e5c904eafdcc23d20541d1Tom Gundersen } else {
1405434b6986d3c3d6ccaaa2e472bad843cbbfa1Lennart Poettering security_context_t con;
1405434b6986d3c3d6ccaaa2e472bad843cbbfa1Lennart Poettering
1405434b6986d3c3d6ccaaa2e472bad843cbbfa1Lennart Poettering if (getpidcon(ucred->pid, &con) >= 0) {
1405434b6986d3c3d6ccaaa2e472bad843cbbfa1Lennart Poettering selinux_context = strappend("_SELINUX_CONTEXT=", con);
1405434b6986d3c3d6ccaaa2e472bad843cbbfa1Lennart Poettering if (selinux_context)
67272d157a35e5cda4e5c904eafdcc23d20541d1Tom Gundersen IOVEC_SET_STRING(iovec[n++], selinux_context);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering freecon(con);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
af5effc4220dab6c4c87a130bae7be441f6967caTom Gundersen#endif
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (tv) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (asprintf(&source_time, "_SOURCE_REALTIME_TIMESTAMP=%llu",
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering (unsigned long long) timeval_load(tv)) >= 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering IOVEC_SET_STRING(iovec[n++], source_time);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering /* Note that strictly speaking storing the boot id here is
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering * redundant since the entry includes this in-line
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering * anyway. However, we need this indexed, too. */
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_id128_get_boot(&id);
b1acce80cd60fe95f16df2f1ad23ff2ad82d08e5Lennart Poettering if (r >= 0)
b1acce80cd60fe95f16df2f1ad23ff2ad82d08e5Lennart Poettering if (asprintf(&boot_id, "_BOOT_ID=%s", sd_id128_to_string(id, idbuf)) >= 0)
373d9f173f910d547159917401c4b1f84af85736Tom Gundersen IOVEC_SET_STRING(iovec[n++], boot_id);
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering r = sd_id128_get_machine(&id);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r >= 0)
af5effc4220dab6c4c87a130bae7be441f6967caTom Gundersen if (asprintf(&machine_id, "_MACHINE_ID=%s", sd_id128_to_string(id, idbuf)) >= 0)
af5effc4220dab6c4c87a130bae7be441f6967caTom Gundersen IOVEC_SET_STRING(iovec[n++], machine_id);
373d9f173f910d547159917401c4b1f84af85736Tom Gundersen
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering t = gethostname_malloc();
af5effc4220dab6c4c87a130bae7be441f6967caTom Gundersen if (t) {
373d9f173f910d547159917401c4b1f84af85736Tom Gundersen hostname = strappend("_HOSTNAME=", t);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering free(t);
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering if (hostname)
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering IOVEC_SET_STRING(iovec[n++], hostname);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering assert(n <= m);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering server_flush_to_var(s);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poetteringretry:
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering f = find_journal(s, realuid == 0 ? 0 : loginuid);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (!f)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering log_warning("Dropping message, as we can't find a place to store the data.");
db73295accbec0c6513817f0a64a92018592bb26Lennart Poettering else {
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL);
db73295accbec0c6513817f0a64a92018592bb26Lennart Poettering
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering if ((r == -E2BIG || /* hit limit */
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering r == -EFBIG || /* hit fs limit */
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering r == -EDQUOT || /* quota hit */
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering r == -ENOSPC || /* disk full */
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering r == -EBADMSG || /* corrupted */
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering r == -ENODATA || /* truncated */
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering r == -EHOSTDOWN || /* other machine */
db73295accbec0c6513817f0a64a92018592bb26Lennart Poettering r == -EPROTONOSUPPORT) && /* unsupported feature */
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering !vacuumed) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r == -E2BIG)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering log_info("Allocation limit reached, rotating.");
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering else
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering log_warning("Journal file corrupted, rotating.");
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering server_rotate(s);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering server_vacuum(s);
2301cb9fdb774d0a1b3d8f5e95c5d358721ccacbLennart Poettering vacuumed = true;
c627729fc49d59ffcecc09555a34d9dd139927ceLennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering log_info("Retrying write.");
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering goto retry;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering log_error("Failed to write entry, ignoring: %s", strerror(-r));
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen }
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(pid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(uid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(gid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(comm);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(exe);
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering free(cmdline);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt free(source_time);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt free(boot_id);
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering free(machine_id);
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering free(hostname);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt free(audit_session);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt free(audit_loginuid);
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering free(cgroup);
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen free(session);
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen free(owner_uid);
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen free(unit);
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering free(selinux_context);
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
c627729fc49d59ffcecc09555a34d9dd139927ceLennart Poetteringstatic void driver_message(Server *s, sd_id128_t message_id, const char *format, ...) {
e92da1e5d0a3b38804e173af136ec7a076c7757eLennart Poettering char mid[11 + 32 + 1];
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char buffer[16 + LINE_MAX + 1];
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering struct iovec iovec[N_IOVEC_META_FIELDS + 4];
e92da1e5d0a3b38804e173af136ec7a076c7757eLennart Poettering int n = 0;
5323ead145304785121b72dcbc1c244303de7575Daniel Buch va_list ap;
b1acce80cd60fe95f16df2f1ad23ff2ad82d08e5Lennart Poettering struct ucred ucred;
b1acce80cd60fe95f16df2f1ad23ff2ad82d08e5Lennart Poettering
b1acce80cd60fe95f16df2f1ad23ff2ad82d08e5Lennart Poettering assert(s);
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering assert(format);
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering IOVEC_SET_STRING(iovec[n++], "PRIORITY=5");
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=driver");
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering memcpy(buffer, "MESSAGE=", 8);
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering va_start(ap, format);
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering vsnprintf(buffer + 8, sizeof(buffer) - 8, format, ap);
c627729fc49d59ffcecc09555a34d9dd139927ceLennart Poettering va_end(ap);
c627729fc49d59ffcecc09555a34d9dd139927ceLennart Poettering char_array_0(buffer);
c627729fc49d59ffcecc09555a34d9dd139927ceLennart Poettering IOVEC_SET_STRING(iovec[n++], buffer);
c627729fc49d59ffcecc09555a34d9dd139927ceLennart Poettering
ddb7f7fc07a31937989afad53edb87b50e2cad72Zbigniew Jędrzejewski-Szmek snprintf(mid, sizeof(mid), "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(message_id));
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering char_array_0(mid);
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering IOVEC_SET_STRING(iovec[n++], mid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering zero(ucred);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ucred.pid = getpid();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ucred.uid = getuid();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ucred.gid = getgid();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poetteringstatic void dispatch_message(Server *s,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering struct iovec *iovec, unsigned n, unsigned m,
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering struct ucred *ucred,
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering struct timeval *tv,
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering const char *label, size_t label_len,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *unit_id,
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering int priority) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int rl;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char *path = NULL, *c;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(s);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt assert(iovec || n == 0);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (n == 0)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (LOG_PRI(priority) > s->max_level_store)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (!ucred)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering goto finish;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering path = shortened_cgroup_path(ucred->pid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!path)
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering goto finish;
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen /* example: /user/lennart/3/foobar
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering * /system/dbus.service/foobar
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering * So let's cut of everything past the third /, since that is
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering * wher user directories start */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering c = strchr(path, '/');
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (c) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering c = strchr(c+1, '/');
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (c) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani c = strchr(c+1, '/');
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (c)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani *c = 0;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani rl = journal_rate_limit_test(s->rate_limit, path, priority & LOG_PRIMASK, available_space(s));
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (rl == 0) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani free(path);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* Write a suppression message if we suppressed something */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (rl > 1)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani driver_message(s, SD_MESSAGE_JOURNAL_DROPPED, "Suppressed %u messages from %s", rl - 1, path);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani free(path);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahanifinish:
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani}
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahanistatic void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani struct msghdr msghdr;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani struct cmsghdr *cmsg;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani union {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani struct cmsghdr cmsghdr;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani } control;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani union sockaddr_union sa;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(s);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(iovec);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(n_iovec > 0);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani zero(msghdr);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani msghdr.msg_iov = (struct iovec*) iovec;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani msghdr.msg_iovlen = n_iovec;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani zero(sa);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani sa.un.sun_family = AF_UNIX;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani strncpy(sa.un.sun_path, "/run/systemd/journal/syslog", sizeof(sa.un.sun_path));
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani msghdr.msg_name = &sa;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani msghdr.msg_namelen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (ucred) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani zero(control);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani msghdr.msg_control = &control;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani msghdr.msg_controllen = sizeof(control);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani cmsg = CMSG_FIRSTHDR(&msghdr);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani cmsg->cmsg_level = SOL_SOCKET;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani cmsg->cmsg_type = SCM_CREDENTIALS;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani memcpy(CMSG_DATA(cmsg), ucred, sizeof(struct ucred));
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani msghdr.msg_controllen = cmsg->cmsg_len;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* Forward the syslog message we received via /dev/log to
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani * /run/systemd/syslog. Unfortunately we currently can't set
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani * the SO_TIMESTAMP auxiliary data, and hence we don't. */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* The socket is full? I guess the syslog implementation is
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani * too slow, and we shouldn't wait for that... */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (errno == EAGAIN)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (ucred && errno == ESRCH) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani struct ucred u;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* Hmm, presumably the sender process vanished
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani * by now, so let's fix it as good as we
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani * can, and retry */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani u = *ucred;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani u.pid = getpid();
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred));
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (errno == EAGAIN)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani log_debug("Failed to forward syslog message: %m");
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani}
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahanistatic void forward_syslog_raw(Server *s, int priority, const char *buffer, struct ucred *ucred, struct timeval *tv) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani struct iovec iovec;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(s);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(buffer);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (LOG_PRI(priority) > s->max_level_syslog)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec, buffer);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani forward_syslog_iovec(s, &iovec, 1, ucred, tv);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani}
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahanistatic void forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani struct iovec iovec[5];
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char header_priority[6], header_time[64], header_pid[16];
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani int n = 0;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani time_t t;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani struct tm *tm;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char *ident_buf = NULL;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(s);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(priority >= 0);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(priority <= 999);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(message);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (LOG_PRI(priority) > s->max_level_syslog)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* First: priority field */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani snprintf(header_priority, sizeof(header_priority), "<%i>", priority);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char_array_0(header_priority);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], header_priority);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* Second: timestamp */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC));
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani tm = localtime(&t);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (!tm)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], header_time);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* Third: identifier and PID */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (ucred) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (!identifier) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani get_process_comm(ucred->pid, &ident_buf);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani identifier = ident_buf;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char_array_0(header_pid);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (identifier)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], identifier);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], header_pid);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani } else if (identifier) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], identifier);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], ": ");
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* Fourth: message */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], message);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani forward_syslog_iovec(s, iovec, n, ucred, tv);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani free(ident_buf);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani}
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahanistatic int fixup_priority(int priority) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if ((priority & LOG_FACMASK) == 0)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return (priority & LOG_PRIMASK) | LOG_USER;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return priority;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani}
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahanistatic void forward_kmsg(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani struct iovec iovec[5];
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char header_priority[6], header_pid[16];
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani int n = 0;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char *ident_buf = NULL;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani int fd;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(s);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(priority >= 0);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(priority <= 999);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(message);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (LOG_PRI(priority) > s->max_level_kmsg)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* Never allow messages with kernel facility to be written to
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani * kmsg, regardless where the data comes from. */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani priority = fixup_priority(priority);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* First: priority field */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani snprintf(header_priority, sizeof(header_priority), "<%i>", priority);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char_array_0(header_priority);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], header_priority);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* Second: identifier and PID */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (ucred) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (!identifier) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani get_process_comm(ucred->pid, &ident_buf);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani identifier = ident_buf;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char_array_0(header_pid);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (identifier)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], identifier);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], header_pid);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani } else if (identifier) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], identifier);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], ": ");
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* Fourth: message */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], message);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], "\n");
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (fd < 0) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani log_debug("Failed to open /dev/kmsg for logging: %s", strerror(errno));
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani goto finish;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (writev(fd, iovec, n) < 0)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani log_debug("Failed to write to /dev/kmsg for logging: %s", strerror(errno));
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani close_nointr_nofail(fd);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahanifinish:
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani free(ident_buf);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani}
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahanistatic void forward_console(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani struct iovec iovec[4];
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char header_pid[16];
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani int n = 0, fd;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char *ident_buf = NULL;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani const char *tty;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(s);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani assert(message);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (LOG_PRI(priority) > s->max_level_console)
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani return;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani /* First: identifier and PID */
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (ucred) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani if (!identifier) {
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani get_process_comm(ucred->pid, &ident_buf);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani identifier = ident_buf;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani }
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani char_array_0(header_pid);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (identifier)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering IOVEC_SET_STRING(iovec[n++], identifier);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering IOVEC_SET_STRING(iovec[n++], header_pid);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering } else if (identifier) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering IOVEC_SET_STRING(iovec[n++], identifier);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering IOVEC_SET_STRING(iovec[n++], ": ");
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* Third: message */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering IOVEC_SET_STRING(iovec[n++], message);
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani IOVEC_SET_STRING(iovec[n++], "\n");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering tty = s->tty_path ? s->tty_path : "/dev/console";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (fd < 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_debug("Failed to open %s for logging: %s", tty, strerror(errno));
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering goto finish;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (writev(fd, iovec, n) < 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_debug("Failed to write to %s for logging: %s", tty, strerror(errno));
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering close_nointr_nofail(fd);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringfinish:
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(ident_buf);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic void read_identifier(const char **buf, char **identifier, char **pid) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *p;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char *t;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering size_t l, e;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(buf);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(identifier);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering assert(pid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering p = *buf;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering p += strspn(p, WHITESPACE);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering l = strcspn(p, WHITESPACE);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (l <= 0 ||
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering p[l-1] != ':')
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering e = l;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering l--;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (p[l-1] == ']') {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering size_t k = l-1;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering for (;;) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (p[k] == '[') {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering t = strndup(p+k+1, l-k-2);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (t)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering *pid = t;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering l = k;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering break;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (k == 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering break;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering k--;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering t = strndup(p, l);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (t)
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen *identifier = t;
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen *buf = p + e;
49699bac94d24b444274f91f85c82e6fad04d029Susant Sahani *buf += strspn(*buf, WHITESPACE);
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic void process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len) {
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering struct iovec iovec[N_IOVEC_META_FIELDS + 6];
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering unsigned n = 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int priority = LOG_USER | LOG_INFO;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char *identifier = NULL, *pid = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *orig;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(s);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(buf);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering orig = buf;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering parse_syslog_priority((char**) &buf, &priority);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (s->forward_to_syslog)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering forward_syslog_raw(s, priority, orig, ucred, tv);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering skip_syslog_date((char**) &buf);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering read_identifier(&buf, &identifier, &pid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (s->forward_to_kmsg)
forward_kmsg(s, priority, identifier, buf, ucred);
if (s->forward_to_console)
forward_console(s, priority, identifier, buf, ucred);
IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog");
if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
IOVEC_SET_STRING(iovec[n++], syslog_priority);
if (priority & LOG_FACMASK)
if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
IOVEC_SET_STRING(iovec[n++], syslog_facility);
if (identifier) {
syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
if (syslog_identifier)
IOVEC_SET_STRING(iovec[n++], syslog_identifier);
}
if (pid) {
syslog_pid = strappend("SYSLOG_PID=", pid);
if (syslog_pid)
IOVEC_SET_STRING(iovec[n++], syslog_pid);
}
message = strappend("MESSAGE=", buf);
if (message)
IOVEC_SET_STRING(iovec[n++], message);
dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority);
free(message);
free(identifier);
free(pid);
free(syslog_priority);
free(syslog_facility);
free(syslog_identifier);
}
static bool valid_user_field(const char *p, size_t l) {
const char *a;
/* We kinda enforce POSIX syntax recommendations for
environment variables here, but make a couple of additional
requirements.
http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
/* No empty field names */
if (l <= 0)
return false;
/* Don't allow names longer than 64 chars */
if (l > 64)
return false;
/* Variables starting with an underscore are protected */
if (p[0] == '_')
return false;
/* Don't allow digits as first character */
if (p[0] >= '0' && p[0] <= '9')
return false;
/* Only allow A-Z0-9 and '_' */
for (a = p; a < p + l; a++)
if (!((*a >= 'A' && *a <= 'Z') ||
(*a >= '0' && *a <= '9') ||
*a == '_'))
return false;
return true;
}
static void process_native_message(
Server *s,
const void *buffer, size_t buffer_size,
struct ucred *ucred,
struct timeval *tv,
const char *label, size_t label_len) {
struct iovec *iovec = NULL;
unsigned n = 0, m = 0, j, tn = (unsigned) -1;
const char *p;
size_t remaining;
int priority = LOG_INFO;
char *identifier = NULL, *message = NULL;
assert(s);
assert(buffer || buffer_size == 0);
p = buffer;
remaining = buffer_size;
while (remaining > 0) {
const char *e, *q;
e = memchr(p, '\n', remaining);
if (!e) {
/* Trailing noise, let's ignore it, and flush what we collected */
log_debug("Received message with trailing noise, ignoring.");
break;
}
if (e == p) {
/* Entry separator */
dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
n = 0;
priority = LOG_INFO;
p++;
remaining--;
continue;
}
if (*p == '.' || *p == '#') {
/* Ignore control commands for now, and
* comments too. */
remaining -= (e - p) + 1;
p = e + 1;
continue;
}
/* A property follows */
if (n+N_IOVEC_META_FIELDS >= m) {
struct iovec *c;
unsigned u;
u = MAX((n+N_IOVEC_META_FIELDS+1) * 2U, 4U);
c = realloc(iovec, u * sizeof(struct iovec));
if (!c) {
log_error("Out of memory");
break;
}
iovec = c;
m = u;
}
q = memchr(p, '=', e - p);
if (q) {
if (valid_user_field(p, q - p)) {
size_t l;
l = e - p;
/* If the field name starts with an
* underscore, skip the variable,
* since that indidates a trusted
* field */
iovec[n].iov_base = (char*) p;
iovec[n].iov_len = l;
n++;
/* We need to determine the priority
* of this entry for the rate limiting
* logic */
if (l == 10 &&
memcmp(p, "PRIORITY=", 9) == 0 &&
p[9] >= '0' && p[9] <= '9')
priority = (priority & LOG_FACMASK) | (p[9] - '0');
else if (l == 17 &&
memcmp(p, "SYSLOG_FACILITY=", 16) == 0 &&
p[16] >= '0' && p[16] <= '9')
priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
else if (l == 18 &&
memcmp(p, "SYSLOG_FACILITY=", 16) == 0 &&
p[16] >= '0' && p[16] <= '9' &&
p[17] >= '0' && p[17] <= '9')
priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
else if (l >= 19 &&
memcmp(p, "SYSLOG_IDENTIFIER=", 18) == 0) {
char *t;
t = strndup(p + 18, l - 18);
if (t) {
free(identifier);
identifier = t;
}
} else if (l >= 8 &&
memcmp(p, "MESSAGE=", 8) == 0) {
char *t;
t = strndup(p + 8, l - 8);
if (t) {
free(message);
message = t;
}
}
}
remaining -= (e - p) + 1;
p = e + 1;
continue;
} else {
le64_t l_le;
uint64_t l;
char *k;
if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
log_debug("Failed to parse message, ignoring.");
break;
}
memcpy(&l_le, e + 1, sizeof(uint64_t));
l = le64toh(l_le);
if (remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
e[1+sizeof(uint64_t)+l] != '\n') {
log_debug("Failed to parse message, ignoring.");
break;
}
k = malloc((e - p) + 1 + l);
if (!k) {
log_error("Out of memory");
break;
}
memcpy(k, p, e - p);
k[e - p] = '=';
memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
if (valid_user_field(p, e - p)) {
iovec[n].iov_base = k;
iovec[n].iov_len = (e - p) + 1 + l;
n++;
} else
free(k);
remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
p = e + 1 + sizeof(uint64_t) + l + 1;
}
}
if (n <= 0)
goto finish;
tn = n++;
IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
if (message) {
if (s->forward_to_syslog)
forward_syslog(s, priority, identifier, message, ucred, tv);
if (s->forward_to_kmsg)
forward_kmsg(s, priority, identifier, message, ucred);
if (s->forward_to_console)
forward_console(s, priority, identifier, message, ucred);
}
dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
finish:
for (j = 0; j < n; j++) {
if (j == tn)
continue;
if (iovec[j].iov_base < buffer ||
(const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
free(iovec[j].iov_base);
}
free(iovec);
free(identifier);
free(message);
}
static void process_native_file(
Server *s,
int fd,
struct ucred *ucred,
struct timeval *tv,
const char *label, size_t label_len) {
struct stat st;
void *p;
ssize_t n;
assert(s);
assert(fd >= 0);
/* Data is in the passed file, since it didn't fit in a
* datagram. We can't map the file here, since clients might
* then truncate it and trigger a SIGBUS for us. So let's
* stupidly read it */
if (fstat(fd, &st) < 0) {
log_error("Failed to stat passed file, ignoring: %m");
return;
}
if (!S_ISREG(st.st_mode)) {
log_error("File passed is not regular. Ignoring.");
return;
}
if (st.st_size <= 0)
return;
if (st.st_size > ENTRY_SIZE_MAX) {
log_error("File passed too large. Ignoring.");
return;
}
p = malloc(st.st_size);
if (!p) {
log_error("Out of memory");
return;
}
n = pread(fd, p, st.st_size, 0);
if (n < 0)
log_error("Failed to read file, ignoring: %s", strerror(-n));
else if (n > 0)
process_native_message(s, p, n, ucred, tv, label, label_len);
free(p);
}
static int stdout_stream_log(StdoutStream *s, const char *p) {
struct iovec iovec[N_IOVEC_META_FIELDS + 5];
char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL;
unsigned n = 0;
int priority;
char *label = NULL;
size_t label_len = 0;
assert(s);
assert(p);
if (isempty(p))
return 0;
priority = s->priority;
if (s->level_prefix)
parse_syslog_priority((char**) &p, &priority);
if (s->forward_to_syslog || s->server->forward_to_syslog)
forward_syslog(s->server, fixup_priority(priority), s->identifier, p, &s->ucred, NULL);
if (s->forward_to_kmsg || s->server->forward_to_kmsg)
forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
if (s->forward_to_console || s->server->forward_to_console)
forward_console(s->server, priority, s->identifier, p, &s->ucred);
IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
IOVEC_SET_STRING(iovec[n++], syslog_priority);
if (priority & LOG_FACMASK)
if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
IOVEC_SET_STRING(iovec[n++], syslog_facility);
if (s->identifier) {
syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
if (syslog_identifier)
IOVEC_SET_STRING(iovec[n++], syslog_identifier);
}
message = strappend("MESSAGE=", p);
if (message)
IOVEC_SET_STRING(iovec[n++], message);
#ifdef HAVE_SELINUX
if (s->security_context) {
label = (char*) s->security_context;
label_len = strlen((char*) s->security_context);
}
#endif
dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority);
free(message);
free(syslog_priority);
free(syslog_facility);
free(syslog_identifier);
return 0;
}
static int stdout_stream_line(StdoutStream *s, char *p) {
int r;
assert(s);
assert(p);
p = strstrip(p);
switch (s->state) {
case STDOUT_STREAM_IDENTIFIER:
if (isempty(p))
s->identifier = NULL;
else {
s->identifier = strdup(p);
if (!s->identifier) {
log_error("Out of memory");
return -ENOMEM;
}
}
s->state = STDOUT_STREAM_UNIT_ID;
return 0;
case STDOUT_STREAM_UNIT_ID:
if (s->ucred.uid == 0) {
if (isempty(p))
s->unit_id = NULL;
else {
s->unit_id = strdup(p);
if (!s->unit_id) {
log_error("Out of memory");
return -ENOMEM;
}
}
}
s->state = STDOUT_STREAM_PRIORITY;
return 0;
case STDOUT_STREAM_PRIORITY:
r = safe_atoi(p, &s->priority);
if (r < 0 || s->priority <= 0 || s->priority >= 999) {
log_warning("Failed to parse log priority line.");
return -EINVAL;
}
s->state = STDOUT_STREAM_LEVEL_PREFIX;
return 0;
case STDOUT_STREAM_LEVEL_PREFIX:
r = parse_boolean(p);
if (r < 0) {
log_warning("Failed to parse level prefix line.");
return -EINVAL;
}
s->level_prefix = !!r;
s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
return 0;
case STDOUT_STREAM_FORWARD_TO_SYSLOG:
r = parse_boolean(p);
if (r < 0) {
log_warning("Failed to parse forward to syslog line.");
return -EINVAL;
}
s->forward_to_syslog = !!r;
s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
return 0;
case STDOUT_STREAM_FORWARD_TO_KMSG:
r = parse_boolean(p);
if (r < 0) {
log_warning("Failed to parse copy to kmsg line.");
return -EINVAL;
}
s->forward_to_kmsg = !!r;
s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
return 0;
case STDOUT_STREAM_FORWARD_TO_CONSOLE:
r = parse_boolean(p);
if (r < 0) {
log_warning("Failed to parse copy to console line.");
return -EINVAL;
}
s->forward_to_console = !!r;
s->state = STDOUT_STREAM_RUNNING;
return 0;
case STDOUT_STREAM_RUNNING:
return stdout_stream_log(s, p);
}
assert_not_reached("Unknown stream state");
}
static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
char *p;
size_t remaining;
int r;
assert(s);
p = s->buffer;
remaining = s->length;
for (;;) {
char *end;
size_t skip;
end = memchr(p, '\n', remaining);
if (end)
skip = end - p + 1;
else if (remaining >= sizeof(s->buffer) - 1) {
end = p + sizeof(s->buffer) - 1;
skip = remaining;
} else
break;
*end = 0;
r = stdout_stream_line(s, p);
if (r < 0)
return r;
remaining -= skip;
p += skip;
}
if (force_flush && remaining > 0) {
p[remaining] = 0;
r = stdout_stream_line(s, p);
if (r < 0)
return r;
p += remaining;
remaining = 0;
}
if (p > s->buffer) {
memmove(s->buffer, p, remaining);
s->length = remaining;
}
return 0;
}
static int stdout_stream_process(StdoutStream *s) {
ssize_t l;
int r;
assert(s);
l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
if (l < 0) {
if (errno == EAGAIN)
return 0;
log_warning("Failed to read from stream: %m");
return -errno;
}
if (l == 0) {
r = stdout_stream_scan(s, true);
if (r < 0)
return r;
return 0;
}
s->length += l;
r = stdout_stream_scan(s, false);
if (r < 0)
return r;
return 1;
}
static void stdout_stream_free(StdoutStream *s) {
assert(s);
if (s->server) {
assert(s->server->n_stdout_streams > 0);
s->server->n_stdout_streams --;
LIST_REMOVE(StdoutStream, stdout_stream, s->server->stdout_streams, s);
}
if (s->fd >= 0) {
if (s->server)
epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL);
close_nointr_nofail(s->fd);
}
#ifdef HAVE_SELINUX
if (s->security_context)
freecon(s->security_context);
#endif
free(s->identifier);
free(s);
}
static int stdout_stream_new(Server *s) {
StdoutStream *stream;
int fd, r;
socklen_t len;
struct epoll_event ev;
assert(s);
fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (fd < 0) {
if (errno == EAGAIN)
return 0;
log_error("Failed to accept stdout connection: %m");
return -errno;
}
if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
log_warning("Too many stdout streams, refusing connection.");
close_nointr_nofail(fd);
return 0;
}
stream = new0(StdoutStream, 1);
if (!stream) {
log_error("Out of memory.");
close_nointr_nofail(fd);
return -ENOMEM;
}
stream->fd = fd;
len = sizeof(stream->ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) {
log_error("Failed to determine peer credentials: %m");
r = -errno;
goto fail;
}
#ifdef HAVE_SELINUX
if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT)
log_error("Failed to determine peer security context: %m");
#endif
if (shutdown(fd, SHUT_WR) < 0) {
log_error("Failed to shutdown writing side of socket: %m");
r = -errno;
goto fail;
}
zero(ev);
ev.data.ptr = stream;
ev.events = EPOLLIN;
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
log_error("Failed to add stream to event loop: %m");
r = -errno;
goto fail;
}
stream->server = s;
LIST_PREPEND(StdoutStream, stdout_stream, s->stdout_streams, stream);
s->n_stdout_streams ++;
return 0;
fail:
stdout_stream_free(stream);
return r;
}
static int parse_kernel_timestamp(char **_p, usec_t *t) {
usec_t r;
int k, i;
char *p;
assert(_p);
assert(*_p);
assert(t);
p = *_p;
if (strlen(p) < 14 || p[0] != '[' || p[13] != ']' || p[6] != '.')
return 0;
r = 0;
for (i = 1; i <= 5; i++) {
r *= 10;
if (p[i] == ' ')
continue;
k = undecchar(p[i]);
if (k < 0)
return 0;
r += k;
}
for (i = 7; i <= 12; i++) {
r *= 10;
k = undecchar(p[i]);
if (k < 0)
return 0;
r += k;
}
*t = r;
*_p += 14;
*_p += strspn(*_p, WHITESPACE);
return 1;
}
static bool is_us(const char *pid) {
pid_t t;
assert(pid);
if (parse_pid(pid, &t) < 0)
return false;
return t == getpid();
}
static void proc_kmsg_line(Server *s, const char *p) {
struct iovec iovec[N_IOVEC_META_FIELDS + 7];
char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL;
int priority = LOG_KERN | LOG_INFO;
unsigned n = 0;
usec_t usec;
char *identifier = NULL, *pid = NULL;
assert(s);
assert(p);
if (isempty(p))
return;
parse_syslog_priority((char **) &p, &priority);
if (s->forward_to_kmsg && (priority & LOG_FACMASK) != LOG_KERN)
return;
if (parse_kernel_timestamp((char **) &p, &usec) > 0) {
if (asprintf(&source_time, "_SOURCE_MONOTONIC_TIMESTAMP=%llu",
(unsigned long long) usec) >= 0)
IOVEC_SET_STRING(iovec[n++], source_time);
}
IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=kernel");
if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
IOVEC_SET_STRING(iovec[n++], syslog_priority);
if ((priority & LOG_FACMASK) == LOG_KERN) {
if (s->forward_to_syslog)
forward_syslog(s, priority, "kernel", p, NULL, NULL);
IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=kernel");
} else {
read_identifier(&p, &identifier, &pid);
/* Avoid any messages we generated ourselves via
* log_info() and friends. */
if (pid && is_us(pid))
goto finish;
if (s->forward_to_syslog)
forward_syslog(s, priority, identifier, p, NULL, NULL);
if (identifier) {
syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
if (syslog_identifier)
IOVEC_SET_STRING(iovec[n++], syslog_identifier);
}
if (pid) {
syslog_pid = strappend("SYSLOG_PID=", pid);
if (syslog_pid)
IOVEC_SET_STRING(iovec[n++], syslog_pid);
}
if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
IOVEC_SET_STRING(iovec[n++], syslog_facility);
}
message = strappend("MESSAGE=", p);
if (message)
IOVEC_SET_STRING(iovec[n++], message);
dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority);
finish:
free(message);
free(syslog_priority);
free(syslog_identifier);
free(syslog_pid);
free(syslog_facility);
free(source_time);
free(identifier);
free(pid);
}
static void proc_kmsg_scan(Server *s) {
char *p;
size_t remaining;
assert(s);
p = s->proc_kmsg_buffer;
remaining = s->proc_kmsg_length;
for (;;) {
char *end;
size_t skip;
end = memchr(p, '\n', remaining);
if (end)
skip = end - p + 1;
else if (remaining >= sizeof(s->proc_kmsg_buffer) - 1) {
end = p + sizeof(s->proc_kmsg_buffer) - 1;
skip = remaining;
} else
break;
*end = 0;
proc_kmsg_line(s, p);
remaining -= skip;
p += skip;
}
if (p > s->proc_kmsg_buffer) {
memmove(s->proc_kmsg_buffer, p, remaining);
s->proc_kmsg_length = remaining;
}
}
static int system_journal_open(Server *s) {
int r;
char *fn;
sd_id128_t machine;
char ids[33];
r = sd_id128_get_machine(&machine);
if (r < 0)
return r;
sd_id128_to_string(machine, ids);
if (!s->system_journal) {
/* First try to create the machine path, but not the prefix */
fn = strappend("/var/log/journal/", ids);
if (!fn)
return -ENOMEM;
(void) mkdir(fn, 0755);
free(fn);
/* The create the system journal file */
fn = join("/var/log/journal/", ids, "/system.journal", NULL);
if (!fn)
return -ENOMEM;
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, NULL, &s->system_journal);
free(fn);
if (r >= 0) {
journal_default_metrics(&s->system_metrics, s->system_journal->fd);
s->system_journal->metrics = s->system_metrics;
s->system_journal->compress = s->compress;
server_fix_perms(s, s->system_journal, 0);
} else if (r < 0) {
if (r != -ENOENT && r != -EROFS)
log_warning("Failed to open system journal: %s", strerror(-r));
r = 0;
}
}
if (!s->runtime_journal) {
fn = join("/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, NULL, &s->runtime_journal);
free(fn);
if (r < 0) {
if (r != -ENOENT)
log_warning("Failed to open runtime journal: %s", strerror(-r));
r = 0;
}
} else {
/* OK, we really need the runtime journal, so create
* it if necessary. */
(void) mkdir_parents_label(fn, 0755);
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, NULL, &s->runtime_journal);
free(fn);
if (r < 0) {
log_error("Failed to open runtime journal: %s", strerror(-r));
return r;
}
}
if (s->runtime_journal) {
journal_default_metrics(&s->runtime_metrics, s->runtime_journal->fd);
s->runtime_journal->metrics = s->runtime_metrics;
s->runtime_journal->compress = s->compress;
server_fix_perms(s, s->runtime_journal, 0);
}
}
return r;
}
static int server_flush_to_var(Server *s) {
char path[] = "/run/log/journal/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
Object *o = NULL;
int r;
sd_id128_t machine;
sd_journal *j;
usec_t ts;
assert(s);
if (!s->runtime_journal)
return 0;
ts = now(CLOCK_MONOTONIC);
if (s->var_available_timestamp + RECHECK_VAR_AVAILABLE_USEC > ts)
return 0;
s->var_available_timestamp = ts;
system_journal_open(s);
if (!s->system_journal)
return 0;
log_info("Flushing to /var...");
r = sd_id128_get_machine(&machine);
if (r < 0) {
log_error("Failed to get machine id: %s", strerror(-r));
return r;
}
r = sd_journal_open(&j, SD_JOURNAL_RUNTIME_ONLY);
if (r < 0) {
log_error("Failed to read runtime journal: %s", strerror(-r));
return r;
}
SD_JOURNAL_FOREACH(j) {
JournalFile *f;
f = j->current_file;
assert(f && f->current_offset > 0);
r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
if (r < 0) {
log_error("Can't read entry: %s", strerror(-r));
goto finish;
}
r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL);
if (r == -E2BIG) {
log_info("Allocation limit reached.");
journal_file_post_change(s->system_journal);
server_rotate(s);
server_vacuum(s);
r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL);
}
if (r < 0) {
log_error("Can't write entry: %s", strerror(-r));
goto finish;
}
}
finish:
journal_file_post_change(s->system_journal);
journal_file_close(s->runtime_journal);
s->runtime_journal = NULL;
if (r >= 0) {
sd_id128_to_string(machine, path + 17);
rm_rf(path, false, true, false);
}
return r;
}
static int server_read_proc_kmsg(Server *s) {
ssize_t l;
assert(s);
assert(s->proc_kmsg_fd >= 0);
l = read(s->proc_kmsg_fd, s->proc_kmsg_buffer + s->proc_kmsg_length, sizeof(s->proc_kmsg_buffer) - 1 - s->proc_kmsg_length);
if (l < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
log_error("Failed to read from kernel: %m");
return -errno;
}
s->proc_kmsg_length += l;
proc_kmsg_scan(s);
return 1;
}
static int server_flush_proc_kmsg(Server *s) {
int r;
assert(s);
if (s->proc_kmsg_fd < 0)
return 0;
log_info("Flushing /proc/kmsg...");
for (;;) {
r = server_read_proc_kmsg(s);
if (r < 0)
return r;
if (r == 0)
break;
}
return 0;
}
static int process_event(Server *s, struct epoll_event *ev) {
assert(s);
assert(ev);
if (ev->data.fd == s->signal_fd) {
struct signalfd_siginfo sfsi;
ssize_t n;
if (ev->events != EPOLLIN) {
log_info("Got invalid event from epoll.");
return -EIO;
}
n = read(s->signal_fd, &sfsi, sizeof(sfsi));
if (n != sizeof(sfsi)) {
if (n >= 0)
return -EIO;
if (errno == EINTR || errno == EAGAIN)
return 1;
return -errno;
}
if (sfsi.ssi_signo == SIGUSR1) {
server_flush_to_var(s);
return 1;
}
if (sfsi.ssi_signo == SIGUSR2) {
server_rotate(s);
server_vacuum(s);
return 1;
}
log_debug("Received SIG%s", signal_to_string(sfsi.ssi_signo));
return 0;
} else if (ev->data.fd == s->proc_kmsg_fd) {
int r;
if (ev->events != EPOLLIN) {
log_info("Got invalid event from epoll.");
return -EIO;
}
r = server_read_proc_kmsg(s);
if (r < 0)
return r;
return 1;
} else if (ev->data.fd == s->native_fd ||
ev->data.fd == s->syslog_fd) {
if (ev->events != EPOLLIN) {
log_info("Got invalid event from epoll.");
return -EIO;
}
for (;;) {
struct msghdr msghdr;
struct iovec iovec;
struct ucred *ucred = NULL;
struct timeval *tv = NULL;
struct cmsghdr *cmsg;
char *label = NULL;
size_t label_len = 0;
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;
ssize_t n;
int v;
int *fds = NULL;
unsigned n_fds = 0;
if (ioctl(ev->data.fd, SIOCINQ, &v) < 0) {
log_error("SIOCINQ failed: %m");
return -errno;
}
if (s->buffer_size < (size_t) v) {
void *b;
size_t l;
l = MAX(LINE_MAX + (size_t) v, s->buffer_size * 2);
b = realloc(s->buffer, l+1);
if (!b) {
log_error("Couldn't increase buffer.");
return -ENOMEM;
}
s->buffer_size = l;
s->buffer = b;
}
zero(iovec);
iovec.iov_base = s->buffer;
iovec.iov_len = s->buffer_size;
zero(control);
zero(msghdr);
msghdr.msg_iov = &iovec;
msghdr.msg_iovlen = 1;
msghdr.msg_control = &control;
msghdr.msg_controllen = sizeof(control);
n = recvmsg(ev->data.fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
if (errno == EINTR || errno == EAGAIN)
return 1;
log_error("recvmsg() failed: %m");
return -errno;
}
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);
}
}
if (ev->data.fd == s->syslog_fd) {
char *e;
if (n > 0 && n_fds == 0) {
e = memchr(s->buffer, '\n', n);
if (e)
*e = 0;
else
s->buffer[n] = 0;
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 (n > 0 && n_fds == 0)
process_native_message(s, s->buffer, n, ucred, tv, label, label_len);
else if (n == 0 && n_fds == 1)
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.");
}
close_many(fds, n_fds);
}
return 1;
} else if (ev->data.fd == s->stdout_fd) {
if (ev->events != EPOLLIN) {
log_info("Got invalid event from epoll.");
return -EIO;
}
stdout_stream_new(s);
return 1;
} else {
StdoutStream *stream;
if ((ev->events|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) {
log_info("Got invalid event from epoll.");
return -EIO;
}
/* If it is none of the well-known fds, it must be an
* stdout stream fd. Note that this is a bit ugly here
* (since we rely that none of the well-known fds
* could be interpreted as pointer), but nonetheless
* safe, since the well-known fds would never get an
* fd > 4096, i.e. beyond the first memory page */
stream = ev->data.ptr;
if (stdout_stream_process(stream) <= 0)
stdout_stream_free(stream);
return 1;
}
log_error("Unknown event.");
return 0;
}
static int open_syslog_socket(Server *s) {
union sockaddr_union sa;
int one, r;
struct epoll_event ev;
assert(s);
if (s->syslog_fd < 0) {
s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->syslog_fd < 0) {
log_error("socket() failed: %m");
return -errno;
}
zero(sa);
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
unlink(sa.un.sun_path);
r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
if (r < 0) {
log_error("bind() failed: %m");
return -errno;
}
chmod(sa.un.sun_path, 0666);
} else
fd_nonblock(s->syslog_fd, 1);
one = 1;
r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
if (r < 0) {
log_error("SO_PASSCRED failed: %m");
return -errno;
}
#ifdef HAVE_SELINUX
one = 1;
r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
if (r < 0)
log_warning("SO_PASSSEC failed: %m");
#endif
one = 1;
r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
if (r < 0) {
log_error("SO_TIMESTAMP failed: %m");
return -errno;
}
zero(ev);
ev.events = EPOLLIN;
ev.data.fd = s->syslog_fd;
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->syslog_fd, &ev) < 0) {
log_error("Failed to add syslog server fd to epoll object: %m");
return -errno;
}
return 0;
}
static int open_native_socket(Server*s) {
union sockaddr_union sa;
int one, r;
struct epoll_event ev;
assert(s);
if (s->native_fd < 0) {
s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->native_fd < 0) {
log_error("socket() failed: %m");
return -errno;
}
zero(sa);
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
unlink(sa.un.sun_path);
r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
if (r < 0) {
log_error("bind() failed: %m");
return -errno;
}
chmod(sa.un.sun_path, 0666);
} else
fd_nonblock(s->native_fd, 1);
one = 1;
r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
if (r < 0) {
log_error("SO_PASSCRED failed: %m");
return -errno;
}
#ifdef HAVE_SELINUX
one = 1;
r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
if (r < 0)
log_warning("SO_PASSSEC failed: %m");
#endif
one = 1;
r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
if (r < 0) {
log_error("SO_TIMESTAMP failed: %m");
return -errno;
}
zero(ev);
ev.events = EPOLLIN;
ev.data.fd = s->native_fd;
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->native_fd, &ev) < 0) {
log_error("Failed to add native server fd to epoll object: %m");
return -errno;
}
return 0;
}
static int open_stdout_socket(Server *s) {
union sockaddr_union sa;
int r;
struct epoll_event ev;
assert(s);
if (s->stdout_fd < 0) {
s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->stdout_fd < 0) {
log_error("socket() failed: %m");
return -errno;
}
zero(sa);
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
unlink(sa.un.sun_path);
r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
if (r < 0) {
log_error("bind() failed: %m");
return -errno;
}
chmod(sa.un.sun_path, 0666);
if (listen(s->stdout_fd, SOMAXCONN) < 0) {
log_error("liste() failed: %m");
return -errno;
}
} else
fd_nonblock(s->stdout_fd, 1);
zero(ev);
ev.events = EPOLLIN;
ev.data.fd = s->stdout_fd;
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->stdout_fd, &ev) < 0) {
log_error("Failed to add stdout server fd to epoll object: %m");
return -errno;
}
return 0;
}
static int open_proc_kmsg(Server *s) {
struct epoll_event ev;
assert(s);
if (!s->import_proc_kmsg)
return 0;
s->proc_kmsg_fd = open("/proc/kmsg", O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (s->proc_kmsg_fd < 0) {
log_warning("Failed to open /proc/kmsg, ignoring: %m");
return 0;
}
zero(ev);
ev.events = EPOLLIN;
ev.data.fd = s->proc_kmsg_fd;
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->proc_kmsg_fd, &ev) < 0) {
log_error("Failed to add /proc/kmsg fd to epoll object: %m");
return -errno;
}
return 0;
}
static int open_signalfd(Server *s) {
sigset_t mask;
struct epoll_event ev;
assert(s);
assert_se(sigemptyset(&mask) == 0);
sigset_add_many(&mask, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, -1);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
s->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (s->signal_fd < 0) {
log_error("signalfd(): %m");
return -errno;
}
zero(ev);
ev.events = EPOLLIN;
ev.data.fd = s->signal_fd;
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->signal_fd, &ev) < 0) {
log_error("epoll_ctl(): %m");
return -errno;
}
return 0;
}
static int server_parse_proc_cmdline(Server *s) {
char *line, *w, *state;
int r;
size_t l;
if (detect_container(NULL) > 0)
return 0;
r = read_one_line_file("/proc/cmdline", &line);
if (r < 0) {
log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
return 0;
}
FOREACH_WORD_QUOTED(w, l, line, state) {
char *word;
word = strndup(w, l);
if (!word) {
r = -ENOMEM;
goto finish;
}
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"))
log_warning("Invalid systemd.journald parameter. Ignoring.");
free(word);
}
r = 0;
finish:
free(line);
return r;
}
static int server_parse_config_file(Server *s) {
FILE *f;
const char *fn;
int r;
assert(s);
fn = "/etc/systemd/journald.conf";
f = fopen(fn, "re");
if (!f) {
if (errno == ENOENT)
return 0;
log_warning("Failed to open configuration file %s: %m", fn);
return -errno;
}
r = config_parse(fn, f, "Journal\0", config_item_perf_lookup, (void*) journald_gperf_lookup, false, s);
if (r < 0)
log_warning("Failed to parse configuration file: %s", strerror(-r));
fclose(f);
return r;
}
static int server_init(Server *s) {
int n, r, fd;
assert(s);
zero(*s);
s->syslog_fd = s->native_fd = s->stdout_fd = s->signal_fd = s->epoll_fd = s->proc_kmsg_fd = -1;
s->compress = true;
s->rate_limit_interval = DEFAULT_RATE_LIMIT_INTERVAL;
s->rate_limit_burst = DEFAULT_RATE_LIMIT_BURST;
s->forward_to_syslog = true;
s->import_proc_kmsg = true;
s->max_level_store = LOG_DEBUG;
s->max_level_syslog = LOG_DEBUG;
s->max_level_kmsg = LOG_NOTICE;
s->max_level_console = LOG_INFO;
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);
s->user_journals = hashmap_new(trivial_hash_func, trivial_compare_func);
if (!s->user_journals) {
log_error("Out of memory.");
return -ENOMEM;
}
s->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (s->epoll_fd < 0) {
log_error("Failed to create epoll object: %m");
return -errno;
}
n = sd_listen_fds(true);
if (n < 0) {
log_error("Failed to read listening file descriptors from environment: %s", strerror(-n));
return n;
}
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) {
if (s->syslog_fd >= 0) {
log_error("Too many /dev/log sockets passed.");
return -EINVAL;
}
s->syslog_fd = fd;
} else {
log_error("Unknown socket passed.");
return -EINVAL;
}
}
r = open_syslog_socket(s);
if (r < 0)
return r;
r = open_native_socket(s);
if (r < 0)
return r;
r = open_stdout_socket(s);
if (r < 0)
return r;
r = open_proc_kmsg(s);
if (r < 0)
return r;
r = open_signalfd(s);
if (r < 0)
return r;
s->rate_limit = journal_rate_limit_new(s->rate_limit_interval, s->rate_limit_burst);
if (!s->rate_limit)
return -ENOMEM;
r = system_journal_open(s);
if (r < 0)
return r;
return 0;
}
static 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 = hashmap_steal_first(s->user_journals)))
journal_file_close(f);
hashmap_free(s->user_journals);
if (s->epoll_fd >= 0)
close_nointr_nofail(s->epoll_fd);
if (s->signal_fd >= 0)
close_nointr_nofail(s->signal_fd);
if (s->syslog_fd >= 0)
close_nointr_nofail(s->syslog_fd);
if (s->native_fd >= 0)
close_nointr_nofail(s->native_fd);
if (s->stdout_fd >= 0)
close_nointr_nofail(s->stdout_fd);
if (s->proc_kmsg_fd >= 0)
close_nointr_nofail(s->proc_kmsg_fd);
if (s->rate_limit)
journal_rate_limit_free(s->rate_limit);
free(s->buffer);
free(s->tty_path);
}
int main(int argc, char *argv[]) {
Server server;
int r;
/* if (getppid() != 1) { */
/* log_error("This program should be invoked by init only."); */
/* return EXIT_FAILURE; */
/* } */
if (argc > 1) {
log_error("This program does not take arguments.");
return EXIT_FAILURE;
}
log_set_target(LOG_TARGET_SAFE);
log_set_facility(LOG_SYSLOG);
log_parse_environment();
log_open();
umask(0022);
r = server_init(&server);
if (r < 0)
goto finish;
server_vacuum(&server);
server_flush_to_var(&server);
server_flush_proc_kmsg(&server);
log_debug("systemd-journald running as pid %lu", (unsigned long) getpid());
driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started");
sd_notify(false,
"READY=1\n"
"STATUS=Processing requests...");
for (;;) {
struct epoll_event event;
r = epoll_wait(server.epoll_fd, &event, 1, -1);
if (r < 0) {
if (errno == EINTR)
continue;
log_error("epoll_wait() failed: %m");
r = -errno;
goto finish;
} else if (r == 0)
break;
r = process_event(&server, &event);
if (r < 0)
goto finish;
else if (r == 0)
break;
}
log_debug("systemd-journald stopped as pid %lu", (unsigned long) getpid());
driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped");
finish:
sd_notify(false,
"STATUS=Shutting down...");
server_done(&server);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}