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