journald.c revision 259d2e762041d8d50c2a17bfea90b1a96f6b880b
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington/***
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington This file is part of systemd.
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington Copyright 2011 Lennart Poettering
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington systemd is free software; you can redistribute it and/or modify it
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington under the terms of the GNU General Public License as published by
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington the Free Software Foundation; either version 2 of the License, or
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington (at your option) any later version.
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington systemd is distributed in the hope that it will be useful, but
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington WITHOUT ANY WARRANTY; without even the implied warranty of
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington General Public License for more details.
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington
0eace215bd758e347767c63c13504520e855b94aAndreas Gustafsson You should have received a copy of the GNU General Public License
d4ef65050feac78554addf6e16a06c6e2e0bd331Brian Wellington along with systemd; If not, see <http://www.gnu.org/licenses/>.
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington***/
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include <sys/epoll.h>
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include <sys/socket.h>
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include <errno.h>
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence#include <sys/signalfd.h>
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence#include <unistd.h>
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include <fcntl.h>
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence#include <sys/acl.h>
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence#include <acl/libacl.h>
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence#include <stddef.h>
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include <sys/ioctl.h>
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence#include <linux/sockios.h>
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include <sys/statvfs.h>
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include <systemd/sd-journal.h>
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include <systemd/sd-login.h>
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include <systemd/sd-messages.h>
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include <systemd/sd-daemon.h>
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include "hashmap.h"
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include "journal-file.h"
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include "socket-util.h"
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include "acl-util.h"
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include "cgroup-util.h"
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include "list.h"
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include "journal-rate-limit.h"
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include "journal-internal.h"
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence#include "conf-parser.h"
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#include "journald.h"
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence#define USER_JOURNALS_MAX 1024
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence#define STDOUT_STREAMS_MAX 4096
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#define DEFAULT_RATE_LIMIT_INTERVAL (10*USEC_PER_SEC)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#define DEFAULT_RATE_LIMIT_BURST 200
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#define RECHECK_VAR_AVAILABLE_USEC (30*USEC_PER_SEC)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#define SYSLOG_TIMEOUT_USEC (5*USEC_PER_SEC)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington#define N_IOVEC_META_FIELDS 16
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtontypedef enum StdoutStreamState {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington STDOUT_STREAM_TAG,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington STDOUT_STREAM_PRIORITY,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington STDOUT_STREAM_PRIORITY_PREFIX,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington STDOUT_STREAM_FORWARD_TO_SYSLOG,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington STDOUT_STREAM_FORWARD_TO_KMSG,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington STDOUT_STREAM_FORWARD_TO_CONSOLE,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington STDOUT_STREAM_RUNNING
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington} StdoutStreamState;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstruct StdoutStream {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington Server *server;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington StdoutStreamState state;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int fd;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct ucred ucred;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char *tag;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int priority;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington bool priority_prefix:1;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington bool forward_to_syslog:1;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington bool forward_to_kmsg:1;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington bool forward_to_console:1;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson char buffer[LINE_MAX+1];
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington size_t length;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington LIST_FIELDS(StdoutStream, stdout_stream);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington};
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic int server_flush_to_var(Server *s);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic uint64_t available_space(Server *s) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char ids[33], *p;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington const char *f;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington sd_id128_t machine;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct statvfs ss;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence uint64_t sum = 0, avail = 0, ss_avail = 0;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence int r;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence DIR *d;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence usec_t ts;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence JournalMetrics *m;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence ts = now(CLOCK_MONOTONIC);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return s->cached_available_space;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson r = sd_id128_get_machine(&machine);
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson if (r < 0)
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson return 0;
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->system_journal) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington f = "/var/log/journal/";
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington m = &s->system_metrics;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington } else {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington f = "/run/log/journal/";
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington m = &s->runtime_metrics;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(m);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington p = strappend(f, sd_id128_to_string(machine, ids));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!p)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return 0;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington d = opendir(p);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(p);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!d)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return 0;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (fstatvfs(dirfd(d), &ss) < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington goto finish;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington for (;;) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct stat st;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct dirent buf, *de;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int k;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington k = readdir_r(d, &buf, &de);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (k != 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = -k;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington goto finish;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!de)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington break;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!dirent_is_file_with_suffix(de, ".journal"))
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington continue;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington continue;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington sum += (uint64_t) st.st_blocks * (uint64_t) st.st_blksize;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington avail = sum >= m->max_use ? 0 : m->max_use - sum;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington ss_avail = ss.f_bsize * ss.f_bavail;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington ss_avail = ss_avail < m->keep_free ? 0 : ss_avail - m->keep_free;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (ss_avail < avail)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington avail = ss_avail;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington s->cached_available_space = avail;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington s->cached_available_space_timestamp = ts;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonfinish:
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington closedir(d);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return avail;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic void fix_perms(JournalFile *f, uid_t uid) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington acl_t acl;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington acl_entry_t entry;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington acl_permset_t permset;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int r;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(f);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence r = fchmod_and_fchown(f->fd, 0640, 0, 0);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_warning("Failed to fix access mode/rights on %s, ignoring: %s", f->path, strerror(-r));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (uid <= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington acl = acl_get_fd(f->fd);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!acl) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_warning("Failed to read ACL on %s, ignoring: %m", f->path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = acl_find_uid(acl, uid, &entry);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r <= 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (acl_create_entry(&acl, &entry) < 0 ||
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington acl_set_tag_type(entry, ACL_USER) < 0 ||
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington acl_set_qualifier(entry, &uid) < 0) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence goto finish;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (acl_get_permset(entry, &permset) < 0 ||
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington acl_add_perm(permset, ACL_READ) < 0 ||
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington acl_calc_mask(&acl) < 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington goto finish;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (acl_set_fd(f->fd, acl) < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_warning("Failed to set ACL on %s, ignoring: %m", f->path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonfinish:
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington acl_free(acl);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic JournalFile* find_journal(Server *s, uid_t uid) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char *p;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int r;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington JournalFile *f;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char ids[33];
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington sd_id128_t machine;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(s);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* We split up user logs only on /var, not on /run. If the
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * runtime file is open, we write to it exclusively, in order
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * to guarantee proper order as soon as we flush /run to
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * /var and close the runtime file. */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->runtime_journal)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return s->runtime_journal;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (uid <= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return s->system_journal;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = sd_id128_get_machine(&machine);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return s->system_journal;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington f = hashmap_get(s->user_journals, UINT32_TO_PTR(uid));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (f)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return f;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&p, "/var/log/journal/%s/user-%lu.journal", sd_id128_to_string(machine, ids), (unsigned long) uid) < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return s->system_journal;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington while (hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* Too many open? Then let's close one */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington f = hashmap_steal_first(s->user_journals);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(f);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington journal_file_close(f);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = journal_file_open(p, O_RDWR|O_CREAT, 0640, s->system_journal, &f);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(p);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return s->system_journal;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington fix_perms(f, uid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington f->metrics = s->system_metrics;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington f->compress = s->compress;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r < 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington journal_file_close(f);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return s->system_journal;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return f;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic void server_rotate(Server *s) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington JournalFile *f;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington void *k;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington Iterator i;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int r;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_info("Rotating...");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->runtime_journal) {
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington r = journal_file_rotate(&s->runtime_journal);
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington if (r < 0)
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington log_error("Failed to rotate %s: %s", s->runtime_journal->path, strerror(-r));
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington }
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington if (s->system_journal) {
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington r = journal_file_rotate(&s->system_journal);
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington if (r < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_error("Failed to rotate %s: %s", s->system_journal->path, strerror(-r));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = journal_file_rotate(&f);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_error("Failed to rotate %s: %s", f->path, strerror(-r));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington else
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington hashmap_replace(s->user_journals, k, f);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic void server_vacuum(Server *s) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char *p;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char ids[33];
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington sd_id128_t machine;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int r;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_info("Vacuuming...");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = sd_id128_get_machine(&machine);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r < 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_error("Failed to get machine ID: %s", strerror(-r));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington sd_id128_to_string(machine, ids);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington if (s->system_journal) {
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington if (asprintf(&p, "/var/log/journal/%s", ids) < 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_error("Out of memory.");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r < 0 && r != -ENOENT)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_error("Failed to vacuum %s: %s", p, strerror(-r));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(p);
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley }
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley if (s->runtime_journal) {
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley if (asprintf(&p, "/run/log/journal/%s", ids) < 0) {
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley log_error("Out of memory.");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington
091329e690b20755aa80b86cc7389d25c5d32c9bBrian Wellington r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r < 0 && r != -ENOENT)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_error("Failed to vacuum %s: %s", p, strerror(-r));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(p);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington s->cached_available_space_timestamp = 0;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic char *shortened_cgroup_path(pid_t pid) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int r;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char *process_path, *init_path, *path;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(pid > 0);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &process_path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return NULL;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &init_path);
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington if (r < 0) {
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington free(process_path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return NULL;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (endswith(init_path, "/system"))
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington init_path[strlen(init_path) - 7] = 0;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington else if (streq(init_path, "/"))
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington init_path[0] = 0;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (startswith(process_path, init_path)) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char *p;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington p = strdup(process_path + strlen(init_path));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!p) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(process_path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(init_path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return NULL;
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington }
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington path = p;
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington } else {
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington path = process_path;
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington process_path = NULL;
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington }
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington free(process_path);
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington free(init_path);
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington return path;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic void dispatch_message_real(Server *s,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct iovec *iovec, unsigned n, unsigned m,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct ucred *ucred,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct timeval *tv) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char *pid = NULL, *uid = NULL, *gid = NULL,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington *source_time = NULL, *boot_id = NULL, *machine_id = NULL,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington *comm = NULL, *cmdline = NULL, *hostname = NULL,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington *audit_session = NULL, *audit_loginuid = NULL,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington *exe = NULL, *cgroup = NULL, *session = NULL,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington *owner_uid = NULL, *unit = NULL;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char idbuf[33];
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington sd_id128_t id;
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley int r;
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley char *t;
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley uid_t loginuid = 0, realuid = 0;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington JournalFile *f;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington bool vacuumed = false;
02d8e643ea6679beff181a2b2b3946b8fe014fecAndreas Gustafsson
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(s);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(iovec);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(n > 0);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(n + N_IOVEC_META_FIELDS <= m);
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley if (ucred) {
3e9b51fc7b2d12c88298f5b777f9075feb52f071Bob Halley uint32_t audit;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington uid_t owner;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington realuid = ucred->uid;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&pid, "_PID=%lu", (unsigned long) ucred->pid) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], pid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
02d8e643ea6679beff181a2b2b3946b8fe014fecAndreas Gustafsson if (asprintf(&uid, "_UID=%lu", (unsigned long) ucred->uid) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], uid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&gid, "_GID=%lu", (unsigned long) ucred->gid) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], gid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = get_process_comm(ucred->pid, &t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r >= 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington comm = strappend("_COMM=", t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (comm)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], comm);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = get_process_exe(ucred->pid, &t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r >= 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington exe = strappend("_EXE=", t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (comm)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], exe);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = get_process_cmdline(ucred->pid, LINE_MAX, false, &t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r >= 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington cmdline = strappend("_CMDLINE=", t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (cmdline)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], cmdline);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = audit_session_from_pid(ucred->pid, &audit);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&audit_session, "_AUDIT_SESSION=%lu", (unsigned long) audit) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], audit_session);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = audit_loginuid_from_pid(ucred->pid, &loginuid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&audit_loginuid, "_AUDIT_LOGINUID=%lu", (unsigned long) loginuid) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], audit_loginuid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington t = shortened_cgroup_path(ucred->pid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (t) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington cgroup = strappend("_SYSTEMD_CGROUP=", t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (cgroup)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], cgroup);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (sd_pid_get_session(ucred->pid, &t) >= 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington session = strappend("_SYSTEMD_SESSION=", t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (session)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], session);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (sd_pid_get_unit(ucred->pid, &t) >= 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington unit = strappend("_SYSTEMD_UNIT=", t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (unit)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], unit);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (sd_pid_get_owner_uid(ucred->uid, &owner) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&owner_uid, "_SYSTEMD_OWNER_UID=%lu", (unsigned long) owner) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], owner_uid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (tv) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&source_time, "_SOURCE_REALTIME_TIMESTAMP=%llu",
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington (unsigned long long) timeval_load(tv)) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], source_time);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* Note that strictly speaking storing the boot id here is
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * redundant since the entry includes this in-line
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * anyway. However, we need this indexed, too. */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = sd_id128_get_boot(&id);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&boot_id, "_BOOT_ID=%s", sd_id128_to_string(id, idbuf)) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], boot_id);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = sd_id128_get_machine(&id);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&machine_id, "_MACHINE_ID=%s", sd_id128_to_string(id, idbuf)) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], machine_id);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington t = gethostname_malloc();
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (t) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington hostname = strappend("_HOSTNAME=", t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(t);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (hostname)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], hostname);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(n <= m);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington server_flush_to_var(s);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonretry:
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington f = find_journal(s, realuid == 0 ? 0 : loginuid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!f)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_warning("Dropping message, as we can't find a place to store the data.");
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson else {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r == -E2BIG && !vacuumed) {
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson log_info("Allocation limit reached.");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington server_rotate(s);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington server_vacuum(s);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington vacuumed = true;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_info("Retrying write.");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington goto retry;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (r < 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_error("Failed to write entry, ignoring: %s", strerror(-r));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(pid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(uid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(gid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(comm);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(exe);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(cmdline);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(source_time);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(boot_id);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(machine_id);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(hostname);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(audit_session);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(audit_loginuid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(cgroup);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(session);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(owner_uid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(unit);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic void driver_message(Server *s, sd_id128_t message_id, const char *format, ...) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char mid[11 + 32 + 1];
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char buffer[16 + LINE_MAX + 1];
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct iovec iovec[N_IOVEC_META_FIELDS + 3];
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int n = 0;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington va_list ap;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence struct ucred ucred;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(s);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(format);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], "PRIORITY=5");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington memcpy(buffer, "MESSAGE=", 8);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington va_start(ap, format);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington vsnprintf(buffer + 8, sizeof(buffer) - 8, format, ap);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington va_end(ap);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char_array_0(buffer);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], buffer);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington snprintf(mid, sizeof(mid), "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(message_id));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char_array_0(mid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], mid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington zero(ucred);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington ucred.pid = getpid();
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington ucred.uid = getuid();
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington ucred.gid = getgid();
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic void dispatch_message(Server *s,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct iovec *iovec, unsigned n, unsigned m,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct ucred *ucred,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct timeval *tv,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int priority) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int rl;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char *path = NULL, *c;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(s);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(iovec || n == 0);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (n == 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!ucred)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington goto finish;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington path = shortened_cgroup_path(ucred->pid);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!path)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington goto finish;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* example: /user/lennart/3/foobar
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * /system/dbus.service/foobar
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington *
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * So let's cut of everything past the third /, since that is
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * wher user directories start */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington c = strchr(path, '/');
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (c) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington c = strchr(c+1, '/');
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (c) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington c = strchr(c+1, '/');
6e0e723b2554ba1c4af8b79733f54bf2692cdecfAndreas Gustafsson if (c)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington *c = 0;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington rl = journal_rate_limit_test(s->rate_limit, path, priority & LOG_PRIMASK, available_space(s));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (rl == 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* Write a suppression message if we suppressed something */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (rl > 1)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington driver_message(s, SD_MESSAGE_JOURNAL_DROPPED, "Suppressed %u messages from %s", rl - 1, path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonfinish:
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington dispatch_message_real(s, iovec, n, m, ucred, tv);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct msghdr msghdr;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct cmsghdr *cmsg;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington union {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct cmsghdr cmsghdr;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington } control;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington union sockaddr_union sa;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(s);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(iovec);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(n_iovec > 0);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington zero(msghdr);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington msghdr.msg_iov = (struct iovec*) iovec;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington msghdr.msg_iovlen = n_iovec;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington zero(sa);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington sa.un.sun_family = AF_UNIX;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington strncpy(sa.un.sun_path, "/run/systemd/journal/syslog", sizeof(sa.un.sun_path));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington msghdr.msg_name = &sa;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington msghdr.msg_namelen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (ucred) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington zero(control);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington msghdr.msg_control = &control;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington msghdr.msg_controllen = sizeof(control);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington cmsg = CMSG_FIRSTHDR(&msghdr);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington cmsg->cmsg_level = SOL_SOCKET;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington cmsg->cmsg_type = SCM_CREDENTIALS;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington memcpy(CMSG_DATA(cmsg), ucred, sizeof(struct ucred));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington msghdr.msg_controllen = cmsg->cmsg_len;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* Forward the syslog message we received via /dev/log to
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * /run/systemd/syslog. Unfortunately we currently can't set
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * the SO_TIMESTAMP auxiliary data, and hence we don't. */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (ucred && errno == ESRCH) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence struct ucred u;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Hmm, presumably the sender process vanished
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence * by now, so let's fix it as good as we
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence * can, and retry */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence u = *ucred;
11c4f6b687564cdda8a0a38745e30a12e874084aDavid Lawrence u.pid = getpid();
11c4f6b687564cdda8a0a38745e30a12e874084aDavid Lawrence memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred));
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
11c4f6b687564cdda8a0a38745e30a12e874084aDavid Lawrence return;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence log_debug("Failed to forward syslog message: %m");
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence}
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrencestatic void forward_syslog_raw(Server *s, const char *buffer, struct ucred *ucred, struct timeval *tv) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence struct iovec iovec;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(s);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(buffer);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec, buffer);
0eace215bd758e347767c63c13504520e855b94aAndreas Gustafsson forward_syslog_iovec(s, &iovec, 1, ucred, tv);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence}
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrencestatic void forward_syslog(Server *s, int priority, const char *tag, const char *message, struct ucred *ucred, struct timeval *tv) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence struct iovec iovec[5];
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char header_priority[6], header_time[64], header_pid[16];
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence int n = 0;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence time_t t;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence struct tm *tm;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char *tag_buf = NULL;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(s);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(priority >= 0);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(priority <= 999);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(message);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* First: priority field */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence snprintf(header_priority, sizeof(header_priority), "<%i>", priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char_array_0(header_priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], header_priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Second: timestamp */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC));
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence tm = localtime(&t);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (!tm)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], header_time);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Third: tag and PID */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (ucred) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (!tag) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence get_process_comm(ucred->pid, &tag_buf);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence tag = tag_buf;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char_array_0(header_pid);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (tag)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], tag);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], header_pid);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence } else if (tag) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], tag);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], ": ");
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Fourth: message */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], message);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence forward_syslog_iovec(s, iovec, n, ucred, tv);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence free(tag_buf);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence}
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrencestatic int fixup_priority(int priority) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if ((priority & LOG_FACMASK) == 0)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return (priority & LOG_PRIMASK) | LOG_USER;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return priority;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence}
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrencestatic void forward_kmsg(Server *s, int priority, const char *tag, const char *message, struct ucred *ucred) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence struct iovec iovec[5];
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char header_priority[6], header_pid[16];
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence int n = 0;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char *tag_buf = NULL;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence int fd;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(s);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(priority >= 0);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(priority <= 999);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(message);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Never allow messages with kernel facility to be written to
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence * kmsg, regardless where the data comes from. */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence priority = fixup_priority(priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* First: priority field */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence snprintf(header_priority, sizeof(header_priority), "<%i>", priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char_array_0(header_priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], header_priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Second: tag and PID */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (ucred) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (!tag) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence get_process_comm(ucred->pid, &tag_buf);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence tag = tag_buf;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char_array_0(header_pid);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (tag)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], tag);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], header_pid);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence } else if (tag) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], tag);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], ": ");
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Fourth: message */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], message);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], "\n");
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (fd < 0) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence log_debug("Failed to open /dev/kmsg for logging: %s", strerror(errno));
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence goto finish;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (writev(fd, iovec, n) < 0)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence log_debug("Failed to write to /dev/kmsg for logging: %s", strerror(errno));
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence close_nointr_nofail(fd);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrencefinish:
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence free(tag_buf);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence}
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrencestatic void forward_console(Server *s, const char *tag, const char *message, struct ucred *ucred) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence struct iovec iovec[4];
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char header_pid[16];
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence int n = 0, fd;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char *tag_buf = NULL;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(s);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(message);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* First: tag and PID */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (ucred) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (!tag) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence get_process_comm(ucred->pid, &tag_buf);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence tag = tag_buf;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char_array_0(header_pid);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (tag)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], tag);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], header_pid);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence } else if (tag) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], tag);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], ": ");
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Third: message */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], message);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], "\n");
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (fd < 0) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence log_debug("Failed to open /dev/console for logging: %s", strerror(errno));
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence goto finish;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (writev(fd, iovec, n) < 0)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence log_debug("Failed to write to /dev/console for logging: %s", strerror(errno));
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence close_nointr_nofail(fd);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrencefinish:
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence free(tag_buf);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence}
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrencestatic void read_tag(const char **buf, char **tag) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence const char *p;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char *t;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence size_t l, e;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(buf);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(tag);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence p = *buf;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence p += strspn(p, WHITESPACE);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence l = strcspn(p, WHITESPACE);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (l <= 0 ||
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence p[l-1] != ':')
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence e = l;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence l--;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (p[l-1] == ']') {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence size_t k = l-1;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence for (;;) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (p[k] == '[') {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence l = k;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence break;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (k == 0)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence break;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence k--;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence t = strndup(p, l);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (t)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence *tag = t;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence *buf = p + e;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence *buf += strspn(*buf, WHITESPACE);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence}
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrencestatic void process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_tag = NULL;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence struct iovec iovec[N_IOVEC_META_FIELDS + 4];
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence unsigned n = 0;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence int priority = LOG_USER | LOG_INFO;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char *tag = NULL;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(s);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(buf);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (s->forward_to_syslog)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence forward_syslog_raw(s, buf, ucred, tv);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence parse_syslog_priority((char**) &buf, &priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence skip_syslog_date((char**) &buf);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence read_tag(&buf, &tag);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (s->forward_to_kmsg)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence forward_kmsg(s, priority, tag, buf, ucred);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (s->forward_to_console)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence forward_console(s, tag, buf, ucred);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], syslog_priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (priority & LOG_FACMASK)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence IOVEC_SET_STRING(iovec[n++], syslog_facility);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (tag) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence syslog_tag = strappend("SYSLOG_TAG=", tag);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (syslog_tag)
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson IOVEC_SET_STRING(iovec[n++], syslog_tag);
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington message = strappend("MESSAGE=", buf);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (message)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], message);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(message);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(tag);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence free(syslog_priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence free(syslog_facility);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(syslog_tag);
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic bool valid_user_field(const char *p, size_t l) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington const char *a;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* We kinda enforce POSIX syntax recommendations for
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington environment variables here, but make a couple of additional
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington requirements.
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* No empty field names */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (l <= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return false;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Don't allow names longer than 64 chars */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (l > 64)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return false;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Variables starting with an underscore are protected */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (p[0] == '_')
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return false;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Don't allow digits as first character */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (p[0] >= '0' && p[0] <= '9')
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return false;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Only allow A-Z0-9 and '_' */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence for (a = p; a < p + l; a++)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (!((*a >= 'A' && *a <= 'Z') ||
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence (*a >= '0' && *a <= '9') ||
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence *a == '_'))
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return false;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return true;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence}
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrencestatic void process_native_message(Server *s, const void *buffer, size_t buffer_size, struct ucred *ucred, struct timeval *tv) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence struct iovec *iovec = NULL;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence unsigned n = 0, m = 0, j;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence const char *p;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence size_t remaining;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence int priority = LOG_INFO;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char *tag = NULL, *message = NULL;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(s);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence assert(buffer || n == 0);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence p = buffer;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence remaining = buffer_size;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence while (remaining > 0) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence const char *e, *q;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence e = memchr(p, '\n', remaining);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (!e) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Trailing noise, let's ignore it, and flush what we collected */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence log_debug("Received message with trailing noise, ignoring.");
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence break;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (e == p) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence /* Entry separator */
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence dispatch_message(s, iovec, n, m, ucred, tv, priority);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence n = 0;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence priority = LOG_INFO;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington p++;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington remaining--;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington continue;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (*p == '.' || *p == '#') {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* Ignore control commands for now, and
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * comments too. */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington remaining -= (e - p) + 1;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington p = e + 1;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington continue;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* A property follows */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (n+N_IOVEC_META_FIELDS >= m) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct iovec *c;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington unsigned u;
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington u = MAX((n+N_IOVEC_META_FIELDS) * 2U, 4U);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington c = realloc(iovec, u * sizeof(struct iovec));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!c) {
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson log_error("Out of memory");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington break;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence iovec = c;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington m = u;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington q = memchr(p, '=', e - p);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (q) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (valid_user_field(p, q - p)) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington size_t l;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington l = e - p;
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* If the field name starts with an
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson * underscore, skip the variable,
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * since that indidates a trusted
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * field */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington iovec[n].iov_base = (char*) p;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington iovec[n].iov_len = l;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington n++;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington /* We need to determine the priority
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * of this entry for the rate limiting
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington * logic */
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (l == 10 &&
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington memcmp(p, "PRIORITY=", 9) == 0 &&
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington p[9] >= '0' && p[9] <= '9')
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington priority = (priority & LOG_FACMASK) | (p[9] - '0');
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington else if (l == 17 &&
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington memcmp(p, "SYSLOG_FACILITY=", 16) == 0 &&
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington p[16] >= '0' && p[16] <= '9')
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington else if (l == 18 &&
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington memcmp(p, "SYSLOG_FACILITY=", 16) == 0 &&
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence p[16] >= '0' && p[16] <= '9' &&
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence p[17] >= '0' && p[17] <= '9')
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence else if (l >= 12 &&
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence memcmp(p, "SYSLOG_TAG=", 11) == 0) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence char *t;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence t = strndup(p + 11, l - 11);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (t) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence free(tag);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence tag = t;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence } else if (l >= 8 &&
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence memcmp(p, "MESSAGE=", 8) == 0) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char *t;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington t = strndup(p + 8, l - 8);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (t) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(message);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington message = t;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington remaining -= (e - p) + 1;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington p = e + 1;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington continue;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington } else {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington uint64_t l;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char *k;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_debug("Failed to parse message, ignoring.");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington break;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington memcpy(&l, e + 1, sizeof(uint64_t));
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington l = le64toh(l);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington e[1+sizeof(uint64_t)+l] != '\n') {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_debug("Failed to parse message, ignoring.");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington break;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington k = malloc((e - p) + 1 + l);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!k) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_error("Out of memory");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington break;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington memcpy(k, p, e - p);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington k[e - p] = '=';
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (valid_user_field(p, e - p)) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington iovec[n].iov_base = k;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington iovec[n].iov_len = (e - p) + 1 + l;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington n++;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington } else
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(k);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington p = e + 1 + sizeof(uint64_t) + l + 1;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson if (message) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->forward_to_syslog)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington forward_syslog(s, priority, tag, message, ucred, tv);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->forward_to_kmsg)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington forward_kmsg(s, priority, tag, message, ucred);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->forward_to_console)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington forward_console(s, tag, message, ucred);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
6e0e723b2554ba1c4af8b79733f54bf2692cdecfAndreas Gustafsson dispatch_message(s, iovec, n, m, ucred, tv, priority);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington for (j = 0; j < n; j++)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (iovec[j].iov_base < buffer ||
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(iovec[j].iov_base);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(tag);
6e0e723b2554ba1c4af8b79733f54bf2692cdecfAndreas Gustafsson free(message);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic int stdout_stream_log(StdoutStream *s, const char *p) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington struct iovec iovec[N_IOVEC_META_FIELDS + 4];
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_tag = NULL;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington unsigned n = 0;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence int priority;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(s);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(p);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington priority = s->priority;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->priority_prefix)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington parse_syslog_priority((char**) &p, &priority);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->forward_to_syslog || s->server->forward_to_syslog)
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence forward_syslog(s->server, fixup_priority(priority), s->tag, p, &s->ucred, NULL);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->forward_to_kmsg || s->server->forward_to_kmsg)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington forward_kmsg(s->server, priority, s->tag, p, &s->ucred);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->forward_to_console || s->server->forward_to_console)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington forward_console(s->server, s->tag, p, &s->ucred);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], syslog_priority);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (priority & LOG_FACMASK)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], syslog_facility);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (s->tag) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington syslog_tag = strappend("SYSLOG_TAG=", s->tag);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (syslog_tag)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], syslog_tag);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington message = strappend("MESSAGE=", p);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (message)
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington IOVEC_SET_STRING(iovec[n++], message);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, priority);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(message);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(syslog_priority);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(syslog_facility);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington free(syslog_tag);
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return 0;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington}
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellingtonstatic int stdout_stream_line(StdoutStream *s, char *p) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington int r;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington assert(s);
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence assert(p);
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington p = strstrip(p);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington switch (s->state) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence case STDOUT_STREAM_TAG:
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington s->tag = strdup(p);
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington if (!s->tag) {
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington log_error("Out of memory");
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return -ENOMEM;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington s->state = STDOUT_STREAM_PRIORITY;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return 0;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence case STDOUT_STREAM_PRIORITY:
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence r = safe_atoi(p, &s->priority);
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence if (r < 0 || s->priority <= 0 || s->priority >= 999) {
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence log_warning("Failed to parse log priority line.");
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence return -EINVAL;
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence }
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence s->state = STDOUT_STREAM_PRIORITY_PREFIX;
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence return 0;
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence case STDOUT_STREAM_PRIORITY_PREFIX:
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence r = parse_boolean(p);
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence if (r < 0) {
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence log_warning("Failed to parse priority prefix line.");
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence return -EINVAL;
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence }
1f7342e0989d9f9063b0e757cf7091668addfdb5David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence s->priority_prefix = !!r;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence return 0;
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence case STDOUT_STREAM_FORWARD_TO_SYSLOG:
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence r = parse_boolean(p);
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence if (r < 0) {
7332e47e11ceb87928f801b925269aa6a91838b1David Lawrence log_warning("Failed to parse forward to syslog line.");
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington return -EINVAL;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington }
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson s->forward_to_syslog = !!r;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson return 0;
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson case STDOUT_STREAM_FORWARD_TO_KMSG:
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson r = parse_boolean(p);
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson if (r < 0) {
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson log_warning("Failed to parse copy to kmsg line.");
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson return -EINVAL;
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson }
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington s->forward_to_kmsg = !!r;
1b4e6163bed546ca7f8ad186f3eabfebacc36bc1Brian Wellington s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson return 0;
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson case STDOUT_STREAM_FORWARD_TO_CONSOLE:
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson r = parse_boolean(p);
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson if (r < 0) {
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson log_warning("Failed to parse copy to console line.");
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson return -EINVAL;
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson }
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson
532989b206894bdaf6de6cb883d2e31169c4bfacAndreas Gustafsson 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 = sizeof(s->buffer) - 1;
} 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);
}
free(s->tag);
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;
}
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 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(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;
fix_perms(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(fn, 0755);
r = journal_file_open(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;
fix_perms(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;
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 process_event(Server *s, struct epoll_event *ev) {
assert(s);
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 0;
return -errno;
}
if (sfsi.ssi_signo == SIGUSR1) {
server_flush_to_var(s);
return 0;
}
log_debug("Received SIG%s", signal_to_string(sfsi.ssi_signo));
return 0;
} 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;
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
CMSG_SPACE(sizeof(struct timeval))];
} control;
ssize_t n;
int v;
if (ioctl(ev->data.fd, SIOCINQ, &v) < 0) {
log_error("SIOCINQ failed: %m");
return -errno;
}
if (v <= 0)
return 1;
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);
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 == SO_TIMESTAMP &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
tv = (struct timeval*) CMSG_DATA(cmsg);
}
if (ev->data.fd == s->syslog_fd) {
char *e;
e = memchr(s->buffer, '\n', n);
if (e)
*e = 0;
else
s->buffer[n] = 0;
process_syslog_message(s, strstrip(s->buffer), ucred, tv);
} else
process_native_message(s, s->buffer, n, ucred, tv);
}
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;
struct timeval tv;
assert(s);
if (s->syslog_fd < 0) {
s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 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);
}
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;
}
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;
}
/* Since we use the same socket for forwarding this to some
* other syslog implementation, make sure we don't hang
* forever */
timeval_store(&tv, SYSLOG_TIMEOUT_USEC);
if (setsockopt(s->syslog_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
log_error("SO_SNDTIMEO 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, 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);
}
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;
}
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, 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;
}
}
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_signalfd(Server *s) {
sigset_t mask;
struct epoll_event ev;
assert(s);
assert_se(sigemptyset(&mask) == 0);
sigset_add_many(&mask, SIGINT, SIGTERM, SIGUSR1, -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_config_file(Server *s) {
FILE *f;
const char *fn;
int r;
assert(s);
fn = "/etc/systemd/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 = -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;
memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics));
memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics));
server_parse_config_file(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 = system_journal_open(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;
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->rate_limit)
journal_rate_limit_free(s->rate_limit);
free(s->buffer);
}
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_CONSOLE);
log_parse_environment();
log_open();
umask(0022);
r = server_init(&server);
if (r < 0)
goto finish;
server_vacuum(&server);
server_flush_to_var(&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;
}