Compare commits

...

52 Commits

Author SHA1 Message Date
Yu Watanabe af06ddf51a meson, man: do not install pam_systemd_home(8) when pam or homed is disabled
Fixes #14725.
2020-02-01 12:13:45 +01:00
Frantisek Sumsal 2273ecfeda test: don't install /etc/securetty
Having /etc/securetty in test containers prevents root from logging into
them:

```
Jan 31 10:15:11 systemd-testsuite login[69]: pam_securetty(login:auth): access denied: tty 'pts/0' is not secure !
Jan 31 10:15:11 systemd-testsuite login[69]: FAILED LOGIN 1 FROM pts/0 FOR root, Authentication failure
```
2020-02-01 11:55:17 +01:00
Lennart Poettering 5ee69e144e
Merge pull request #14178 from poettering/journal-namespace
journal: add concept of "journal namespaces"
2020-02-01 11:25:48 +01:00
Lennart Poettering ad23785246 update TODO 2020-01-31 15:10:40 +01:00
Lennart Poettering 2b6b8bd3f7 man: document --namespace= switch of journalctl 2020-01-31 15:10:40 +01:00
Lennart Poettering 241c8f67f6 man: document the new sd_journal_open_namespace() API 2020-01-31 15:10:40 +01:00
Lennart Poettering 5b0a76d107 man: document LogNamespace= unit setting 2020-01-31 15:10:40 +01:00
Lennart Poettering 7d8155b3df man: document new _NAMESPACE= journal field 2020-01-31 15:10:40 +01:00
Lennart Poettering 6bc4361997 man: document journald@NAMESPACE.conf 2020-01-31 15:10:40 +01:00
Lennart Poettering efcbcd0d04 man: document journald namespaces 2020-01-31 15:10:40 +01:00
Lennart Poettering 23d8c56046 journalctl: underline sections in --help 2020-01-31 15:10:40 +01:00
Lennart Poettering 340cb115b3 units: define RuntimeDirectory= in systemd-journald.service
It doesn't get us much, but makes the differences between the templated
and non-templated versions a bit smaller.
2020-01-31 15:04:24 +01:00
Lennart Poettering 5591cd4e20 units: sort settings in systemd-journald.service again 2020-01-31 15:04:15 +01:00
Lennart Poettering fb38a7beb8 tmpfiles: apply ACLs to top-level journal directory in /run, too
We already apply them to the directory in /var. Let's do the same in
/run too. That's because due to the log namespace logic we nowadays can
gain additional subdirs there during regular operation.
2020-01-31 15:04:12 +01:00
Lennart Poettering 0f5a4f9cd9 tmpfiles: merge lines for the same inodes 2020-01-31 15:04:08 +01:00
Lennart Poettering db23d83bd4 test: add simple test for log namespaces 2020-01-31 15:04:05 +01:00
Lennart Poettering dc5437c78b journald: add ability to activate by varlink socket
If we have exit on idle, then operations such as "journalctl
--namespace=foo --rotate" should work even if the journal daemon is
currently not running.

(Note that we don't do activation by varlink for the main instance of
journald, I am not sure the deadlocks it might introduce are worth it)
2020-01-31 15:03:55 +01:00
Lennart Poettering 65c398c031 journald: add exit on idle 2020-01-31 15:03:44 +01:00
Lennart Poettering 6d4d600260 varlink: add ability to register callback for disconnections 2020-01-31 15:03:27 +01:00
Lennart Poettering c4f601f205 varlink: add API for determining number of current connections 2020-01-31 15:03:11 +01:00
Lennart Poettering d98580e438 journald: use structured initialization 2020-01-31 15:03:07 +01:00
Lennart Poettering 2435269171 journald: add logging for one error we lacked logging for 2020-01-31 15:03:04 +01:00
Lennart Poettering d93dda3afe systemctl: show logs for correct namespace of service 2020-01-31 15:02:52 +01:00
Lennart Poettering 21fa231ece journalctl: drop misplaced empty line 2020-01-31 15:02:48 +01:00
Lennart Poettering 6b25db87a1 journalctl: add new --namespace= switch for showing logs for namespace 2020-01-31 15:02:45 +01:00
Lennart Poettering 31e99dd2cc journal: make constant argument actually 'const' 2020-01-31 15:02:41 +01:00
Lennart Poettering 456aa87906 journal: allow opening journal files specific to some namespace 2020-01-31 15:02:29 +01:00
Lennart Poettering 2f5435a147 journal: use structured initialization 2020-01-31 15:02:25 +01:00
Lennart Poettering 33ff74643e journalctl: use an anonymous array when an array is needed
I am pretty sure this makes things more readable, since the expected
argument here is actually an array.
2020-01-31 15:02:22 +01:00
Lennart Poettering 68312977db journal: properly mark two definitions that are deprecated with GCC attributes for that 2020-01-31 15:02:00 +01:00
Lennart Poettering e7238caf0c journalctl: use automatic memory cleanup 2020-01-31 15:01:57 +01:00
Lennart Poettering 0491150b5c journalctl: use log_error_errno() wherever we can 2020-01-31 15:01:53 +01:00
Lennart Poettering a6214d9643 journalctl: move pcre function code down
We usually put the static arguments at the top of each source files, do
so here too, and thus move the first code down.
2020-01-31 15:01:50 +01:00
Lennart Poettering 91dd5f7cbe core: add new LogNamespace= execution setting 2020-01-31 15:01:43 +01:00
Lennart Poettering 839d1b2014 string-util: add brief explanatory comment 2020-01-31 15:01:39 +01:00
Lennart Poettering 1ee51fbd70 units: add unit files for instantiated journal daemons 2020-01-31 15:01:30 +01:00
Lennart Poettering b1852c48c1 journald: allow running multiple instances of journald
If we do, we operate on a separate set of logs and runtime objects

The namespace is configured via argv[1].

Fixes: #12123

Fixes: #10230 #9519

(These latter two issues ask for slightly different stuff, but the
usecases generally can be solved by running separate instances of
journald now, hence also declaring that as "Fixes:")
2020-01-31 15:01:18 +01:00
Lennart Poettering d6f46470f5 journald: when create journal directories use calculated paths 2020-01-31 15:01:14 +01:00
Lennart Poettering 4f60310373 journald: minor coding style updates 2020-01-31 15:01:09 +01:00
Lennart Poettering 4e00337b16 journald: let's simplify rotating of offline user journals
Let's just use the path that is already stored in JournalStorage,
instead of generating our own. While we are at it, split out the loop
into its own function.
2020-01-31 15:01:05 +01:00
Lennart Poettering 46e2348a58 journald: simplify find_journal() a bit
Let's use the already precalculated persistent storage path instead of
deriving it again from the machine ID.
2020-01-31 15:01:01 +01:00
Lennart Poettering b42b9479a8 journald: hide current storage determination in helper call 2020-01-31 15:00:57 +01:00
Lennart Poettering 74dd8f5759 journald: use structured initialization 2020-01-31 15:00:53 +01:00
Lennart Poettering 8548f4f09b journald: line break overly long function header 2020-01-31 15:00:49 +01:00
Lennart Poettering 7e7ef3bfb2 journald: let's use TAKE_PTR() and TAKE_FD() where appropriate 2020-01-31 15:00:45 +01:00
Lennart Poettering a30e35f85a journald: let's use unlink_and_free() where we can 2020-01-31 15:00:41 +01:00
Lennart Poettering 2066f4fe30 journald: specifying _pure_ on static functions is unnecessary, compiler can figure that out on its own 2020-01-31 15:00:37 +01:00
Lennart Poettering a2735a4549 journald: don't bother with seqnum file if we don't read form /dev/kmsg anyway 2020-01-31 15:00:33 +01:00
Lennart Poettering dbac262578 journald: fix indentation 2020-01-31 15:00:29 +01:00
Lennart Poettering 99d0d05a10 journald: use free_and_replace() where appropriate 2020-01-31 15:00:25 +01:00
Lennart Poettering 659a77bec6 journald: add missing logging for some errors 2020-01-31 15:00:21 +01:00
Lennart Poettering d83f7e4c92 journald: why bitwise XOR when boolean != is easier to read? 2020-01-31 14:59:41 +01:00
62 changed files with 1390 additions and 473 deletions

5
TODO
View File

@ -894,11 +894,6 @@ Features:
- journald: when we drop syslog messages because the syslog socket is - journald: when we drop syslog messages because the syslog socket is
full, make sure to write how many messages are lost as first thing full, make sure to write how many messages are lost as first thing
to syslog when it works again. to syslog when it works again.
- change systemd-journal-flush into a service that stays around during
boot, and causes the journal to be moved back to /run on shutdown,
so that we do not keep /var busy. This needs to happen synchronously,
hence doing this via signals is not going to work.
- optionally support running journald from the command line for testing purposes in external projects
- journald: allow per-priority and per-service retention times when rotating/vacuuming - journald: allow per-priority and per-service retention times when rotating/vacuuming
- journald: make use of uid-range.h to managed uid ranges to split - journald: make use of uid-range.h to managed uid ranges to split
journals in. journals in.

View File

@ -749,6 +749,18 @@
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--namespace=<replaceable>NAMESPACE</replaceable></option></term>
<listitem><para>Takes a journal namespace identifier string as argument. If not specified the data
collected by the default namespace is shown. If specified shows the log data of the specified
namespace instead. If the namespace is specified as <literal>*</literal> data from all namespaces is
shown, interleaved. If the namespace identifier is prefixed with <literal>+</literal> data from the
specified namespace and the default namespace is shown, interleaved, but no other. For details about
journal namespaces see
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>--header</option></term> <term><option>--header</option></term>

View File

@ -18,6 +18,7 @@
<refnamediv> <refnamediv>
<refname>journald.conf</refname> <refname>journald.conf</refname>
<refname>journald.conf.d</refname> <refname>journald.conf.d</refname>
<refname>journald@.conf</refname>
<refpurpose>Journal service configuration files</refpurpose> <refpurpose>Journal service configuration files</refpurpose>
</refnamediv> </refnamediv>
@ -26,6 +27,7 @@
<para><filename>/etc/systemd/journald.conf.d/*.conf</filename></para> <para><filename>/etc/systemd/journald.conf.d/*.conf</filename></para>
<para><filename>/run/systemd/journald.conf.d/*.conf</filename></para> <para><filename>/run/systemd/journald.conf.d/*.conf</filename></para>
<para><filename>/usr/lib/systemd/journald.conf.d/*.conf</filename></para> <para><filename>/usr/lib/systemd/journald.conf.d/*.conf</filename></para>
<para><filename>/etc/systemd/journald@<replaceable>NAMESPACE</replaceable>.conf</filename></para>
</refsynopsisdiv> </refsynopsisdiv>
<refsect1> <refsect1>
@ -37,6 +39,12 @@
<citerefentry><refentrytitle>systemd.syntax</refentrytitle><manvolnum>5</manvolnum></citerefentry> <citerefentry><refentrytitle>systemd.syntax</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for a general description of the syntax.</para> for a general description of the syntax.</para>
<para>The <command>systemd-journald</command> instance managing the default namespace is configured by
<filename>/etc/systemd/journald.conf</filename> and associated drop-ins. Instances managing other
namespaces read <filename>/etc/systemd/journald@<replaceable>NAMESPACE</replaceable>.conf</filename> with
the namespace identifier filled in. This allows each namespace to carry a distinct configuration. See
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for details about journal namespaces.</para>
</refsect1> </refsect1>
<xi:include href="standard-conf.xml" xpointer="main-conf" /> <xi:include href="standard-conf.xml" xpointer="main-conf" />
@ -52,29 +60,19 @@
<varlistentry> <varlistentry>
<term><varname>Storage=</varname></term> <term><varname>Storage=</varname></term>
<listitem><para>Controls where to store journal data. One of <listitem><para>Controls where to store journal data. One of <literal>volatile</literal>,
<literal>volatile</literal>, <literal>persistent</literal>, <literal>auto</literal> and <literal>none</literal>. If
<literal>persistent</literal>, <literal>volatile</literal>, journal log data will be stored only in memory, i.e. below the
<literal>auto</literal> and <filename>/run/log/journal</filename> hierarchy (which is created if needed). If
<literal>none</literal>. If <literal>persistent</literal>, data will be stored preferably on disk, i.e. below the
<literal>volatile</literal>, journal <filename>/var/log/journal</filename> hierarchy (which is created if needed), with a fallback to
log data will be stored only in memory, i.e. below the <filename>/run/log/journal</filename> (which is created if needed), during early boot and if the disk
<filename>/run/log/journal</filename> hierarchy (which is is not writable. <literal>auto</literal> is similar to <literal>persistent</literal> but the
created if needed). If <literal>persistent</literal>, data directory <filename>/var/log/journal</filename> is not created if needed, so that its existence
will be stored preferably on disk, i.e. below the controls where log data goes. <literal>none</literal> turns off all storage, all log data received
<filename>/var/log/journal</filename> hierarchy (which is will be dropped. Forwarding to other targets, such as the console, the kernel log buffer, or a syslog
created if needed), with a fallback to socket will still work however. Defaults to <literal>auto</literal> in the default journal namespace,
<filename>/run/log/journal</filename> (which is created if and <literal>persistent</literal> in all others.</para></listitem>
needed), during early boot and if the disk is not writable.
<literal>auto</literal> is similar to
<literal>persistent</literal> but the directory
<filename>/var/log/journal</filename> is not created if
needed, so that its existence controls where log data goes.
<literal>none</literal> turns off all storage, all log data
received will be dropped. Forwarding to other targets, such as
the console, the kernel log buffer, or a syslog socket will
still work however. Defaults to
<literal>auto</literal>.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
@ -399,9 +397,9 @@
<varlistentry> <varlistentry>
<term><varname>ReadKMsg=</varname></term> <term><varname>ReadKMsg=</varname></term>
<listitem><para>Takes a boolean value. If enabled (the <listitem><para>Takes a boolean value. If enabled <command>systemd-journal</command> processes
default), journal reads <filename>/dev/kmsg</filename> <filename>/dev/kmsg</filename> messages generated by the kernel. In the default journal namespace
messages generated by the kernel.</para></listitem> this option is enabled by default, it is disabled in all others.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -3,7 +3,7 @@
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1+ --> <!-- SPDX-License-Identifier: LGPL-2.1+ -->
<refentry id="pam_systemd_home" conditional='HAVE_PAM'> <refentry id="pam_systemd_home" conditional='ENABLE_PAM_HOME'>
<refentryinfo> <refentryinfo>
<title>pam_systemd_home</title> <title>pam_systemd_home</title>

View File

@ -24,7 +24,7 @@ manpages = [
['journal-remote.conf', '5', ['journal-remote.conf.d'], 'HAVE_MICROHTTPD'], ['journal-remote.conf', '5', ['journal-remote.conf.d'], 'HAVE_MICROHTTPD'],
['journal-upload.conf', '5', ['journal-upload.conf.d'], 'HAVE_MICROHTTPD'], ['journal-upload.conf', '5', ['journal-upload.conf.d'], 'HAVE_MICROHTTPD'],
['journalctl', '1', [], ''], ['journalctl', '1', [], ''],
['journald.conf', '5', ['journald.conf.d'], ''], ['journald.conf', '5', ['journald.conf.d', 'journald@.conf'], ''],
['kernel-command-line', '7', [], ''], ['kernel-command-line', '7', [], ''],
['kernel-install', '8', [], ''], ['kernel-install', '8', [], ''],
['libudev', '3', [], ''], ['libudev', '3', [], ''],
@ -46,7 +46,7 @@ manpages = [
['nss-systemd', '8', ['libnss_systemd.so.2'], 'ENABLE_NSS_SYSTEMD'], ['nss-systemd', '8', ['libnss_systemd.so.2'], 'ENABLE_NSS_SYSTEMD'],
['os-release', '5', [], ''], ['os-release', '5', [], ''],
['pam_systemd', '8', [], 'HAVE_PAM'], ['pam_systemd', '8', [], 'HAVE_PAM'],
['pam_systemd_home', '8', [], 'HAVE_PAM'], ['pam_systemd_home', '8', [], 'ENABLE_PAM_HOME'],
['portablectl', '1', [], 'ENABLE_PORTABLED'], ['portablectl', '1', [], 'ENABLE_PORTABLED'],
['pstore.conf', '5', ['pstore.conf.d'], 'ENABLE_PSTORE'], ['pstore.conf', '5', ['pstore.conf.d'], 'ENABLE_PSTORE'],
['repart.d', '5', [], 'ENABLE_REPART'], ['repart.d', '5', [], 'ENABLE_REPART'],
@ -550,7 +550,9 @@ manpages = [
''], ''],
['sd_journal_open', ['sd_journal_open',
'3', '3',
['SD_JOURNAL_CURRENT_USER', ['SD_JOURNAL_ALL_NAMESPACES',
'SD_JOURNAL_CURRENT_USER',
'SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE',
'SD_JOURNAL_LOCAL_ONLY', 'SD_JOURNAL_LOCAL_ONLY',
'SD_JOURNAL_OS_ROOT', 'SD_JOURNAL_OS_ROOT',
'SD_JOURNAL_RUNTIME_ONLY', 'SD_JOURNAL_RUNTIME_ONLY',
@ -737,7 +739,10 @@ manpages = [
['systemd-journald', ['systemd-journald',
'systemd-journald-audit.socket', 'systemd-journald-audit.socket',
'systemd-journald-dev-log.socket', 'systemd-journald-dev-log.socket',
'systemd-journald.socket'], 'systemd-journald-varlink@.socket',
'systemd-journald.socket',
'systemd-journald@.service',
'systemd-journald@.socket'],
''], ''],
['systemd-localed.service', '8', ['systemd-localed'], 'ENABLE_LOCALED'], ['systemd-localed.service', '8', ['systemd-localed'], 'ENABLE_LOCALED'],
['systemd-logind.service', '8', ['systemd-logind'], 'ENABLE_LOGIND'], ['systemd-logind.service', '8', ['systemd-logind'], 'ENABLE_LOGIND'],

View File

@ -29,6 +29,8 @@
<refname>SD_JOURNAL_SYSTEM</refname> <refname>SD_JOURNAL_SYSTEM</refname>
<refname>SD_JOURNAL_CURRENT_USER</refname> <refname>SD_JOURNAL_CURRENT_USER</refname>
<refname>SD_JOURNAL_OS_ROOT</refname> <refname>SD_JOURNAL_OS_ROOT</refname>
<refname>SD_JOURNAL_ALL_NAMESPACES</refname>
<refname>SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE</refname>
<refpurpose>Open the system journal for reading</refpurpose> <refpurpose>Open the system journal for reading</refpurpose>
</refnamediv> </refnamediv>
@ -42,6 +44,13 @@
<paramdef>int <parameter>flags</parameter></paramdef> <paramdef>int <parameter>flags</parameter></paramdef>
</funcprototype> </funcprototype>
<funcprototype>
<funcdef>int <function>sd_journal_open_namespace</function></funcdef>
<paramdef>sd_journal **<parameter>ret</parameter></paramdef>
<paramdef>const char *<parameter>namespace</parameter></paramdef>
<paramdef>int <parameter>flags</parameter></paramdef>
</funcprototype>
<funcprototype> <funcprototype>
<funcdef>int <function>sd_journal_open_directory</function></funcdef> <funcdef>int <function>sd_journal_open_directory</function></funcdef>
<paramdef>sd_journal **<parameter>ret</parameter></paramdef> <paramdef>sd_journal **<parameter>ret</parameter></paramdef>
@ -101,6 +110,19 @@
<constant>SD_JOURNAL_CURRENT_USER</constant> are specified, all <constant>SD_JOURNAL_CURRENT_USER</constant> are specified, all
journal file types will be opened.</para> journal file types will be opened.</para>
<para><function>sd_journal_open_namespace()</function> is similar to
<function>sd_journal_open()</function> but takes an additional <parameter>namespace</parameter> parameter
that specifies which journal namespace to operate on. If specified as <constant>NULL</constant> the call
is identical to <function>sd_journal_open()</function>. If non-<constant>NULL</constant> only data from
the namespace identified by the specified parameter is accessed. This call understands two additional
flags: if <constant>SD_JOURNAL_ALL_NAMESPACES</constant> is specified the
<parameter>namespace</parameter> parameter is ignored and all defined namespaces are accessed
simultaneously; if <constant>SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE</constant> the specified namespace and
the default namespace are accessed but no others (this flag has no effect when
<parameter>namespace</parameter> is passed as <constant>NULL</constant>). For details about journal
namespaces see
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
<para><function>sd_journal_open_directory()</function> is similar to <function>sd_journal_open()</function> but <para><function>sd_journal_open_directory()</function> is similar to <function>sd_journal_open()</function> but
takes an absolute directory path as argument. All journal files in this directory will be opened and interleaved takes an absolute directory path as argument. All journal files in this directory will be opened and interleaved
automatically. This call also takes a flags argument. The flags parameters accepted by this call are automatically. This call also takes a flags argument. The flags parameters accepted by this call are

View File

@ -20,6 +20,9 @@
<refname>systemd-journald.socket</refname> <refname>systemd-journald.socket</refname>
<refname>systemd-journald-dev-log.socket</refname> <refname>systemd-journald-dev-log.socket</refname>
<refname>systemd-journald-audit.socket</refname> <refname>systemd-journald-audit.socket</refname>
<refname>systemd-journald@.service</refname>
<refname>systemd-journald@.socket</refname>
<refname>systemd-journald-varlink@.socket</refname>
<refname>systemd-journald</refname> <refname>systemd-journald</refname>
<refpurpose>Journal service</refpurpose> <refpurpose>Journal service</refpurpose>
</refnamediv> </refnamediv>
@ -29,6 +32,9 @@
<para><filename>systemd-journald.socket</filename></para> <para><filename>systemd-journald.socket</filename></para>
<para><filename>systemd-journald-dev-log.socket</filename></para> <para><filename>systemd-journald-dev-log.socket</filename></para>
<para><filename>systemd-journald-audit.socket</filename></para> <para><filename>systemd-journald-audit.socket</filename></para>
<para><filename>systemd-journald@.service</filename></para>
<para><filename>systemd-journald@.socket</filename></para>
<para><filename>systemd-journald-varlink@.socket</filename></para>
<para><filename>/usr/lib/systemd/systemd-journald</filename></para> <para><filename>/usr/lib/systemd/systemd-journald</filename></para>
</refsynopsisdiv> </refsynopsisdiv>
@ -129,6 +135,40 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
<constant>EPIPE</constant> right from the beginning.</para> <constant>EPIPE</constant> right from the beginning.</para>
</refsect1> </refsect1>
<refsect1>
<title>Journal Namespaces</title>
<para>Journal 'namespaces' are both a mechanism for logically isolating the log stream of projects
consisting of one or more services from the rest of the system and a mechanism for improving
performance. Multiple journal namespaces may exist simultaneously, each defining its own, independent log
stream managed by its own instance of <command>systemd-journald</command>. Namespaces are independent of
each other, both in the data store and in the IPC interface. By default only a single 'default' namespace
exists, managed by <filename>systemd-journald.service</filename> (and its associated socket
units). Additional namespaces are created by starting an instance of the
<filename>systemd-journald@.service</filename> service template. The instance name is the namespace
identifier, which is a short string used for referencing the journal namespace. Service units may be
assigned to a specific journal namespace through the <varname>LogNamespace=</varname> unit file setting,
see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details. The <option>--namespace=</option> switch of
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> may be
used to view the log stream of a specific namespace. If the switch is not used the log stream of the
default namespace is shown, i.e. log data from other namespaces is not visible.</para>
<para>Services associated with a specific log namespace may log via syslog, the native logging protocol
of the journal and via stdout/stderr; the logging from all three transports is associated with the
namespace.</para>
<para>By default only the default namespace will collect kernel and audit log messages.</para>
<para>The <command>systemd-journald</command> instance of the default namespace is configured through
<filename>/etc/systemd/journald.conf</filename> (see below), while the other instances are configured
through <filename>/etc/systemd/journald@<replaceable>NAMESPACE</replaceable>.conf</filename>. The journal
log data for the default namespace is placed in
<filename>/var/log/journal/<replaceable>MACHINE_ID</replaceable></filename> (see below) while the data
for the other namespaces is located in
<filename>/var/log/journal/<replaceable>MACHINE_ID</replaceable>.<replaceable>NAMESPACE</replaceable></filename>.</para>
</refsect1>
<refsect1> <refsect1>
<title>Signals</title> <title>Signals</title>
@ -190,6 +230,9 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
<para>Note that these kernel command line options are only honoured by the default namespace, see
above.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
@ -279,12 +322,14 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
<term><filename>/run/systemd/journal/socket</filename></term> <term><filename>/run/systemd/journal/socket</filename></term>
<term><filename>/run/systemd/journal/stdout</filename></term> <term><filename>/run/systemd/journal/stdout</filename></term>
<listitem><para>Sockets and other paths that <listitem><para>Sockets and other file node paths that <command>systemd-journald</command> will
<command>systemd-journald</command> will listen on that are listen on and are visible in the file system. In addition to these,
visible in the file system. In addition to these, journald can <command>systemd-journald</command> can listen for audit events using <citerefentry
listen for audit events using netlink.</para></listitem> project='man-pages'><refentrytitle>netlink</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para></listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
<para>If journal namespacing is used these paths are slightly altered to include a namespace identifier, see above.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
@ -296,7 +341,7 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
<citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-coredump</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-coredump</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='die-net'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<command>pydoc systemd.journal</command> <command>pydoc systemd.journal</command>
</para> </para>

View File

@ -70,6 +70,10 @@
<option>syslog</option> or <option>kmsg</option> (or their combinations with console output, see below) <option>syslog</option> or <option>kmsg</option> (or their combinations with console output, see below)
automatically acquire dependencies of type <varname>After=</varname> on automatically acquire dependencies of type <varname>After=</varname> on
<filename>systemd-journald.socket</filename>.</para></listitem> <filename>systemd-journald.socket</filename>.</para></listitem>
<listitem><para>Units using <varname>LogNamespace=</varname> will automatically gain ordering and
requirement dependencies on the two socket units associated with
<filename>systemd-journald@.service</filename> instances.</para></listitem>
</itemizedlist> </itemizedlist>
</refsect1> </refsect1>
@ -2254,6 +2258,36 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>LogNamespace=</varname></term>
<listitem><para>Run the unit's processes in the specified journal namespace. Expects a short
user-defined string identifying the namespace. If not used the processes of the service are run in
the default journal namespace, i.e. their log stream is collected and processed by
<filename>systemd-journald.service</filename>. If this option is used any log data generated by
processes of this unit (regardless if via the <function>syslog()</function>, journal native logging
or stdout/stderr logging) is collected and processed by an instance of the
<filename>systemd-journald@.service</filename> template unit, which manages the specified
namespace. The log data is stored in a data store independent from the default log namespace's data
store. See
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for details about journal namespaces.</para>
<para>Internally, journal namespaces are implemented through Linux mount namespacing and
over-mounting the directory that contains the relevant <constant>AF_UNIX</constant> sockets used for
logging in the unit's mount namespace. Since mount namespaces are used this setting disconnects
propagation of mounts from the unit's processes to the host, similar to how
<varname>ReadOnlyPaths=</varname> and similar settings (see above) work. Journal namespaces may hence
not be used for services that need to establish mount points on the host.</para>
<para>When this option is used the unit will automatically gain ordering and requirement dependencies
on the two socket units associated with the <filename>systemd-journald@.service</filename> instance
so that they are automatically established prior to the unit starting up. Note that when this option
is used log output of this service does not appear in the regular
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
output, unless the <option>--namespace=</option> option is used.</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>SyslogIdentifier=</varname></term> <term><varname>SyslogIdentifier=</varname></term>

View File

@ -358,6 +358,15 @@
marking the log line end.</para> marking the log line end.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>_NAMESPACE=</varname></term>
<listitem><para>If this file was written by a <command>systemd-journald</command> instance managing a
journal namespace that is not the default, this field contains the namespace identifier. See
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for details about journal namespaces.</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>

View File

@ -1343,6 +1343,9 @@ else
endif endif
conf.set10('ENABLE_HOMED', have) conf.set10('ENABLE_HOMED', have)
have = have and conf.get('HAVE_PAM') == 1
conf.set10('ENABLE_PAM_HOME', have)
want_remote = get_option('remote') want_remote = get_option('remote')
if want_remote != 'false' if want_remote != 'false'
have_deps = [conf.get('HAVE_MICROHTTPD') == 1, have_deps = [conf.get('HAVE_MICROHTTPD') == 1,

View File

@ -1054,6 +1054,8 @@ bool string_is_safe(const char *p) {
if (!p) if (!p)
return false; return false;
/* Checks if the specified string contains no quotes or control characters */
for (t = p; *t; t++) { for (t = p; *t; t++) {
if (*t > 0 && *t < ' ') /* no control characters */ if (*t > 0 && *t < ' ') /* no control characters */
return false; return false;

View File

@ -2,10 +2,15 @@
#include <syslog.h> #include <syslog.h>
#include "sd-id128.h"
#include "glob-util.h"
#include "hexdecoct.h" #include "hexdecoct.h"
#include "macro.h" #include "macro.h"
#include "path-util.h"
#include "string-table.h" #include "string-table.h"
#include "syslog-util.h" #include "syslog-util.h"
#include "unit-name.h"
int syslog_parse_priority(const char **p, int *priority, bool with_facility) { int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
int a = 0, b = 0, c = 0; int a = 0, b = 0, c = 0;
@ -96,3 +101,31 @@ DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
bool log_level_is_valid(int level) { bool log_level_is_valid(int level) {
return level >= 0 && level <= LOG_DEBUG; return level >= 0 && level <= LOG_DEBUG;
} }
/* The maximum size for a log namespace length. This is the file name size limit 255 minus the size of a
* formatted machine ID minus a separator char */
#define LOG_NAMESPACE_MAX (NAME_MAX - (SD_ID128_STRING_MAX - 1) - 1)
bool log_namespace_name_valid(const char *s) {
/* Let's make sure the namespace fits in a filename that is prefixed with the machine ID and a dot
* (so that /var/log/journal/<machine-id>.<namespace> can be created based on it). Also make sure it
* is suitable as unit instance name, and does not contain fishy characters. */
if (!filename_is_valid(s))
return false;
if (strlen(s) > LOG_NAMESPACE_MAX)
return false;
if (!unit_instance_is_valid(s))
return false;
if (!string_is_safe(s))
return false;
/* Let's avoid globbing for now */
if (string_is_glob(s))
return false;
return true;
}

View File

@ -12,3 +12,5 @@ int log_level_from_string(const char *s);
bool log_level_is_valid(int level); bool log_level_is_valid(int level);
int syslog_parse_priority(const char **p, int *priority, bool with_facility); int syslog_parse_priority(const char **p, int *priority, bool with_facility);
bool log_namespace_name_valid(const char *s);

View File

@ -766,6 +766,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_ratelimit_interval_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_ratelimit_interval_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_ratelimit_burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_ratelimit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogNamespace", "s", NULL, offsetof(ExecContext, log_namespace), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CapabilityBoundingSet", "t", NULL, offsetof(ExecContext, capability_bounding_set), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CapabilityBoundingSet", "t", NULL, offsetof(ExecContext, capability_bounding_set), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("AmbientCapabilities", "t", NULL, offsetof(ExecContext, capability_ambient_set), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("AmbientCapabilities", "t", NULL, offsetof(ExecContext, capability_ambient_set), SD_BUS_VTABLE_PROPERTY_CONST),
@ -1436,6 +1437,32 @@ int bus_exec_context_set_transient_property(
return 1; return 1;
} else if (streq(name, "LogNamespace")) {
const char *n;
r = sd_bus_message_read(message, "s", &n);
if (r < 0)
return r;
if (!isempty(n) && !log_namespace_name_valid(n))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log namespace name not valid");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (isempty(n)) {
c->log_namespace = mfree(c->log_namespace);
unit_write_settingf(u, flags, name, "%s=", name);
} else {
r = free_and_strdup(&c->log_namespace, n);
if (r < 0)
return r;
unit_write_settingf(u, flags, name, "%s=%s", name, n);
}
}
return 1;
} else if (streq(name, "LogExtraFields")) { } else if (streq(name, "LogExtraFields")) {
size_t n = 0; size_t n = 0;

View File

@ -265,15 +265,27 @@ static int open_null_as(int flags, int nfd) {
return move_fd(fd, nfd, false); return move_fd(fd, nfd, false);
} }
static int connect_journal_socket(int fd, uid_t uid, gid_t gid) { static int connect_journal_socket(
static const union sockaddr_union sa = { int fd,
const char *log_namespace,
uid_t uid,
gid_t gid) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX, .un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
}; };
uid_t olduid = UID_INVALID; uid_t olduid = UID_INVALID;
gid_t oldgid = GID_INVALID; gid_t oldgid = GID_INVALID;
const char *j;
int r; int r;
j = log_namespace ?
strjoina("/run/systemd/journal.", log_namespace, "/stdout") :
"/run/systemd/journal/stdout";
r = sockaddr_un_set_path(&sa.un, j);
if (r < 0)
return r;
if (gid_is_valid(gid)) { if (gid_is_valid(gid)) {
oldgid = getgid(); oldgid = getgid();
@ -328,7 +340,7 @@ static int connect_logger_as(
if (fd < 0) if (fd < 0)
return -errno; return -errno;
r = connect_journal_socket(fd, uid, gid); r = connect_journal_socket(fd, context->log_namespace, uid, gid);
if (r < 0) if (r < 0)
return r; return r;
@ -1686,7 +1698,7 @@ static int build_environment(
assert(p); assert(p);
assert(ret); assert(ret);
our_env = new0(char*, 14 + _EXEC_DIRECTORY_TYPE_MAX); our_env = new0(char*, 15 + _EXEC_DIRECTORY_TYPE_MAX);
if (!our_env) if (!our_env)
return -ENOMEM; return -ENOMEM;
@ -1795,6 +1807,14 @@ static int build_environment(
our_env[n_env++] = x; our_env[n_env++] = x;
} }
if (c->log_namespace) {
x = strjoin("LOG_NAMESPACE=", c->log_namespace);
if (!x)
return -ENOMEM;
our_env[n_env++] = x;
}
for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) { for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
_cleanup_free_ char *pre = NULL, *joined = NULL; _cleanup_free_ char *pre = NULL, *joined = NULL;
const char *n; const char *n;
@ -1919,6 +1939,9 @@ static bool exec_needs_mount_namespace(
!strv_isempty(context->directories[EXEC_DIRECTORY_LOGS].paths))) !strv_isempty(context->directories[EXEC_DIRECTORY_LOGS].paths)))
return true; return true;
if (context->log_namespace)
return true;
return false; return false;
} }
@ -2517,6 +2540,9 @@ static bool insist_on_sandboxing(
if (!path_equal(bind_mounts[i].source, bind_mounts[i].destination)) if (!path_equal(bind_mounts[i].source, bind_mounts[i].destination))
return true; return true;
if (context->log_namespace)
return true;
return false; return false;
} }
@ -2600,6 +2626,7 @@ static int apply_mount_namespace(
context->n_temporary_filesystems, context->n_temporary_filesystems,
tmp, tmp,
var, var,
context->log_namespace,
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO, needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO, needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
context->mount_flags, context->mount_flags,
@ -4140,6 +4167,8 @@ void exec_context_done(ExecContext *c) {
c->stdin_data_size = 0; c->stdin_data_size = 0;
c->network_namespace_path = mfree(c->network_namespace_path); c->network_namespace_path = mfree(c->network_namespace_path);
c->log_namespace = mfree(c->log_namespace);
} }
int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) { int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
@ -4675,6 +4704,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
} }
} }
if (c->log_namespace)
fprintf(f, "%sLogNamespace: %s\n", prefix, c->log_namespace);
if (c->secure_bits) { if (c->secure_bits) {
_cleanup_free_ char *str = NULL; _cleanup_free_ char *str = NULL;

View File

@ -250,6 +250,8 @@ struct ExecContext {
int log_level_max; int log_level_max;
char *log_namespace;
bool private_tmp; bool private_tmp;
bool private_network; bool private_network;
bool private_devices; bool private_devices;

View File

@ -119,6 +119,7 @@ $1.ProtectKernelLogs, config_parse_bool, 0,
$1.ProtectClock, config_parse_bool, 0, offsetof($1, exec_context.protect_clock) $1.ProtectClock, config_parse_bool, 0, offsetof($1, exec_context.protect_clock)
$1.ProtectControlGroups, config_parse_bool, 0, offsetof($1, exec_context.protect_control_groups) $1.ProtectControlGroups, config_parse_bool, 0, offsetof($1, exec_context.protect_control_groups)
$1.NetworkNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.network_namespace_path) $1.NetworkNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.network_namespace_path)
$1.LogNamespace, config_parse_log_namespace, 0, offsetof($1, exec_context)
$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) $1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network)
$1.PrivateUsers, config_parse_bool, 0, offsetof($1, exec_context.private_users) $1.PrivateUsers, config_parse_bool, 0, offsetof($1, exec_context.private_users)
$1.PrivateMounts, config_parse_bool, 0, offsetof($1, exec_context.private_mounts) $1.PrivateMounts, config_parse_bool, 0, offsetof($1, exec_context.private_mounts)

View File

@ -52,10 +52,11 @@
#include "stat-util.h" #include "stat-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "syslog-util.h"
#include "time-util.h"
#include "unit-name.h" #include "unit-name.h"
#include "unit-printf.h" #include "unit-printf.h"
#include "user-util.h" #include "user-util.h"
#include "time-util.h"
#include "web-util.h" #include "web-util.h"
static int parse_socket_protocol(const char *s) { static int parse_socket_protocol(const char *s) {
@ -2519,6 +2520,48 @@ int config_parse_log_extra_fields(
} }
} }
int config_parse_log_namespace(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_free_ char *k = NULL;
ExecContext *c = data;
const Unit *u = userdata;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(c);
if (isempty(rvalue)) {
c->log_namespace = mfree(c->log_namespace);
return 0;
}
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
}
if (!log_namespace_name_valid(k)) {
log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Specified log namespace name is not valid: %s", k);
return 0;
}
free_and_replace(c->log_namespace, k);
return 0;
}
int config_parse_unit_condition_path( int config_parse_unit_condition_path(
const char *unit, const char *unit,
const char *filename, const char *filename,

View File

@ -107,6 +107,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_keyring_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_job_timeout_sec); CONFIG_PARSER_PROTOTYPE(config_parse_job_timeout_sec);
CONFIG_PARSER_PROTOTYPE(config_parse_job_running_timeout_sec); CONFIG_PARSER_PROTOTYPE(config_parse_job_running_timeout_sec);
CONFIG_PARSER_PROTOTYPE(config_parse_log_extra_fields); CONFIG_PARSER_PROTOTYPE(config_parse_log_extra_fields);
CONFIG_PARSER_PROTOTYPE(config_parse_log_namespace);
CONFIG_PARSER_PROTOTYPE(config_parse_collect_mode); CONFIG_PARSER_PROTOTYPE(config_parse_collect_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_pid_file); CONFIG_PARSER_PROTOTYPE(config_parse_pid_file);
CONFIG_PARSER_PROTOTYPE(config_parse_exit_status); CONFIG_PARSER_PROTOTYPE(config_parse_exit_status);

View File

@ -1132,6 +1132,7 @@ static size_t namespace_calculate_mounts(
size_t n_temporary_filesystems, size_t n_temporary_filesystems,
const char* tmp_dir, const char* tmp_dir,
const char* var_tmp_dir, const char* var_tmp_dir,
const char* log_namespace,
ProtectHome protect_home, ProtectHome protect_home,
ProtectSystem protect_system) { ProtectSystem protect_system) {
@ -1166,7 +1167,8 @@ static size_t namespace_calculate_mounts(
(ns_info->protect_control_groups ? 1 : 0) + (ns_info->protect_control_groups ? 1 : 0) +
protect_home_cnt + protect_system_cnt + protect_home_cnt + protect_system_cnt +
(ns_info->protect_hostname ? 2 : 0) + (ns_info->protect_hostname ? 2 : 0) +
(namespace_info_mount_apivfs(ns_info) ? ELEMENTSOF(apivfs_table) : 0); (namespace_info_mount_apivfs(ns_info) ? ELEMENTSOF(apivfs_table) : 0) +
!!log_namespace;
} }
static void normalize_mounts(const char *root_directory, MountEntry *mounts, size_t *n_mounts) { static void normalize_mounts(const char *root_directory, MountEntry *mounts, size_t *n_mounts) {
@ -1247,6 +1249,7 @@ int setup_namespace(
size_t n_temporary_filesystems, size_t n_temporary_filesystems,
const char* tmp_dir, const char* tmp_dir,
const char* var_tmp_dir, const char* var_tmp_dir,
const char *log_namespace,
ProtectHome protect_home, ProtectHome protect_home,
ProtectSystem protect_system, ProtectSystem protect_system,
unsigned long mount_flags, unsigned long mount_flags,
@ -1323,6 +1326,7 @@ int setup_namespace(
n_bind_mounts, n_bind_mounts,
n_temporary_filesystems, n_temporary_filesystems,
tmp_dir, var_tmp_dir, tmp_dir, var_tmp_dir,
log_namespace,
protect_home, protect_system); protect_home, protect_system);
if (n_mounts > 0) { if (n_mounts > 0) {
@ -1428,6 +1432,23 @@ int setup_namespace(
}; };
} }
if (log_namespace) {
_cleanup_free_ char *q;
q = strjoin("/run/systemd/journal.", log_namespace);
if (!q) {
r = -ENOMEM;
goto finish;
}
*(m++) = (MountEntry) {
.path_const = "/run/systemd/journal",
.mode = BIND_MOUNT_RECURSIVE,
.read_only = true,
.source_malloc = TAKE_PTR(q),
};
}
assert(mounts + n_mounts == m); assert(mounts + n_mounts == m);
/* Prepend the root directory where that's necessary */ /* Prepend the root directory where that's necessary */

View File

@ -84,6 +84,7 @@ int setup_namespace(
size_t n_temporary_filesystems, size_t n_temporary_filesystems,
const char *tmp_dir, const char *tmp_dir,
const char *var_tmp_dir, const char *var_tmp_dir,
const char *log_namespace,
ProtectHome protect_home, ProtectHome protect_home,
ProtectSystem protect_system, ProtectSystem protect_system,
unsigned long mount_flags, unsigned long mount_flags,

View File

@ -1059,12 +1059,32 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
!IN_SET(c->std_error, !IN_SET(c->std_error,
EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE, EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE)) EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) &&
!c->log_namespace)
return 0; return 0;
/* If syslog or kernel logging is requested, make sure our own /* If syslog or kernel logging is requested (or log namespacing is), make sure our own logging daemon
* logging daemon is run first. */ * is run first. */
if (c->log_namespace) {
_cleanup_free_ char *socket_unit = NULL, *varlink_socket_unit = NULL;
r = unit_name_build_from_type("systemd-journald", c->log_namespace, UNIT_SOCKET, &socket_unit);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, socket_unit, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
r = unit_name_build_from_type("systemd-journald-varlink", c->log_namespace, UNIT_SOCKET, &varlink_socket_unit);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, varlink_socket_unit, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
} else
r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, true, UNIT_DEPENDENCY_FILE); r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, true, UNIT_DEPENDENCY_FILE);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -754,9 +754,13 @@ static int open_journal(sd_journal **j) {
r = sd_journal_open_directory(j, arg_directory, arg_journal_type); r = sd_journal_open_directory(j, arg_directory, arg_journal_type);
else if (arg_file) else if (arg_file)
r = sd_journal_open_files(j, (const char**) arg_file, 0); r = sd_journal_open_files(j, (const char**) arg_file, 0);
else if (arg_machine) else if (arg_machine) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/* FIXME: replace with D-Bus call OpenMachineRootDirectory() so that things also work with raw disk images */
r = sd_journal_open_container(j, arg_machine, 0); r = sd_journal_open_container(j, arg_machine, 0);
else #pragma GCC diagnostic pop
} else
r = sd_journal_open(j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type); r = sd_journal_open(j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
if (r < 0) if (r < 0)
log_error_errno(r, "Failed to open %s: %m", log_error_errno(r, "Failed to open %s: %m",

View File

@ -69,6 +69,7 @@ struct sd_journal {
char *path; char *path;
char *prefix; char *prefix;
char *namespace;
OrderedHashmap *files; OrderedHashmap *files;
IteratedCache *files_cache; IteratedCache *files_cache;

View File

@ -70,36 +70,8 @@
#include "varlink.h" #include "varlink.h"
#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
#define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */ #define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
#if HAVE_PCRE2
DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, pcre2_match_data_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, pcre2_code_free);
static int pattern_compile(const char *pattern, unsigned flags, pcre2_code **out) {
int errorcode, r;
PCRE2_SIZE erroroffset;
pcre2_code *p;
p = pcre2_compile((PCRE2_SPTR8) pattern,
PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL);
if (!p) {
unsigned char buf[LINE_MAX];
r = pcre2_get_error_message(errorcode, buf, sizeof buf);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Bad pattern \"%s\": %s", pattern,
r < 0 ? "unknown error" : (char *)buf);
}
*out = p;
return 0;
}
#endif
enum { enum {
/* Special values for arg_lines */ /* Special values for arg_lines */
ARG_LINES_DEFAULT = -2, ARG_LINES_DEFAULT = -2,
@ -143,13 +115,14 @@ static const char *arg_field = NULL;
static bool arg_catalog = false; static bool arg_catalog = false;
static bool arg_reverse = false; static bool arg_reverse = false;
static int arg_journal_type = 0; static int arg_journal_type = 0;
static int arg_namespace_flags = 0;
static char *arg_root = NULL; static char *arg_root = NULL;
static const char *arg_machine = NULL; static const char *arg_machine = NULL;
static const char *arg_namespace = NULL;
static uint64_t arg_vacuum_size = 0; static uint64_t arg_vacuum_size = 0;
static uint64_t arg_vacuum_n_files = 0; static uint64_t arg_vacuum_n_files = 0;
static usec_t arg_vacuum_time = 0; static usec_t arg_vacuum_time = 0;
static char **arg_output_fields = NULL; static char **arg_output_fields = NULL;
#if HAVE_PCRE2 #if HAVE_PCRE2
static const char *arg_pattern = NULL; static const char *arg_pattern = NULL;
static pcre2_code *arg_compiled_pattern = NULL; static pcre2_code *arg_compiled_pattern = NULL;
@ -184,6 +157,33 @@ typedef struct BootId {
LIST_FIELDS(struct BootId, boot_list); LIST_FIELDS(struct BootId, boot_list);
} BootId; } BootId;
#if HAVE_PCRE2
DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, pcre2_match_data_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, pcre2_code_free);
static int pattern_compile(const char *pattern, unsigned flags, pcre2_code **out) {
int errorcode, r;
PCRE2_SIZE erroroffset;
pcre2_code *p;
p = pcre2_compile((PCRE2_SPTR8) pattern,
PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL);
if (!p) {
unsigned char buf[LINE_MAX];
r = pcre2_get_error_message(errorcode, buf, sizeof buf);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Bad pattern \"%s\": %s", pattern,
r < 0 ? "unknown error" : (char *)buf);
}
*out = p;
return 0;
}
#endif
static int add_matches_for_device(sd_journal *j, const char *devpath) { static int add_matches_for_device(sd_journal *j, const char *devpath) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL; _cleanup_(sd_device_unrefp) sd_device *device = NULL;
sd_device *d = NULL; sd_device *d = NULL;
@ -313,9 +313,9 @@ static int help(void) {
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
printf("%s [OPTIONS...] [MATCHES...]\n\n" printf("%1$s [OPTIONS...] [MATCHES...]\n\n"
"%sQuery the journal.%s\n\n" "%5$sQuery the journal.%6$s\n\n"
"Options:\n" "%3$sOptions:%4$s\n"
" --system Show the system journal\n" " --system Show the system journal\n"
" --user Show the user journal for the current user\n" " --user Show the user journal for the current user\n"
" -M --machine=CONTAINER Operate on local container\n" " -M --machine=CONTAINER Operate on local container\n"
@ -356,10 +356,11 @@ static int help(void) {
" -D --directory=PATH Show journal files from directory\n" " -D --directory=PATH Show journal files from directory\n"
" --file=PATH Show journal file\n" " --file=PATH Show journal file\n"
" --root=ROOT Operate on files below a root directory\n" " --root=ROOT Operate on files below a root directory\n"
" --namespace=NAMESPACE Show journal data from specified namespace\n"
" --interval=TIME Time interval for changing the FSS sealing key\n" " --interval=TIME Time interval for changing the FSS sealing key\n"
" --verify-key=KEY Specify FSS verification key\n" " --verify-key=KEY Specify FSS verification key\n"
" --force Override of the FSS key pair with --setup-keys\n" " --force Override of the FSS key pair with --setup-keys\n"
"\nCommands:\n" "\n%3$sCommands:%4$s\n"
" -h --help Show this help text\n" " -h --help Show this help text\n"
" --version Show package version\n" " --version Show package version\n"
" -N --fields List all field names currently used\n" " -N --fields List all field names currently used\n"
@ -379,10 +380,11 @@ static int help(void) {
" --dump-catalog Show entries in the message catalog\n" " --dump-catalog Show entries in the message catalog\n"
" --update-catalog Update the message catalog database\n" " --update-catalog Update the message catalog database\n"
" --setup-keys Generate a new FSS key pair\n" " --setup-keys Generate a new FSS key pair\n"
"\nSee the %s for details.\n" "\nSee the %2$s for details.\n"
, program_invocation_short_name , program_invocation_short_name
, ansi_highlight(), ansi_normal()
, link , link
, ansi_underline(), ansi_normal()
, ansi_highlight(), ansi_normal()
); );
return 0; return 0;
@ -428,6 +430,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VACUUM_TIME, ARG_VACUUM_TIME,
ARG_NO_HOSTNAME, ARG_NO_HOSTNAME,
ARG_OUTPUT_FIELDS, ARG_OUTPUT_FIELDS,
ARG_NAMESPACE,
}; };
static const struct option options[] = { static const struct option options[] = {
@ -492,6 +495,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME }, { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
{ "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME }, { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME },
{ "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS }, { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS },
{ "namespace", required_argument, NULL, ARG_NAMESPACE },
{} {}
}; };
@ -533,10 +537,8 @@ static int parse_argv(int argc, char *argv[]) {
} }
arg_output = output_mode_from_string(optarg); arg_output = output_mode_from_string(optarg);
if (arg_output < 0) { if (arg_output < 0)
log_error("Unknown output format '%s'.", optarg); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown output format '%s'.", optarg);
return -EINVAL;
}
if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ, OUTPUT_CAT)) if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ, OUTPUT_CAT))
arg_quiet = true; arg_quiet = true;
@ -561,10 +563,8 @@ static int parse_argv(int argc, char *argv[]) {
arg_lines = ARG_LINES_ALL; arg_lines = ARG_LINES_ALL;
else { else {
r = safe_atoi(optarg, &arg_lines); r = safe_atoi(optarg, &arg_lines);
if (r < 0 || arg_lines < 0) { if (r < 0 || arg_lines < 0)
log_error("Failed to parse lines '%s'", optarg); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse lines '%s'", optarg);
return -EINVAL;
}
} }
} else { } else {
arg_lines = 10; arg_lines = 10;
@ -656,6 +656,23 @@ static int parse_argv(int argc, char *argv[]) {
arg_machine = optarg; arg_machine = optarg;
break; break;
case ARG_NAMESPACE:
if (streq(optarg, "*")) {
arg_namespace_flags = SD_JOURNAL_ALL_NAMESPACES;
arg_namespace = NULL;
} else if (startswith(optarg, "+")) {
arg_namespace_flags = SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE;
arg_namespace = optarg + 1;
} else if (isempty(optarg)) {
arg_namespace_flags = 0;
arg_namespace = NULL;
} else {
arg_namespace_flags = 0;
arg_namespace = optarg;
}
break;
case 'D': case 'D':
arg_directory = optarg; arg_directory = optarg;
break; break;
@ -710,30 +727,24 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VACUUM_SIZE: case ARG_VACUUM_SIZE:
r = parse_size(optarg, 1024, &arg_vacuum_size); r = parse_size(optarg, 1024, &arg_vacuum_size);
if (r < 0) { if (r < 0)
log_error("Failed to parse vacuum size: %s", optarg); return log_error_errno(r, "Failed to parse vacuum size: %s", optarg);
return r;
}
arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
break; break;
case ARG_VACUUM_FILES: case ARG_VACUUM_FILES:
r = safe_atou64(optarg, &arg_vacuum_n_files); r = safe_atou64(optarg, &arg_vacuum_n_files);
if (r < 0) { if (r < 0)
log_error("Failed to parse vacuum files: %s", optarg); return log_error_errno(r, "Failed to parse vacuum files: %s", optarg);
return r;
}
arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
break; break;
case ARG_VACUUM_TIME: case ARG_VACUUM_TIME:
r = parse_sec(optarg, &arg_vacuum_time); r = parse_sec(optarg, &arg_vacuum_time);
if (r < 0) { if (r < 0)
log_error("Failed to parse vacuum time: %s", optarg); return log_error_errno(r, "Failed to parse vacuum time: %s", optarg);
return r;
}
arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
break; break;
@ -748,7 +759,6 @@ static int parse_argv(int argc, char *argv[]) {
break; break;
case ARG_VERIFY_KEY: case ARG_VERIFY_KEY:
arg_action = ACTION_VERIFY;
r = free_and_strdup(&arg_verify_key, optarg); r = free_and_strdup(&arg_verify_key, optarg);
if (r < 0) if (r < 0)
return r; return r;
@ -756,23 +766,23 @@ static int parse_argv(int argc, char *argv[]) {
* in ps or htop output. */ * in ps or htop output. */
memset(optarg, 'x', strlen(optarg)); memset(optarg, 'x', strlen(optarg));
arg_action = ACTION_VERIFY;
arg_merge = false; arg_merge = false;
break; break;
case ARG_INTERVAL: case ARG_INTERVAL:
r = parse_sec(optarg, &arg_interval); r = parse_sec(optarg, &arg_interval);
if (r < 0 || arg_interval <= 0) { if (r < 0 || arg_interval <= 0)
log_error("Failed to parse sealing key change interval: %s", optarg); return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
return -EINVAL; "Failed to parse sealing key change interval: %s", optarg);
}
break; break;
#else #else
case ARG_SETUP_KEYS: case ARG_SETUP_KEYS:
case ARG_VERIFY_KEY: case ARG_VERIFY_KEY:
case ARG_INTERVAL: case ARG_INTERVAL:
case ARG_FORCE: case ARG_FORCE:
log_error("Compiled without forward-secure sealing support."); return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
return -EOPNOTSUPP; "Compiled without forward-secure sealing support.");
#endif #endif
case 'p': { case 'p': {
@ -780,7 +790,7 @@ static int parse_argv(int argc, char *argv[]) {
dots = strstr(optarg, ".."); dots = strstr(optarg, "..");
if (dots) { if (dots) {
char *a; _cleanup_free_ char *a = NULL;
int from, to, i; int from, to, i;
/* a range */ /* a range */
@ -790,12 +800,10 @@ static int parse_argv(int argc, char *argv[]) {
from = log_level_from_string(a); from = log_level_from_string(a);
to = log_level_from_string(dots + 2); to = log_level_from_string(dots + 2);
free(a);
if (from < 0 || to < 0) { if (from < 0 || to < 0)
log_error("Failed to parse log level range %s", optarg); return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
return -EINVAL; "Failed to parse log level range %s", optarg);
}
arg_priorities = 0; arg_priorities = 0;
@ -811,10 +819,9 @@ static int parse_argv(int argc, char *argv[]) {
int p, i; int p, i;
p = log_level_from_string(optarg); p = log_level_from_string(optarg);
if (p < 0) { if (p < 0)
log_error("Unknown log level %s", optarg); return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
return -EINVAL; "Unknown log level %s", optarg);
}
arg_priorities = 0; arg_priorities = 0;
@ -848,19 +855,17 @@ static int parse_argv(int argc, char *argv[]) {
case 'S': case 'S':
r = parse_timestamp(optarg, &arg_since); r = parse_timestamp(optarg, &arg_since);
if (r < 0) { if (r < 0)
log_error("Failed to parse timestamp: %s", optarg); return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
return -EINVAL; "Failed to parse timestamp: %s", optarg);
}
arg_since_set = true; arg_since_set = true;
break; break;
case 'U': case 'U':
r = parse_timestamp(optarg, &arg_until); r = parse_timestamp(optarg, &arg_until);
if (r < 0) { if (r < 0)
log_error("Failed to parse timestamp: %s", optarg); return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
return -EINVAL; "Failed to parse timestamp: %s", optarg);
}
arg_until_set = true; arg_until_set = true;
break; break;
@ -1417,7 +1422,6 @@ static int add_boot(sd_journal *j) {
* so take the slow path if log location is specified. */ * so take the slow path if log location is specified. */
if (arg_boot_offset == 0 && sd_id128_is_null(arg_boot_id) && if (arg_boot_offset == 0 && sd_id128_is_null(arg_boot_id) &&
!arg_directory && !arg_file && !arg_root) !arg_directory && !arg_file && !arg_root)
return add_match_this_boot(j, arg_machine); return add_match_this_boot(j, arg_machine);
boot_id = arg_boot_id; boot_id = arg_boot_id;
@ -1944,15 +1948,19 @@ static int verify(sd_journal *j) {
static int simple_varlink_call(const char *option, const char *method) { static int simple_varlink_call(const char *option, const char *method) {
_cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL; _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL;
const char *error; const char *error, *fn;
int r; int r;
if (arg_machine) if (arg_machine)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "%s is not supported in conjunction with --machine=.", option); return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "%s is not supported in conjunction with --machine=.", option);
r = varlink_connect_address(&link, "/run/systemd/journal/io.systemd.journal"); fn = arg_namespace ?
strjoina("/run/systemd/journal.", arg_namespace, "/io.systemd.journal") :
"/run/systemd/journal/io.systemd.journal";
r = varlink_connect_address(&link, fn);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to connect to /run/systemd/journal/io.systemd.journal: %m"); return log_error_errno(r, "Failed to connect to %s: %m", fn);
(void) varlink_set_description(link, "journal"); (void) varlink_set_description(link, "journal");
(void) varlink_set_relative_timeout(link, USEC_INFINITY); (void) varlink_set_relative_timeout(link, USEC_INFINITY);
@ -2122,10 +2130,9 @@ int main(int argc, char *argv[]) {
r = sd_journal_open_directory(&j, arg_directory, arg_journal_type); r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
else if (arg_root) else if (arg_root)
r = sd_journal_open_directory(&j, arg_root, arg_journal_type | SD_JOURNAL_OS_ROOT); r = sd_journal_open_directory(&j, arg_root, arg_journal_type | SD_JOURNAL_OS_ROOT);
else if (arg_file_stdin) { else if (arg_file_stdin)
int ifd = STDIN_FILENO; r = sd_journal_open_files_fd(&j, (int[]) { STDIN_FILENO }, 1, 0);
r = sd_journal_open_files_fd(&j, &ifd, 1, 0); else if (arg_file)
} else if (arg_file)
r = sd_journal_open_files(&j, (const char**) arg_file, 0); r = sd_journal_open_files(&j, (const char**) arg_file, 0);
else if (arg_machine) { else if (arg_machine) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@ -2136,8 +2143,7 @@ int main(int argc, char *argv[]) {
if (geteuid() != 0) { if (geteuid() != 0) {
/* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
* the container, thus we need root privileges to override them. */ * the container, thus we need root privileges to override them. */
log_error("Using the --machine= switch requires root privileges."); r = log_error_errno(SYNTHETIC_ERRNO(EPERM), "Using the --machine= switch requires root privileges.");
r = -EPERM;
goto finish; goto finish;
} }
@ -2177,7 +2183,11 @@ int main(int argc, char *argv[]) {
if (r < 0) if (r < 0)
safe_close(fd); safe_close(fd);
} else } else
r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type); r = sd_journal_open_namespace(
&j,
arg_namespace,
(arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY) |
arg_namespace_flags | arg_journal_type);
if (r < 0) { if (r < 0) {
log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal"); log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
goto finish; goto finish;

View File

@ -117,23 +117,24 @@ static int client_context_new(Server *s, pid_t pid, ClientContext **ret) {
if (r < 0) if (r < 0)
return r; return r;
c = new0(ClientContext, 1); c = new(ClientContext, 1);
if (!c) if (!c)
return -ENOMEM; return -ENOMEM;
c->pid = pid; *c = (ClientContext) {
.pid = pid,
c->uid = UID_INVALID; .uid = UID_INVALID,
c->gid = GID_INVALID; .gid = GID_INVALID,
c->auditid = AUDIT_SESSION_INVALID; .auditid = AUDIT_SESSION_INVALID,
c->loginuid = UID_INVALID; .loginuid = UID_INVALID,
c->owner_uid = UID_INVALID; .owner_uid = UID_INVALID,
c->lru_index = PRIOQ_IDX_NULL; .lru_index = PRIOQ_IDX_NULL,
c->timestamp = USEC_INFINITY; .timestamp = USEC_INFINITY,
c->extra_fields_mtime = NSEC_INFINITY; .extra_fields_mtime = NSEC_INFINITY,
c->log_level_max = -1; .log_level_max = -1,
c->log_ratelimit_interval = s->ratelimit_interval; .log_ratelimit_interval = s->ratelimit_interval,
c->log_ratelimit_burst = s->ratelimit_burst; .log_ratelimit_burst = s->ratelimit_burst,
};
r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c); r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c);
if (r < 0) { if (r < 0) {
@ -779,7 +780,9 @@ void client_context_acquire_default(Server *s) {
log_warning_errno(r, "Failed to acquire our own context, ignoring: %m"); log_warning_errno(r, "Failed to acquire our own context, ignoring: %m");
} }
if (!s->pid1_context) { if (!s->namespace && !s->pid1_context) {
/* Acquire PID1's context, but only if we are in non-namespaced mode, since PID 1 is only
* going to log to the non-namespaced journal instance. */
r = client_context_acquire(s, 1, NULL, NULL, 0, NULL, &s->pid1_context); r = client_context_acquire(s, 1, NULL, NULL, 0, NULL, &s->pid1_context);
if (r < 0) if (r < 0)

View File

@ -416,19 +416,23 @@ fail:
} }
int server_open_kernel_seqnum(Server *s) { int server_open_kernel_seqnum(Server *s) {
_cleanup_close_ int fd; _cleanup_close_ int fd = -1;
const char *fn;
uint64_t *p; uint64_t *p;
int r; int r;
assert(s); assert(s);
/* We store the seqnum we last read in an mmaped file. That /* We store the seqnum we last read in an mmaped file. That way we can just use it like a variable,
* way we can just use it like a variable, but it is * but it is persistent and automatically flushed at reboot. */
* persistent and automatically flushed at reboot. */
fd = open("/run/systemd/journal/kernel-seqnum", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644); if (!s->read_kmsg)
return 0;
fn = strjoina(s->runtime_directory, "/kernel-seqnum");
fd = open(fn, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
if (fd < 0) { if (fd < 0) {
log_error_errno(errno, "Failed to open /run/systemd/journal/kernel-seqnum, ignoring: %m"); log_error_errno(errno, "Failed to open %s, ignoring: %m", fn);
return 0; return 0;
} }

View File

@ -450,17 +450,21 @@ void server_process_native_file(
} }
} }
int server_open_native_socket(Server *s) { int server_open_native_socket(Server *s, const char *native_socket) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/socket",
};
int r; int r;
assert(s); assert(s);
assert(native_socket);
if (s->native_fd < 0) { if (s->native_fd < 0) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
r = sockaddr_un_set_path(&sa.un, native_socket);
if (r < 0)
return log_error_errno(r, "Unable to use namespace path %s for AF_UNIX socket: %m", native_socket);
s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->native_fd < 0) if (s->native_fd < 0)
return log_error_errno(errno, "socket() failed: %m"); return log_error_errno(errno, "socket() failed: %m");

View File

@ -20,4 +20,4 @@ void server_process_native_file(
const char *label, const char *label,
size_t label_len); size_t label_len);
int server_open_native_socket(Server *s); int server_open_native_socket(Server *s, const char *native_socket);

View File

@ -99,7 +99,7 @@ void journal_ratelimit_free(JournalRateLimit *r) {
free(r); free(r);
} }
_pure_ static bool journal_ratelimit_group_expired(JournalRateLimitGroup *g, usec_t ts) { static bool journal_ratelimit_group_expired(JournalRateLimitGroup *g, usec_t ts) {
unsigned i; unsigned i;
assert(g); assert(g);

View File

@ -44,6 +44,7 @@
#include "missing_audit.h" #include "missing_audit.h"
#include "mkdir.h" #include "mkdir.h"
#include "parse-util.h" #include "parse-util.h"
#include "path-util.h"
#include "proc-cmdline.h" #include "proc-cmdline.h"
#include "process-util.h" #include "process-util.h"
#include "rm-rf.h" #include "rm-rf.h"
@ -76,11 +77,20 @@
#define DEFERRED_CLOSES_MAX (4096) #define DEFERRED_CLOSES_MAX (4096)
static int determine_path_usage(Server *s, const char *path, uint64_t *ret_used, uint64_t *ret_free) { #define IDLE_TIMEOUT_USEC (30*USEC_PER_SEC)
static int determine_path_usage(
Server *s,
const char *path,
uint64_t *ret_used,
uint64_t *ret_free) {
_cleanup_closedir_ DIR *d = NULL; _cleanup_closedir_ DIR *d = NULL;
struct dirent *de; struct dirent *de;
struct statvfs ss; struct statvfs ss;
assert(s);
assert(path);
assert(ret_used); assert(ret_used);
assert(ret_free); assert(ret_free);
@ -163,13 +173,19 @@ static void patch_min_use(JournalStorage *storage) {
storage->metrics.min_use = MAX(storage->metrics.min_use, storage->space.vfs_used); storage->metrics.min_use = MAX(storage->metrics.min_use, storage->space.vfs_used);
} }
static JournalStorage* server_current_storage(Server *s) {
assert(s);
return s->system_journal ? &s->system_storage : &s->runtime_storage;
}
static int determine_space(Server *s, uint64_t *available, uint64_t *limit) { static int determine_space(Server *s, uint64_t *available, uint64_t *limit) {
JournalStorage *js; JournalStorage *js;
int r; int r;
assert(s); assert(s);
js = s->system_journal ? &s->system_storage : &s->runtime_storage; js = server_current_storage(s);
r = cache_space_refresh(s, js); r = cache_space_refresh(s, js);
if (r >= 0) { if (r >= 0) {
@ -189,7 +205,7 @@ void server_space_usage_message(Server *s, JournalStorage *storage) {
assert(s); assert(s);
if (!storage) if (!storage)
storage = s->system_journal ? &s->system_storage : &s->runtime_storage; storage = server_current_storage(s);
if (cache_space_refresh(s, storage) < 0) if (cache_space_refresh(s, storage) < 0)
return; return;
@ -280,8 +296,18 @@ static int open_journal(
return r; return r;
} }
static bool flushed_flag_is_set(void) { static bool flushed_flag_is_set(Server *s) {
return access("/run/systemd/journal/flushed", F_OK) >= 0; const char *fn;
assert(s);
/* We don't support the "flushing" concept for namespace instances, we assume them to always have
* access to /var */
if (s->namespace)
return true;
fn = strjoina(s->runtime_directory, "/flushed");
return access(fn, F_OK) >= 0;
} }
static int system_journal_open(Server *s, bool flush_requested, bool relinquish_requested) { static int system_journal_open(Server *s, bool flush_requested, bool relinquish_requested) {
@ -290,17 +316,15 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_
if (!s->system_journal && if (!s->system_journal &&
IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) && IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) &&
(flush_requested || flushed_flag_is_set()) && (flush_requested || flushed_flag_is_set(s)) &&
!relinquish_requested) { !relinquish_requested) {
/* If in auto mode: first try to create the machine /* If in auto mode: first try to create the machine path, but not the prefix.
* path, but not the prefix.
* *
* If in persistent mode: create /var/log/journal and * If in persistent mode: create /var/log/journal and the machine path */
* the machine path */
if (s->storage == STORAGE_PERSISTENT) if (s->storage == STORAGE_PERSISTENT)
(void) mkdir_p("/var/log/journal/", 0755); (void) mkdir_parents(s->system_storage.path, 0755);
(void) mkdir(s->system_storage.path, 0755); (void) mkdir(s->system_storage.path, 0755);
@ -317,12 +341,11 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_
r = 0; r = 0;
} }
/* If the runtime journal is open, and we're post-flush, we're /* If the runtime journal is open, and we're post-flush, we're recovering from a failed
* recovering from a failed system journal rotate (ENOSPC) * system journal rotate (ENOSPC) for which the runtime journal was reopened.
* for which the runtime journal was reopened.
* *
* Perform an implicit flush to var, leaving the runtime * Perform an implicit flush to var, leaving the runtime journal closed, now that the system
* journal closed, now that the system journal is back. * journal is back.
*/ */
if (!flush_requested) if (!flush_requested)
(void) server_flush_to_var(s, true); (void) server_flush_to_var(s, true);
@ -349,12 +372,10 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_
} else { } else {
/* OK, we really need the runtime journal, so create /* OK, we really need the runtime journal, so create it if necessary. */
* it if necessary. */
(void) mkdir("/run/log", 0755); (void) mkdir_parents(s->runtime_storage.path, 0755);
(void) mkdir("/run/log/journal", 0755); (void) mkdir(s->runtime_storage.path, 0750);
(void) mkdir_parents(fn, 0750);
r = open_journal(s, true, fn, O_RDWR|O_CREAT, false, &s->runtime_storage.metrics, &s->runtime_journal); r = open_journal(s, true, fn, O_RDWR|O_CREAT, false, &s->runtime_storage.metrics, &s->runtime_journal);
if (r < 0) if (r < 0)
@ -373,27 +394,23 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_
static JournalFile* find_journal(Server *s, uid_t uid) { static JournalFile* find_journal(Server *s, uid_t uid) {
_cleanup_free_ char *p = NULL; _cleanup_free_ char *p = NULL;
int r;
JournalFile *f; JournalFile *f;
sd_id128_t machine; int r;
assert(s); assert(s);
/* A rotate that fails to create the new journal (ENOSPC) leaves the /* A rotate that fails to create the new journal (ENOSPC) leaves the rotated journal as NULL. Unless
* rotated journal as NULL. Unless we revisit opening, even after * we revisit opening, even after space is made available we'll continue to return NULL indefinitely.
* space is made available we'll continue to return NULL indefinitely.
* *
* system_journal_open() is a noop if the journals are already open, so * system_journal_open() is a noop if the journals are already open, so we can just call it here to
* we can just call it here to recover from failed rotates (or anything * recover from failed rotates (or anything else that's left the journals as NULL).
* else that's left the journals as NULL).
* *
* Fixes https://github.com/systemd/systemd/issues/3968 */ * Fixes https://github.com/systemd/systemd/issues/3968 */
(void) system_journal_open(s, false, false); (void) system_journal_open(s, false, false);
/* We split up user logs only on /var, not on /run. If the /* We split up user logs only on /var, not on /run. If the runtime file is open, we write to it
* runtime file is open, we write to it exclusively, in order * exclusively, in order to guarantee proper order as soon as we flush /run to /var and close the
* to guarantee proper order as soon as we flush /run to * runtime file. */
* /var and close the runtime file. */
if (s->runtime_journal) if (s->runtime_journal)
return s->runtime_journal; return s->runtime_journal;
@ -405,22 +422,14 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
if (f) if (f)
return f; return f;
r = sd_id128_get_machine(&machine); if (asprintf(&p, "%s/user-" UID_FMT ".journal", s->system_storage.path, uid) < 0) {
if (r < 0) {
log_debug_errno(r, "Failed to determine machine ID, using system log: %m");
return s->system_journal;
}
if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/user-"UID_FMT".journal",
SD_ID128_FORMAT_VAL(machine), uid) < 0) {
log_oom(); log_oom();
return s->system_journal; return s->system_journal;
} }
/* Too many open? Then let's close one (or more) */
while (ordered_hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) { while (ordered_hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) {
/* Too many open? Then let's close one */ assert_se(f = ordered_hashmap_steal_first(s->user_journals));
f = ordered_hashmap_steal_first(s->user_journals);
assert(f);
(void) journal_file_close(f); (void) journal_file_close(f);
} }
@ -428,14 +437,13 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
if (r < 0) if (r < 0)
return s->system_journal; return s->system_journal;
server_add_acls(f, uid);
r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f); r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f);
if (r < 0) { if (r < 0) {
(void) journal_file_close(f); (void) journal_file_close(f);
return s->system_journal; return s->system_journal;
} }
server_add_acls(f, uid);
return f; return f;
} }
@ -461,7 +469,6 @@ static int do_rotate(
} }
server_add_acls(*f, uid); server_add_acls(*f, uid);
return r; return r;
} }
@ -498,70 +505,37 @@ static void server_vacuum_deferred_closes(Server *s) {
} }
} }
static int open_user_journal_directory(Server *s, DIR **ret_dir, char **ret_path) { static int vacuum_offline_user_journals(Server *s) {
_cleanup_closedir_ DIR *dir = NULL; _cleanup_closedir_ DIR *d = NULL;
_cleanup_free_ char *path = NULL;
sd_id128_t machine;
int r; int r;
assert(s); assert(s);
r = sd_id128_get_machine(&machine); d = opendir(s->system_storage.path);
if (r < 0) if (!d) {
return log_error_errno(r, "Failed to determine machine ID, ignoring: %m"); if (errno == ENOENT)
if (asprintf(&path, "/var/log/journal/" SD_ID128_FORMAT_STR "/", SD_ID128_FORMAT_VAL(machine)) < 0)
return log_oom();
dir = opendir(path);
if (!dir)
return log_error_errno(errno, "Failed to open user journal directory '%s': %m", path);
if (ret_dir)
*ret_dir = TAKE_PTR(dir);
if (ret_path)
*ret_path = TAKE_PTR(path);
return 0; return 0;
return log_error_errno(errno, "Failed to open %s: %m", s->system_storage.path);
} }
void server_rotate(Server *s) { for (;;) {
_cleanup_free_ char *path = NULL;
_cleanup_closedir_ DIR *d = NULL;
JournalFile *f;
Iterator i;
void *k;
int r;
log_debug("Rotating...");
/* First, rotate the system journal (either in its runtime flavour or in its runtime flavour) */
(void) do_rotate(s, &s->runtime_journal, "runtime", false, 0);
(void) do_rotate(s, &s->system_journal, "system", s->seal, 0);
/* Then, rotate all user journals we have open (keeping them open) */
ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
r = do_rotate(s, &f, "user", s->seal, PTR_TO_UID(k));
if (r >= 0)
ordered_hashmap_replace(s->user_journals, k, f);
else if (!f)
/* Old file has been closed and deallocated */
ordered_hashmap_remove(s->user_journals, k);
}
/* Finally, also rotate all user journals we currently do not have open. (But do so only if we actually have
* access to /var, i.e. are not in the log-to-runtime-journal mode). */
if (!s->runtime_journal &&
open_user_journal_directory(s, &d, &path) >= 0) {
struct dirent *de;
FOREACH_DIRENT(de, d, log_warning_errno(errno, "Failed to enumerate %s, ignoring: %m", path)) {
_cleanup_free_ char *u = NULL, *full = NULL; _cleanup_free_ char *u = NULL, *full = NULL;
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
const char *a, *b; const char *a, *b;
struct dirent *de;
JournalFile *f;
uid_t uid; uid_t uid;
errno = 0;
de = readdir_no_dot(d);
if (!de) {
if (errno != 0)
log_warning_errno(errno, "Failed to enumerate %s, ignoring: %m", s->system_storage.path);
break;
}
a = startswith(de->d_name, "user-"); a = startswith(de->d_name, "user-");
if (!a) if (!a)
continue; continue;
@ -570,10 +544,8 @@ void server_rotate(Server *s) {
continue; continue;
u = strndup(a, b-a); u = strndup(a, b-a);
if (!u) { if (!u)
log_oom(); return log_oom();
break;
}
r = parse_uid(u, &uid); r = parse_uid(u, &uid);
if (r < 0) { if (r < 0) {
@ -585,11 +557,9 @@ void server_rotate(Server *s) {
if (ordered_hashmap_contains(s->user_journals, UID_TO_PTR(uid))) if (ordered_hashmap_contains(s->user_journals, UID_TO_PTR(uid)))
continue; continue;
full = strjoin(path, de->d_name); full = path_join(s->system_storage.path, de->d_name);
if (!full) { if (!full)
log_oom(); return log_oom();
break;
}
fd = openat(dirfd(d), de->d_name, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK); fd = openat(dirfd(d), de->d_name, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
if (fd < 0) { if (fd < 0) {
@ -634,8 +604,37 @@ void server_rotate(Server *s) {
f = journal_initiate_close(f, s->deferred_closes); f = journal_initiate_close(f, s->deferred_closes);
} }
return 0;
} }
void server_rotate(Server *s) {
JournalFile *f;
Iterator i;
void *k;
int r;
log_debug("Rotating...");
/* First, rotate the system journal (either in its runtime flavour or in its runtime flavour) */
(void) do_rotate(s, &s->runtime_journal, "runtime", false, 0);
(void) do_rotate(s, &s->system_journal, "system", s->seal, 0);
/* Then, rotate all user journals we have open (keeping them open) */
ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
r = do_rotate(s, &f, "user", s->seal, PTR_TO_UID(k));
if (r >= 0)
ordered_hashmap_replace(s->user_journals, k, f);
else if (!f)
/* Old file has been closed and deallocated */
ordered_hashmap_remove(s->user_journals, k);
}
/* Finally, also rotate all user journals we currently do not have open. (But do so only if we
* actually have access to /var, i.e. are not in the log-to-runtime-journal mode). */
if (!s->runtime_journal)
(void) vacuum_offline_user_journals(s);
server_process_deferred_closes(s); server_process_deferred_closes(s);
} }
@ -741,8 +740,7 @@ static void server_cache_hostname(Server *s) {
if (!x) if (!x)
return; return;
free(s->hostname_field); free_and_replace(s->hostname_field, x);
s->hostname_field = x;
} }
static bool shall_try_append_again(JournalFile *f, int r) { static bool shall_try_append_again(JournalFile *f, int r) {
@ -1003,6 +1001,9 @@ static void dispatch_message_real(
if (!isempty(s->hostname_field)) if (!isempty(s->hostname_field))
iovec[n++] = IOVEC_MAKE_STRING(s->hostname_field); iovec[n++] = IOVEC_MAKE_STRING(s->hostname_field);
if (!isempty(s->namespace_field))
iovec[n++] = IOVEC_MAKE_STRING(s->namespace_field);
assert(n <= m); assert(n <= m);
if (s->split_mode == SPLIT_UID && c && uid_is_valid(c->uid)) if (s->split_mode == SPLIT_UID && c && uid_is_valid(c->uid))
@ -1115,10 +1116,11 @@ void server_dispatch_message(
} }
int server_flush_to_var(Server *s, bool require_flag_file) { int server_flush_to_var(Server *s, bool require_flag_file) {
sd_journal *j = NULL;
char ts[FORMAT_TIMESPAN_MAX]; char ts[FORMAT_TIMESPAN_MAX];
usec_t start; sd_journal *j = NULL;
const char *fn;
unsigned n = 0; unsigned n = 0;
usec_t start;
int r, k; int r, k;
assert(s); assert(s);
@ -1126,10 +1128,13 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
if (!IN_SET(s->storage, STORAGE_AUTO, STORAGE_PERSISTENT)) if (!IN_SET(s->storage, STORAGE_AUTO, STORAGE_PERSISTENT))
return 0; return 0;
if (!s->runtime_journal) if (s->namespace) /* Flushing concept does not exist for namespace instances */
return 0; return 0;
if (require_flag_file && !flushed_flag_is_set()) if (!s->runtime_journal) /* Nothing to flush? */
return 0;
if (require_flag_file && !flushed_flag_is_set(s))
return 0; return 0;
(void) system_journal_open(s, true, false); (void) system_journal_open(s, true, false);
@ -1137,7 +1142,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
if (!s->system_journal) if (!s->system_journal)
return 0; return 0;
log_debug("Flushing to /var..."); log_debug("Flushing to %s...", s->system_storage.path);
start = now(CLOCK_MONOTONIC); start = now(CLOCK_MONOTONIC);
@ -1197,33 +1202,40 @@ finish:
s->runtime_journal = journal_file_close(s->runtime_journal); s->runtime_journal = journal_file_close(s->runtime_journal);
if (r >= 0) if (r >= 0)
(void) rm_rf("/run/log/journal", REMOVE_ROOT); (void) rm_rf(s->runtime_storage.path, REMOVE_ROOT);
sd_journal_close(j); sd_journal_close(j);
server_driver_message(s, 0, NULL, server_driver_message(s, 0, NULL,
LOG_MESSAGE("Time spent on flushing to /var is %s for %u entries.", LOG_MESSAGE("Time spent on flushing to %s is %s for %u entries.",
s->system_storage.path,
format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0), format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0),
n), n),
NULL); NULL);
k = touch("/run/systemd/journal/flushed"); fn = strjoina(s->runtime_directory, "/flushed");
k = touch(fn);
if (k < 0) if (k < 0)
log_warning_errno(k, "Failed to touch /run/systemd/journal/flushed, ignoring: %m"); log_warning_errno(k, "Failed to touch %s, ignoring: %m", fn);
server_refresh_idle_timer(s);
return r; return r;
} }
static int server_relinquish_var(Server *s) { static int server_relinquish_var(Server *s) {
const char *fn;
assert(s); assert(s);
if (s->storage == STORAGE_NONE) if (s->storage == STORAGE_NONE)
return 0; return 0;
if (s->namespace) /* Concept does not exist for namespaced instances */
return -EOPNOTSUPP;
if (s->runtime_journal && !s->system_journal) if (s->runtime_journal && !s->system_journal)
return 0; return 0;
log_debug("Relinquishing /var..."); log_debug("Relinquishing %s...", s->system_storage.path);
(void) system_journal_open(s, false, true); (void) system_journal_open(s, false, true);
@ -1231,13 +1243,20 @@ static int server_relinquish_var(Server *s) {
ordered_hashmap_clear_with_destructor(s->user_journals, journal_file_close); ordered_hashmap_clear_with_destructor(s->user_journals, journal_file_close);
set_clear_with_destructor(s->deferred_closes, journal_file_close); set_clear_with_destructor(s->deferred_closes, journal_file_close);
if (unlink("/run/systemd/journal/flushed") < 0 && errno != ENOENT) fn = strjoina(s->runtime_directory, "/flushed");
log_warning_errno(errno, "Failed to unlink /run/systemd/journal/flushed, ignoring: %m"); if (unlink(fn) < 0 && errno != ENOENT)
log_warning_errno(errno, "Failed to unlink %s, ignoring: %m", fn);
server_refresh_idle_timer(s);
return 0; return 0;
} }
int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata) { int server_process_datagram(
sd_event_source *es,
int fd,
uint32_t revents,
void *userdata) {
Server *s = userdata; Server *s = userdata;
struct ucred *ucred = NULL; struct ucred *ucred = NULL;
struct timeval *tv = NULL; struct timeval *tv = NULL;
@ -1352,6 +1371,8 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
} }
close_many(fds, n_fds); close_many(fds, n_fds);
server_refresh_idle_timer(s);
return 0; return 0;
} }
@ -1363,6 +1384,8 @@ static void server_full_flush(Server *s) {
server_vacuum(s, false); server_vacuum(s, false);
server_space_usage_message(s, NULL); server_space_usage_message(s, NULL);
server_refresh_idle_timer(s);
} }
static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
@ -1370,6 +1393,11 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *
assert(s); assert(s);
if (s->namespace) {
log_error("Received SIGUSR1 signal from PID " PID_FMT ", but flushing runtime journals not supported for namespaced instances.", si->ssi_pid);
return 0;
}
log_info("Received SIGUSR1 signal from PID " PID_FMT ", as request to flush runtime journal.", si->ssi_pid); log_info("Received SIGUSR1 signal from PID " PID_FMT ", as request to flush runtime journal.", si->ssi_pid);
server_full_flush(s); server_full_flush(s);
@ -1377,6 +1405,7 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *
} }
static void server_full_rotate(Server *s) { static void server_full_rotate(Server *s) {
const char *fn;
int r; int r;
assert(s); assert(s);
@ -1390,9 +1419,10 @@ static void server_full_rotate(Server *s) {
patch_min_use(&s->runtime_storage); patch_min_use(&s->runtime_storage);
/* Let clients know when the most recent rotation happened. */ /* Let clients know when the most recent rotation happened. */
r = write_timestamp_file_atomic("/run/systemd/journal/rotated", now(CLOCK_MONOTONIC)); fn = strjoina(s->runtime_directory, "/rotated");
r = write_timestamp_file_atomic(fn, now(CLOCK_MONOTONIC));
if (r < 0) if (r < 0)
log_warning_errno(r, "Failed to write /run/systemd/journal/rotated, ignoring: %m"); log_warning_errno(r, "Failed to write %s, ignoring: %m", fn);
} }
static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
@ -1418,6 +1448,7 @@ static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *
} }
static void server_full_sync(Server *s) { static void server_full_sync(Server *s) {
const char *fn;
int r; int r;
assert(s); assert(s);
@ -1425,9 +1456,10 @@ static void server_full_sync(Server *s) {
server_sync(s); server_sync(s);
/* Let clients know when the most recent sync happened. */ /* Let clients know when the most recent sync happened. */
r = write_timestamp_file_atomic("/run/systemd/journal/synced", now(CLOCK_MONOTONIC)); fn = strjoina(s->runtime_directory, "/synced");
r = write_timestamp_file_atomic(fn, now(CLOCK_MONOTONIC));
if (r < 0) if (r < 0)
log_warning_errno(r, "Failed to write /run/systemd/journal/synced, ignoring: %m"); log_warning_errno(r, "Failed to write %s, ignoring: %m", fn);
return; return;
} }
@ -1592,8 +1624,28 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
} }
static int server_parse_config_file(Server *s) { static int server_parse_config_file(Server *s) {
int r;
assert(s); assert(s);
if (s->namespace) {
const char *namespaced;
/* If we are running in namespace mode, load the namespace specific configuration file, and nothing else */
namespaced = strjoina(PKGSYSCONFDIR "/journald@", s->namespace, ".conf");
r = config_parse(
NULL,
namespaced, NULL,
"Journal\0",
config_item_perf_lookup, journald_gperf_lookup,
CONFIG_PARSE_WARN, s);
if (r < 0)
return r;
return 0;
}
return config_parse_many_nulstr(PKGSYSCONFDIR "/journald.conf", return config_parse_many_nulstr(PKGSYSCONFDIR "/journald.conf",
CONF_PATHS_NULSTR("systemd/journald.conf.d"), CONF_PATHS_NULSTR("systemd/journald.conf.d"),
"Journal\0", "Journal\0",
@ -1936,6 +1988,8 @@ static int vl_method_flush_to_var(Varlink *link, JsonVariant *parameters, Varlin
if (json_variant_elements(parameters) > 0) if (json_variant_elements(parameters) > 0)
return varlink_error_invalid_parameter(link, parameters); return varlink_error_invalid_parameter(link, parameters);
if (s->namespace)
return varlink_error(link, "io.systemd.Journal.NotSupportedByNamespaces", NULL);
log_info("Received client request to flush runtime journal."); log_info("Received client request to flush runtime journal.");
server_full_flush(s); server_full_flush(s);
@ -1951,14 +2005,38 @@ static int vl_method_relinquish_var(Varlink *link, JsonVariant *parameters, Varl
if (json_variant_elements(parameters) > 0) if (json_variant_elements(parameters) > 0)
return varlink_error_invalid_parameter(link, parameters); return varlink_error_invalid_parameter(link, parameters);
if (s->namespace)
return varlink_error(link, "io.systemd.Journal.NotSupportedByNamespaces", NULL);
log_info("Received client request to relinquish /var access."); log_info("Received client request to relinquish %s access.", s->system_storage.path);
server_relinquish_var(s); server_relinquish_var(s);
return varlink_reply(link, NULL); return varlink_reply(link, NULL);
} }
static int server_open_varlink(Server *s) { static int vl_connect(VarlinkServer *server, Varlink *link, void *userdata) {
Server *s = userdata;
assert(server);
assert(link);
assert(s);
(void) server_start_or_stop_idle_timer(s); /* maybe we are no longer idle */
return 0;
}
static void vl_disconnect(VarlinkServer *server, Varlink *link, void *userdata) {
Server *s = userdata;
assert(server);
assert(link);
assert(s);
(void) server_start_or_stop_idle_timer(s); /* maybe we are idle now */
}
static int server_open_varlink(Server *s, const char *socket, int fd) {
int r; int r;
assert(s); assert(s);
@ -1978,7 +2056,18 @@ static int server_open_varlink(Server *s) {
if (r < 0) if (r < 0)
return r; return r;
r = varlink_server_listen_address(s->varlink_server, "/run/systemd/journal/io.systemd.journal", 0600); r = varlink_server_bind_connect(s->varlink_server, vl_connect);
if (r < 0)
return r;
r = varlink_server_bind_disconnect(s->varlink_server, vl_disconnect);
if (r < 0)
return r;
if (fd < 0)
r = varlink_server_listen_address(s->varlink_server, socket, 0600);
else
r = varlink_server_listen_fd(s->varlink_server, fd);
if (r < 0) if (r < 0)
return r; return r;
@ -1989,9 +2078,117 @@ static int server_open_varlink(Server *s) {
return 0; return 0;
} }
int server_init(Server *s) { static bool server_is_idle(Server *s) {
assert(s);
/* The server for the main namespace is never idle */
if (!s->namespace)
return false;
/* If a retention maximum is set larger than the idle time we need to be running to enforce it, hence
* turn off the idle logic. */
if (s->max_retention_usec > IDLE_TIMEOUT_USEC)
return false;
/* We aren't idle if we have a varlink client */
if (varlink_server_current_connections(s->varlink_server) > 0)
return false;
/* If we have stdout streams we aren't idle */
if (s->n_stdout_streams > 0)
return false;
return true;
}
static int server_idle_handler(sd_event_source *source, uint64_t usec, void *userdata) {
Server *s = userdata;
assert(source);
assert(s);
log_debug("Server is idle, exiting.");
sd_event_exit(s->event, 0);
return 0;
}
int server_start_or_stop_idle_timer(Server *s) {
_cleanup_(sd_event_source_unrefp) sd_event_source *source = NULL;
usec_t when;
int r;
assert(s);
if (!server_is_idle(s)) {
s->idle_event_source = sd_event_source_disable_unref(s->idle_event_source);
return 0;
}
if (s->idle_event_source)
return 1;
r = sd_event_now(s->event, CLOCK_MONOTONIC, &when);
if (r < 0)
return log_error_errno(r, "Failed to determine current time: %m");
r = sd_event_add_time(s->event, &source, CLOCK_MONOTONIC, usec_add(when, IDLE_TIMEOUT_USEC), 0, server_idle_handler, s);
if (r < 0)
return log_error_errno(r, "Failed to allocate idle timer: %m");
r = sd_event_source_set_priority(source, SD_EVENT_PRIORITY_IDLE);
if (r < 0)
return log_error_errno(r, "Failed to set idle timer priority: %m");
(void) sd_event_source_set_description(source, "idle-timer");
s->idle_event_source = TAKE_PTR(source);
return 1;
}
int server_refresh_idle_timer(Server *s) {
usec_t when;
int r;
assert(s);
if (!s->idle_event_source)
return 0;
r = sd_event_now(s->event, CLOCK_MONOTONIC, &when);
if (r < 0)
return log_error_errno(r, "Failed to determine current time: %m");
r = sd_event_source_set_time(s->idle_event_source, usec_add(when, IDLE_TIMEOUT_USEC));
if (r < 0)
return log_error_errno(r, "Failed to refresh idle timer: %m");
return 1;
}
static int set_namespace(Server *s, const char *namespace) {
assert(s);
if (!namespace)
return 0;
if (!log_namespace_name_valid(namespace))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specified namespace name not valid, refusing: %s", namespace);
s->namespace = strdup(namespace);
if (!s->namespace)
return log_oom();
s->namespace_field = strjoin("_NAMESPACE=", namespace);
if (!s->namespace_field)
return log_oom();
return 1;
}
int server_init(Server *s, const char *namespace) {
const char *native_socket, *syslog_socket, *stdout_socket, *varlink_socket, *e;
_cleanup_fdset_free_ FDSet *fds = NULL; _cleanup_fdset_free_ FDSet *fds = NULL;
int n, r, fd; int n, r, fd, varlink_fd = -1;
bool no_sockets; bool no_sockets;
assert(s); assert(s);
@ -2008,7 +2205,6 @@ int server_init(Server *s) {
.compress.enabled = true, .compress.enabled = true,
.compress.threshold_bytes = (uint64_t) -1, .compress.threshold_bytes = (uint64_t) -1,
.seal = true, .seal = true,
.read_kmsg = true,
.watchdog_usec = USEC_INFINITY, .watchdog_usec = USEC_INFINITY,
@ -2034,22 +2230,43 @@ int server_init(Server *s) {
.system_storage.name = "System Journal", .system_storage.name = "System Journal",
}; };
r = set_namespace(s, namespace);
if (r < 0)
return r;
/* By default, only read from /dev/kmsg if are the main namespace */
s->read_kmsg = !s->namespace;
s->storage = s->namespace ? STORAGE_PERSISTENT : STORAGE_AUTO;
journal_reset_metrics(&s->system_storage.metrics); journal_reset_metrics(&s->system_storage.metrics);
journal_reset_metrics(&s->runtime_storage.metrics); journal_reset_metrics(&s->runtime_storage.metrics);
server_parse_config_file(s); server_parse_config_file(s);
if (!s->namespace) {
/* Parse kernel command line, but only if we are not a namespace instance */
r = proc_cmdline_parse(parse_proc_cmdline_item, s, PROC_CMDLINE_STRIP_RD_PREFIX); r = proc_cmdline_parse(parse_proc_cmdline_item, s, PROC_CMDLINE_STRIP_RD_PREFIX);
if (r < 0) if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
}
if (!!s->ratelimit_interval ^ !!s->ratelimit_burst) { if (!!s->ratelimit_interval != !!s->ratelimit_burst) { /* One set to 0 and the other not? */
log_debug("Setting both rate limit interval and burst from "USEC_FMT",%u to 0,0", log_debug("Setting both rate limit interval and burst from "USEC_FMT",%u to 0,0",
s->ratelimit_interval, s->ratelimit_burst); s->ratelimit_interval, s->ratelimit_burst);
s->ratelimit_interval = s->ratelimit_burst = 0; s->ratelimit_interval = s->ratelimit_burst = 0;
} }
(void) mkdir_p("/run/systemd/journal", 0755); e = getenv("RUNTIME_DIRECTORY");
if (e)
s->runtime_directory = strdup(e);
else if (s->namespace)
s->runtime_directory = strjoin("/run/systemd/journal.", s->namespace);
else
s->runtime_directory = strdup("/run/systemd/journal");
if (!s->runtime_directory)
return log_oom();
(void) mkdir_p(s->runtime_directory, 0755);
s->user_journals = ordered_hashmap_new(NULL); s->user_journals = ordered_hashmap_new(NULL);
if (!s->user_journals) if (!s->user_journals)
@ -2071,9 +2288,14 @@ int server_init(Server *s) {
if (n < 0) if (n < 0)
return log_error_errno(n, "Failed to read listening file descriptors from environment: %m"); return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
native_socket = strjoina(s->runtime_directory, "/socket");
stdout_socket = strjoina(s->runtime_directory, "/stdout");
syslog_socket = strjoina(s->runtime_directory, "/dev-log");
varlink_socket = strjoina(s->runtime_directory, "/io.systemd.journal");
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { 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 (sd_is_socket_unix(fd, SOCK_DGRAM, -1, native_socket, 0) > 0) {
if (s->native_fd >= 0) if (s->native_fd >= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@ -2081,7 +2303,7 @@ int server_init(Server *s) {
s->native_fd = fd; s->native_fd = fd;
} else if (sd_is_socket_unix(fd, SOCK_STREAM, 1, "/run/systemd/journal/stdout", 0) > 0) { } else if (sd_is_socket_unix(fd, SOCK_STREAM, 1, stdout_socket, 0) > 0) {
if (s->stdout_fd >= 0) if (s->stdout_fd >= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@ -2089,8 +2311,7 @@ int server_init(Server *s) {
s->stdout_fd = fd; s->stdout_fd = fd;
} else if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/dev/log", 0) > 0 || } else if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, syslog_socket, 0) > 0) {
sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/run/systemd/journal/dev-log", 0) > 0) {
if (s->syslog_fd >= 0) if (s->syslog_fd >= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@ -2098,6 +2319,13 @@ int server_init(Server *s) {
s->syslog_fd = fd; s->syslog_fd = fd;
} else if (sd_is_socket_unix(fd, SOCK_STREAM, 1, varlink_socket, 0) > 0) {
if (varlink_fd >= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Too many varlink sockets passed.");
varlink_fd = fd;
} else if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) { } else if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
if (s->audit_fd >= 0) if (s->audit_fd >= 0)
@ -2128,22 +2356,22 @@ int server_init(Server *s) {
fds = fdset_free(fds); fds = fdset_free(fds);
} }
no_sockets = s->native_fd < 0 && s->stdout_fd < 0 && s->syslog_fd < 0 && s->audit_fd < 0; no_sockets = s->native_fd < 0 && s->stdout_fd < 0 && s->syslog_fd < 0 && s->audit_fd < 0 && varlink_fd < 0;
/* always open stdout, syslog, native, and kmsg sockets */ /* always open stdout, syslog, native, and kmsg sockets */
/* systemd-journald.socket: /run/systemd/journal/stdout */ /* systemd-journald.socket: /run/systemd/journal/stdout */
r = server_open_stdout_socket(s); r = server_open_stdout_socket(s, stdout_socket);
if (r < 0) if (r < 0)
return r; return r;
/* systemd-journald-dev-log.socket: /run/systemd/journal/dev-log */ /* systemd-journald-dev-log.socket: /run/systemd/journal/dev-log */
r = server_open_syslog_socket(s); r = server_open_syslog_socket(s, syslog_socket);
if (r < 0) if (r < 0)
return r; return r;
/* systemd-journald.socket: /run/systemd/journal/socket */ /* systemd-journald.socket: /run/systemd/journal/socket */
r = server_open_native_socket(s); r = server_open_native_socket(s, native_socket);
if (r < 0) if (r < 0)
return r; return r;
@ -2159,7 +2387,7 @@ int server_init(Server *s) {
return r; return r;
} }
r = server_open_varlink(s); r = server_open_varlink(s, varlink_socket, varlink_fd);
if (r < 0) if (r < 0)
return r; return r;
@ -2177,26 +2405,43 @@ int server_init(Server *s) {
s->ratelimit = journal_ratelimit_new(); s->ratelimit = journal_ratelimit_new();
if (!s->ratelimit) if (!s->ratelimit)
return -ENOMEM; return log_oom();
r = cg_get_root_path(&s->cgroup_root); r = cg_get_root_path(&s->cgroup_root);
if (r < 0) if (r < 0)
return r; return log_error_errno(r, "Failed to acquire cgroup root path: %m");
server_cache_hostname(s); server_cache_hostname(s);
server_cache_boot_id(s); server_cache_boot_id(s);
server_cache_machine_id(s); server_cache_machine_id(s);
s->runtime_storage.path = path_join("/run/log/journal", SERVER_MACHINE_ID(s)); if (s->namespace)
s->system_storage.path = path_join("/var/log/journal", SERVER_MACHINE_ID(s)); s->runtime_storage.path = strjoin("/run/log/journal/", SERVER_MACHINE_ID(s), ".", s->namespace);
if (!s->runtime_storage.path || !s->system_storage.path) else
return -ENOMEM; s->runtime_storage.path = strjoin("/run/log/journal/", SERVER_MACHINE_ID(s));
if (!s->runtime_storage.path)
return log_oom();
e = getenv("LOGS_DIRECTORY");
if (e)
s->system_storage.path = strdup(e);
else if (s->namespace)
s->system_storage.path = strjoin("/var/log/journal/", SERVER_MACHINE_ID(s), ".", s->namespace);
else
s->system_storage.path = strjoin("/var/log/journal/", SERVER_MACHINE_ID(s));
if (!s->system_storage.path)
return log_oom();
(void) server_connect_notify(s); (void) server_connect_notify(s);
(void) client_context_acquire_default(s); (void) client_context_acquire_default(s);
return system_journal_open(s, false, false); r = system_journal_open(s, false, false);
if (r < 0)
return r;
server_start_or_stop_idle_timer(s);
return 0;
} }
void server_maybe_append_tags(Server *s) { void server_maybe_append_tags(Server *s) {
@ -2218,6 +2463,9 @@ void server_maybe_append_tags(Server *s) {
void server_done(Server *s) { void server_done(Server *s) {
assert(s); assert(s);
free(s->namespace);
free(s->namespace_field);
set_free_with_destructor(s->deferred_closes, journal_file_close); set_free_with_destructor(s->deferred_closes, journal_file_close);
while (s->stdout_streams) while (s->stdout_streams)
@ -2246,6 +2494,7 @@ void server_done(Server *s) {
sd_event_source_unref(s->hostname_event_source); sd_event_source_unref(s->hostname_event_source);
sd_event_source_unref(s->notify_event_source); sd_event_source_unref(s->notify_event_source);
sd_event_source_unref(s->watchdog_event_source); sd_event_source_unref(s->watchdog_event_source);
sd_event_source_unref(s->idle_event_source);
sd_event_unref(s->event); sd_event_unref(s->event);
safe_close(s->syslog_fd); safe_close(s->syslog_fd);
@ -2268,6 +2517,7 @@ void server_done(Server *s) {
free(s->hostname_field); free(s->hostname_field);
free(s->runtime_storage.path); free(s->runtime_storage.path);
free(s->system_storage.path); free(s->system_storage.path);
free(s->runtime_directory);
mmap_cache_unref(s->mmap); mmap_cache_unref(s->mmap);
} }

View File

@ -60,6 +60,8 @@ typedef struct JournalStorage {
} JournalStorage; } JournalStorage;
struct Server { struct Server {
char *namespace;
int syslog_fd; int syslog_fd;
int native_fd; int native_fd;
int stdout_fd; int stdout_fd;
@ -84,6 +86,7 @@ struct Server {
sd_event_source *hostname_event_source; sd_event_source *hostname_event_source;
sd_event_source *notify_event_source; sd_event_source *notify_event_source;
sd_event_source *watchdog_event_source; sd_event_source *watchdog_event_source;
sd_event_source *idle_event_source;
JournalFile *runtime_journal; JournalFile *runtime_journal;
JournalFile *system_journal; JournalFile *system_journal;
@ -147,6 +150,8 @@ struct Server {
char machine_id_field[sizeof("_MACHINE_ID=") + 32]; char machine_id_field[sizeof("_MACHINE_ID=") + 32];
char boot_id_field[sizeof("_BOOT_ID=") + 32]; char boot_id_field[sizeof("_BOOT_ID=") + 32];
char *hostname_field; char *hostname_field;
char *namespace_field;
char *runtime_directory;
/* Cached cgroup root, so that we don't have to query that all the time */ /* Cached cgroup root, so that we don't have to query that all the time */
char *cgroup_root; char *cgroup_root;
@ -172,7 +177,7 @@ struct Server {
#define SERVER_MACHINE_ID(s) ((s)->machine_id_field + STRLEN("_MACHINE_ID=")) #define SERVER_MACHINE_ID(s) ((s)->machine_id_field + STRLEN("_MACHINE_ID="))
/* Extra fields for any log messages */ /* Extra fields for any log messages */
#define N_IOVEC_META_FIELDS 22 #define N_IOVEC_META_FIELDS 23
/* Extra fields for log messages that contain OBJECT_PID= (i.e. log about another process) */ /* Extra fields for log messages that contain OBJECT_PID= (i.e. log about another process) */
#define N_IOVEC_OBJECT_FIELDS 18 #define N_IOVEC_OBJECT_FIELDS 18
@ -204,7 +209,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_split_mode);
const char *split_mode_to_string(SplitMode s) _const_; const char *split_mode_to_string(SplitMode s) _const_;
SplitMode split_mode_from_string(const char *s) _pure_; SplitMode split_mode_from_string(const char *s) _pure_;
int server_init(Server *s); int server_init(Server *s, const char *namespace);
void server_done(Server *s); void server_done(Server *s);
void server_sync(Server *s); void server_sync(Server *s);
int server_vacuum(Server *s, bool verbose); int server_vacuum(Server *s, bool verbose);
@ -214,3 +219,6 @@ int server_flush_to_var(Server *s, bool require_flag_file);
void server_maybe_append_tags(Server *s); void server_maybe_append_tags(Server *s);
int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata); int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata);
void server_space_usage_message(Server *s, JournalStorage *storage); void server_space_usage_message(Server *s, JournalStorage *storage);
int server_start_or_stop_idle_timer(Server *s);
int server_refresh_idle_timer(Server *s);

View File

@ -17,6 +17,7 @@
#include "escape.h" #include "escape.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "fs-util.h"
#include "io-util.h" #include "io-util.h"
#include "journald-console.h" #include "journald-console.h"
#include "journald-context.h" #include "journald-context.h"
@ -109,6 +110,8 @@ void stdout_stream_free(StdoutStream *s) {
if (s->in_notify_queue) if (s->in_notify_queue)
LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
(void) server_start_or_stop_idle_timer(s->server); /* Maybe we are idle now? */
} }
if (s->event_source) { if (s->event_source) {
@ -139,7 +142,7 @@ void stdout_stream_destroy(StdoutStream *s) {
} }
static int stdout_stream_save(StdoutStream *s) { static int stdout_stream_save(StdoutStream *s) {
_cleanup_free_ char *temp_path = NULL; _cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
int r; int r;
@ -156,11 +159,12 @@ static int stdout_stream_save(StdoutStream *s) {
return log_warning_errno(errno, "Failed to stat connected stream: %m"); return log_warning_errno(errno, "Failed to stat connected stream: %m");
/* We use device and inode numbers as identifier for the stream */ /* We use device and inode numbers as identifier for the stream */
if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0) r = asprintf(&s->state_file, "%s/streams/%lu:%lu", s->server->runtime_directory, (unsigned long) st.st_dev, (unsigned long) st.st_ino);
if (r < 0)
return log_oom(); return log_oom();
} }
(void) mkdir_p("/run/systemd/journal/streams", 0755); (void) mkdir_parents(s->state_file, 0755);
r = fopen_temporary(s->state_file, &f, &temp_path); r = fopen_temporary(s->state_file, &f, &temp_path);
if (r < 0) if (r < 0)
@ -214,6 +218,8 @@ static int stdout_stream_save(StdoutStream *s) {
goto fail; goto fail;
} }
temp_path = mfree(temp_path);
if (!s->fdstore && !s->in_notify_queue) { if (!s->fdstore && !s->in_notify_queue) {
LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
s->in_notify_queue = true; s->in_notify_queue = true;
@ -229,10 +235,6 @@ static int stdout_stream_save(StdoutStream *s) {
fail: fail:
(void) unlink(s->state_file); (void) unlink(s->state_file);
if (temp_path)
(void) unlink(temp_path);
return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file); return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
} }
@ -590,12 +592,14 @@ int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to generate stream ID: %m"); return log_error_errno(r, "Failed to generate stream ID: %m");
stream = new0(StdoutStream, 1); stream = new(StdoutStream, 1);
if (!stream) if (!stream)
return log_oom(); return log_oom();
stream->fd = -1; *stream = (StdoutStream) {
stream->priority = LOG_INFO; .fd = -1,
.priority = LOG_INFO,
};
xsprintf(stream->id_field, "_STREAM_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)); xsprintf(stream->id_field, "_STREAM_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id));
@ -629,11 +633,12 @@ int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
LIST_PREPEND(stdout_stream, s->stdout_streams, stream); LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
s->n_stdout_streams++; s->n_stdout_streams++;
(void) server_start_or_stop_idle_timer(s); /* Maybe no longer idle? */
if (ret) if (ret)
*ret = stream; *ret = stream;
stream = NULL; TAKE_PTR(stream);
return 0; return 0;
} }
@ -676,7 +681,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
if (r < 0) if (r < 0)
return r; return r;
fd = -1; TAKE_FD(fd);
return 0; return 0;
} }
@ -694,7 +699,7 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) {
assert(fname); assert(fname);
if (!stream->state_file) { if (!stream->state_file) {
stream->state_file = path_join("/run/systemd/journal/streams", fname); stream->state_file = path_join(stream->server->runtime_directory, "streams", fname);
if (!stream->state_file) if (!stream->state_file)
return log_oom(); return log_oom();
} }
@ -783,14 +788,16 @@ static int stdout_stream_restore(Server *s, const char *fname, int fd) {
int server_restore_streams(Server *s, FDSet *fds) { int server_restore_streams(Server *s, FDSet *fds) {
_cleanup_closedir_ DIR *d = NULL; _cleanup_closedir_ DIR *d = NULL;
struct dirent *de; struct dirent *de;
const char *path;
int r; int r;
d = opendir("/run/systemd/journal/streams"); path = strjoina(s->runtime_directory, "/streams");
d = opendir(path);
if (!d) { if (!d) {
if (errno == ENOENT) if (errno == ENOENT)
return 0; return 0;
return log_warning_errno(errno, "Failed to enumerate /run/systemd/journal/streams: %m"); return log_warning_errno(errno, "Failed to enumerate %s: %m", path);
} }
FOREACH_DIRENT(de, d, goto fail) { FOREACH_DIRENT(de, d, goto fail) {
@ -818,8 +825,7 @@ int server_restore_streams(Server *s, FDSet *fds) {
/* No file descriptor? Then let's delete the state file */ /* No file descriptor? Then let's delete the state file */
log_debug("Cannot restore stream file %s", de->d_name); log_debug("Cannot restore stream file %s", de->d_name);
if (unlinkat(dirfd(d), de->d_name, 0) < 0) if (unlinkat(dirfd(d), de->d_name, 0) < 0)
log_warning_errno(errno, "Failed to remove /run/systemd/journal/streams/%s: %m", log_warning_errno(errno, "Failed to remove %s%s: %m", path, de->d_name);
de->d_name);
continue; continue;
} }
@ -836,16 +842,21 @@ fail:
return log_error_errno(errno, "Failed to read streams directory: %m"); return log_error_errno(errno, "Failed to read streams directory: %m");
} }
int server_open_stdout_socket(Server *s) { int server_open_stdout_socket(Server *s, const char *stdout_socket) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
int r; int r;
assert(s); assert(s);
assert(stdout_socket);
if (s->stdout_fd < 0) { if (s->stdout_fd < 0) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
r = sockaddr_un_set_path(&sa.un, stdout_socket);
if (r < 0)
return log_error_errno(r, "Unable to use namespace path %s for AF_UNIX socket: %m", stdout_socket);
s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->stdout_fd < 0) if (s->stdout_fd < 0)
return log_error_errno(errno, "socket() failed: %m"); return log_error_errno(errno, "socket() failed: %m");

View File

@ -6,7 +6,7 @@ typedef struct StdoutStream StdoutStream;
#include "fdset.h" #include "fdset.h"
#include "journald-server.h" #include "journald-server.h"
int server_open_stdout_socket(Server *s); int server_open_stdout_socket(Server *s, const char *stdout_socket);
int server_restore_streams(Server *s, FDSet *fds); int server_restore_streams(Server *s, FDSet *fds);
void stdout_stream_free(StdoutStream *s); void stdout_stream_free(StdoutStream *s);

View File

@ -25,11 +25,15 @@
/* Warn once every 30s if we missed syslog message */ /* Warn once every 30s if we missed syslog message */
#define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC) #define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC)
static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, const struct ucred *ucred, const struct timeval *tv) { static void forward_syslog_iovec(
Server *s,
const struct iovec *iovec,
unsigned n_iovec,
const struct ucred *ucred,
const struct timeval *tv) {
static const union sockaddr_union sa = { union sockaddr_union sa = {
.un.sun_family = AF_UNIX, .un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/syslog",
}; };
struct msghdr msghdr = { struct msghdr msghdr = {
.msg_iov = (struct iovec *) iovec, .msg_iov = (struct iovec *) iovec,
@ -42,11 +46,20 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
struct cmsghdr cmsghdr; struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
} control; } control;
const char *j;
int r;
assert(s); assert(s);
assert(iovec); assert(iovec);
assert(n_iovec > 0); assert(n_iovec > 0);
j = strjoina(s->runtime_directory, "/syslog");
r = sockaddr_un_set_path(&sa.un, j);
if (r < 0) {
log_debug_errno(r, "Forwarding socket path %s too long for AF_UNIX, not forwarding: %m", j);
return;
}
if (ucred) { if (ucred) {
zero(control); zero(control);
msghdr.msg_control = &control; msghdr.msg_control = &control;
@ -441,17 +454,21 @@ void server_process_syslog_message(
server_dispatch_message(s, iovec, n, m, context, tv, priority, 0); server_dispatch_message(s, iovec, n, m, context, tv, priority, 0);
} }
int server_open_syslog_socket(Server *s) { int server_open_syslog_socket(Server *s, const char *syslog_socket) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/dev-log",
};
int r; int r;
assert(s); assert(s);
assert(syslog_socket);
if (s->syslog_fd < 0) { if (s->syslog_fd < 0) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
r = sockaddr_un_set_path(&sa.un, syslog_socket);
if (r < 0)
return log_error_errno(r, "Unable to use namespace path %s for AF_UNIX socket: %m", syslog_socket);
s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->syslog_fd < 0) if (s->syslog_fd < 0)
return log_error_errno(errno, "socket() failed: %m"); return log_error_errno(errno, "socket() failed: %m");

View File

@ -10,6 +10,6 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid);
void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred, const struct timeval *tv); void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred, const struct timeval *tv);
void server_process_syslog_message(Server *s, const char *buf, size_t buf_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len); void server_process_syslog_message(Server *s, const char *buf, size_t buf_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len);
int server_open_syslog_socket(Server *s); int server_open_syslog_socket(Server *s, const char *syslog_socket);
void server_maybe_warn_forward_syslog_missed(Server *s); void server_maybe_warn_forward_syslog_missed(Server *s);

View File

@ -14,14 +14,17 @@
#include "sigbus.h" #include "sigbus.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
const char *namespace;
Server server; Server server;
int r; int r;
if (argc > 1) { if (argc > 2) {
log_error("This program does not take arguments."); log_error("This program takes one or no arguments.");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
namespace = argc > 1 ? empty_to_null(argv[1]) : NULL;
log_set_prohibit_ipc(true); log_set_prohibit_ipc(true);
log_set_target(LOG_TARGET_AUTO); log_set_target(LOG_TARGET_AUTO);
log_set_facility(LOG_SYSLOG); log_set_facility(LOG_SYSLOG);
@ -32,7 +35,7 @@ int main(int argc, char *argv[]) {
sigbus_install(); sigbus_install();
r = server_init(&server); r = server_init(&server, namespace);
if (r < 0) if (r < 0)
goto finish; goto finish;
@ -40,7 +43,11 @@ int main(int argc, char *argv[]) {
server_flush_to_var(&server, true); server_flush_to_var(&server, true);
server_flush_dev_kmsg(&server); server_flush_dev_kmsg(&server);
log_debug("systemd-journald running as pid "PID_FMT, getpid_cached()); if (server.namespace)
log_debug("systemd-journald running as PID "PID_FMT" for namespace '%s'.", getpid_cached(), server.namespace ?: "<system>");
else
log_debug("systemd-journald running as PID "PID_FMT" for the system.", getpid_cached());
server_driver_message(&server, 0, server_driver_message(&server, 0,
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_START_STR, "MESSAGE_ID=" SD_MESSAGE_JOURNAL_START_STR,
LOG_MESSAGE("Journal started"), LOG_MESSAGE("Journal started"),
@ -55,8 +62,10 @@ int main(int argc, char *argv[]) {
usec_t t = USEC_INFINITY, n; usec_t t = USEC_INFINITY, n;
r = sd_event_get_state(server.event); r = sd_event_get_state(server.event);
if (r < 0) if (r < 0) {
log_error_errno(r, "Failed to get event loop state: %m");
goto finish; goto finish;
}
if (r == SD_EVENT_FINISHED) if (r == SD_EVENT_FINISHED)
break; break;
@ -99,7 +108,11 @@ int main(int argc, char *argv[]) {
server_maybe_warn_forward_syslog_missed(&server); server_maybe_warn_forward_syslog_missed(&server);
} }
log_debug("systemd-journald stopped as pid "PID_FMT, getpid_cached()); if (server.namespace)
log_debug("systemd-journald stopped as PID "PID_FMT" for namespace '%s'.", getpid_cached(), server.namespace ?: "<system>");
else
log_debug("systemd-journald stopped as PID "PID_FMT" for the system.", getpid_cached());
server_driver_message(&server, 0, server_driver_message(&server, 0,
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_STOP_STR, "MESSAGE_ID=" SD_MESSAGE_JOURNAL_STOP_STR,
LOG_MESSAGE("Journal stopped"), LOG_MESSAGE("Journal stopped"),

View File

@ -39,6 +39,7 @@
#include "stdio-util.h" #include "stdio-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "syslog-util.h"
#define JOURNAL_FILES_MAX 7168 #define JOURNAL_FILES_MAX 7168
@ -204,16 +205,17 @@ static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
static Match *match_new(Match *p, MatchType t) { static Match *match_new(Match *p, MatchType t) {
Match *m; Match *m;
m = new0(Match, 1); m = new(Match, 1);
if (!m) if (!m)
return NULL; return NULL;
m->type = t; *m = (Match) {
.type = t,
.parent = p,
};
if (p) { if (p)
m->parent = p;
LIST_PREPEND(matches, p->matches, m); LIST_PREPEND(matches, p->matches, m);
}
return m; return m;
} }
@ -1434,12 +1436,26 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
static int dirname_is_machine_id(const char *fn) { static int dirname_is_machine_id(const char *fn) {
sd_id128_t id, machine; sd_id128_t id, machine;
const char *e;
int r; int r;
/* Returns true if the specified directory name matches the local machine ID */
r = sd_id128_get_machine(&machine); r = sd_id128_get_machine(&machine);
if (r < 0) if (r < 0)
return r; return r;
e = strchr(fn, '.');
if (e) {
const char *k;
/* Looks like it has a namespace suffix. Verify that. */
if (!log_namespace_name_valid(e + 1))
return false;
k = strndupa(fn, e - fn);
r = sd_id128_from_string(k, &id);
} else
r = sd_id128_from_string(fn, &id); r = sd_id128_from_string(fn, &id);
if (r < 0) if (r < 0)
return r; return r;
@ -1447,9 +1463,36 @@ static int dirname_is_machine_id(const char *fn) {
return sd_id128_equal(id, machine); return sd_id128_equal(id, machine);
} }
static int dirname_has_namespace(const char *fn, const char *namespace) {
const char *e;
/* Returns true if the specified directory name matches the specified namespace */
e = strchr(fn, '.');
if (e) {
const char *k;
if (!namespace)
return false;
if (!streq(e + 1, namespace))
return false;
k = strndupa(fn, e - fn);
return id128_is_valid(k);
}
if (namespace)
return false;
return id128_is_valid(fn);
}
static bool dirent_is_journal_file(const struct dirent *de) { static bool dirent_is_journal_file(const struct dirent *de) {
assert(de); assert(de);
/* Returns true if the specified directory entry looks like a journal file we might be interested in */
if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN)) if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN))
return false; return false;
@ -1457,13 +1500,26 @@ static bool dirent_is_journal_file(const struct dirent *de) {
endswith(de->d_name, ".journal~"); endswith(de->d_name, ".journal~");
} }
static bool dirent_is_id128_subdir(const struct dirent *de) { static bool dirent_is_journal_subdir(const struct dirent *de) {
const char *e, *n;
assert(de); assert(de);
/* returns true if the specified directory entry looks like a directory that might contain journal
* files we might be interested in, i.e. is either a 128bit ID or a 128bit ID suffixed by a
* namespace. */
if (!IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN)) if (!IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN))
return false; return false;
return id128_is_valid(de->d_name); e = strchr(de->d_name, '.');
if (!e)
return id128_is_valid(de->d_name); /* No namespace */
n = strndupa(de->d_name, e - de->d_name);
if (!id128_is_valid(n))
return false;
return log_namespace_name_valid(e + 1);
} }
static int directory_open(sd_journal *j, const char *path, DIR **ret) { static int directory_open(sd_journal *j, const char *path, DIR **ret) {
@ -1500,7 +1556,7 @@ static void directory_enumerate(sd_journal *j, Directory *m, DIR *d) {
if (dirent_is_journal_file(de)) if (dirent_is_journal_file(de))
(void) add_file_by_name(j, m->path, de->d_name); (void) add_file_by_name(j, m->path, de->d_name);
if (m->is_root && dirent_is_id128_subdir(de)) if (m->is_root && dirent_is_journal_subdir(de))
(void) add_directory(j, m->path, de->d_name); (void) add_directory(j, m->path, de->d_name);
} }
@ -1540,7 +1596,11 @@ static void directory_watch(sd_journal *j, Directory *m, int fd, uint32_t mask)
} }
} }
static int add_directory(sd_journal *j, const char *prefix, const char *dirname) { static int add_directory(
sd_journal *j,
const char *prefix,
const char *dirname) {
_cleanup_free_ char *path = NULL; _cleanup_free_ char *path = NULL;
_cleanup_closedir_ DIR *d = NULL; _cleanup_closedir_ DIR *d = NULL;
Directory *m; Directory *m;
@ -1565,6 +1625,11 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
!((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run"))) !((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run")))
return 0; return 0;
if (!(FLAGS_SET(j->flags, SD_JOURNAL_ALL_NAMESPACES) ||
dirname_has_namespace(dirname, j->namespace) > 0 ||
(FLAGS_SET(j->flags, SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE) && dirname_has_namespace(dirname, NULL) > 0)))
return 0;
r = directory_open(j, path, &d); r = directory_open(j, path, &d);
if (r < 0) { if (r < 0) {
log_debug_errno(r, "Failed to open directory '%s': %m", path); log_debug_errno(r, "Failed to open directory '%s': %m", path);
@ -1573,14 +1638,16 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
m = hashmap_get(j->directories_by_path, path); m = hashmap_get(j->directories_by_path, path);
if (!m) { if (!m) {
m = new0(Directory, 1); m = new(Directory, 1);
if (!m) { if (!m) {
r = -ENOMEM; r = -ENOMEM;
goto fail; goto fail;
} }
m->is_root = false; *m = (Directory) {
m->path = path; .is_root = false,
.path = path,
};
if (hashmap_put(j->directories_by_path, m->path, m) < 0) { if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
free(m); free(m);
@ -1803,7 +1870,7 @@ static int allocate_inotify(sd_journal *j) {
return hashmap_ensure_allocated(&j->directories_by_wd, NULL); return hashmap_ensure_allocated(&j->directories_by_wd, NULL);
} }
static sd_journal *journal_new(int flags, const char *path) { static sd_journal *journal_new(int flags, const char *path, const char *namespace) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL; _cleanup_(sd_journal_closep) sd_journal *j = NULL;
j = new0(sd_journal, 1); j = new0(sd_journal, 1);
@ -1829,6 +1896,12 @@ static sd_journal *journal_new(int flags, const char *path) {
j->path = t; j->path = t;
} }
if (namespace) {
j->namespace = strdup(namespace);
if (!j->namespace)
return NULL;
}
j->files = ordered_hashmap_new(&path_hash_ops); j->files = ordered_hashmap_new(&path_hash_ops);
if (!j->files) if (!j->files)
return NULL; return NULL;
@ -1845,16 +1918,19 @@ static sd_journal *journal_new(int flags, const char *path) {
#define OPEN_ALLOWED_FLAGS \ #define OPEN_ALLOWED_FLAGS \
(SD_JOURNAL_LOCAL_ONLY | \ (SD_JOURNAL_LOCAL_ONLY | \
SD_JOURNAL_RUNTIME_ONLY | \ SD_JOURNAL_RUNTIME_ONLY | \
SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER) SD_JOURNAL_SYSTEM | \
SD_JOURNAL_CURRENT_USER | \
SD_JOURNAL_ALL_NAMESPACES | \
SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE)
_public_ int sd_journal_open(sd_journal **ret, int flags) { _public_ int sd_journal_open_namespace(sd_journal **ret, const char *namespace, int flags) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL; _cleanup_(sd_journal_closep) sd_journal *j = NULL;
int r; int r;
assert_return(ret, -EINVAL); assert_return(ret, -EINVAL);
assert_return((flags & ~OPEN_ALLOWED_FLAGS) == 0, -EINVAL); assert_return((flags & ~OPEN_ALLOWED_FLAGS) == 0, -EINVAL);
j = journal_new(flags, NULL); j = journal_new(flags, NULL, namespace);
if (!j) if (!j)
return -ENOMEM; return -ENOMEM;
@ -1866,6 +1942,10 @@ _public_ int sd_journal_open(sd_journal **ret, int flags) {
return 0; return 0;
} }
_public_ int sd_journal_open(sd_journal **ret, int flags) {
return sd_journal_open_namespace(ret, NULL, flags);
}
#define OPEN_CONTAINER_ALLOWED_FLAGS \ #define OPEN_CONTAINER_ALLOWED_FLAGS \
(SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM) (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
@ -1875,7 +1955,7 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in
char *p; char *p;
int r; int r;
/* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in /* This is deprecated, people should use machined's OpenMachineRootDirectory() call instead in
* combination with sd_journal_open_directory_fd(). */ * combination with sd_journal_open_directory_fd(). */
assert_return(machine, -EINVAL); assert_return(machine, -EINVAL);
@ -1897,7 +1977,7 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in
if (!streq_ptr(class, "container")) if (!streq_ptr(class, "container"))
return -EIO; return -EIO;
j = journal_new(flags, root); j = journal_new(flags, root, NULL);
if (!j) if (!j)
return -ENOMEM; return -ENOMEM;
@ -1921,7 +2001,7 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
assert_return(path, -EINVAL); assert_return(path, -EINVAL);
assert_return((flags & ~OPEN_DIRECTORY_ALLOWED_FLAGS) == 0, -EINVAL); assert_return((flags & ~OPEN_DIRECTORY_ALLOWED_FLAGS) == 0, -EINVAL);
j = journal_new(flags, path); j = journal_new(flags, path, NULL);
if (!j) if (!j)
return -ENOMEM; return -ENOMEM;
@ -1944,7 +2024,7 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
assert_return(ret, -EINVAL); assert_return(ret, -EINVAL);
assert_return(flags == 0, -EINVAL); assert_return(flags == 0, -EINVAL);
j = journal_new(flags, NULL); j = journal_new(flags, NULL, NULL);
if (!j) if (!j)
return -ENOMEM; return -ENOMEM;
@ -1979,7 +2059,7 @@ _public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
if (!S_ISDIR(st.st_mode)) if (!S_ISDIR(st.st_mode))
return -EBADFD; return -EBADFD;
j = journal_new(flags, NULL); j = journal_new(flags, NULL, NULL);
if (!j) if (!j)
return -ENOMEM; return -ENOMEM;
@ -2007,7 +2087,7 @@ _public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fd
assert_return(n_fds > 0, -EBADF); assert_return(n_fds > 0, -EBADF);
assert_return(flags == 0, -EINVAL); assert_return(flags == 0, -EINVAL);
j = journal_new(flags, NULL); j = journal_new(flags, NULL, NULL);
if (!j) if (!j)
return -ENOMEM; return -ENOMEM;
@ -2079,6 +2159,7 @@ _public_ void sd_journal_close(sd_journal *j) {
free(j->path); free(j->path);
free(j->prefix); free(j->prefix);
free(j->namespace);
free(j->unique_field); free(j->unique_field);
free(j->fields_buffer); free(j->fields_buffer);
free(j); free(j);
@ -2480,7 +2561,7 @@ static void process_q_overflow(sd_journal *j) {
log_debug("Reiteration complete."); log_debug("Reiteration complete.");
} }
static void process_inotify_event(sd_journal *j, struct inotify_event *e) { static void process_inotify_event(sd_journal *j, const struct inotify_event *e) {
Directory *d; Directory *d;
assert(j); assert(j);

View File

@ -693,4 +693,5 @@ global:
sd_event_source_get_child_process_own; sd_event_source_get_child_process_own;
sd_event_source_set_child_process_own; sd_event_source_set_child_process_own;
sd_event_source_send_child_signal; sd_event_source_send_child_signal;
sd_journal_open_namespace;
} LIBSYSTEMD_243; } LIBSYSTEMD_243;

View File

@ -576,6 +576,7 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
show_journal_by_unit( show_journal_by_unit(
stdout, stdout,
i.scope, i.scope,
NULL,
arg_output, arg_output,
0, 0,
i.timestamp.monotonic, i.timestamp.monotonic,
@ -660,6 +661,7 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
show_journal_by_unit( show_journal_by_unit(
stdout, stdout,
i.slice, i.slice,
NULL,
arg_output, arg_output,
0, 0,
i.timestamp.monotonic, i.timestamp.monotonic,

View File

@ -626,6 +626,7 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
show_journal_by_unit( show_journal_by_unit(
stdout, stdout,
i->unit, i->unit,
NULL,
arg_output, arg_output,
0, 0,
i->timestamp.monotonic, i->timestamp.monotonic,

View File

@ -833,7 +833,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"RuntimeDirectoryPreserve", "RuntimeDirectoryPreserve",
"Personality", "Personality",
"KeyringMode", "KeyringMode",
"NetworkNamespacePath")) "NetworkNamespacePath",
"LogNamespace"))
return bus_append_string(m, field, eq); return bus_append_string(m, field, eq);
if (STR_IN_SET(field, "IgnoreSIGPIPE", if (STR_IN_SET(field, "IgnoreSIGPIPE",

View File

@ -1453,6 +1453,7 @@ int add_match_this_boot(sd_journal *j, const char *machine) {
int show_journal_by_unit( int show_journal_by_unit(
FILE *f, FILE *f,
const char *unit, const char *unit,
const char *log_namespace,
OutputMode mode, OutputMode mode,
unsigned n_columns, unsigned n_columns,
usec_t not_before, usec_t not_before,
@ -1473,7 +1474,7 @@ int show_journal_by_unit(
if (how_many <= 0) if (how_many <= 0)
return 0; return 0;
r = sd_journal_open(&j, journal_open_flags); r = sd_journal_open_namespace(&j, log_namespace, journal_open_flags | SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to open journal: %m"); return log_error_errno(r, "Failed to open journal: %m");

View File

@ -46,6 +46,7 @@ int add_matches_for_user_unit(
int show_journal_by_unit( int show_journal_by_unit(
FILE *f, FILE *f,
const char *unit, const char *unit,
const char *namespace,
OutputMode mode, OutputMode mode,
unsigned n_columns, unsigned n_columns,
usec_t not_before, usec_t not_before,

View File

@ -168,6 +168,7 @@ struct VarlinkServer {
Hashmap *methods; Hashmap *methods;
VarlinkConnect connect_callback; VarlinkConnect connect_callback;
VarlinkDisconnect disconnect_callback;
sd_event *event; sd_event *event;
int64_t event_priority; int64_t event_priority;
@ -1146,6 +1147,7 @@ int varlink_flush(Varlink *v) {
} }
static void varlink_detach_server(Varlink *v) { static void varlink_detach_server(Varlink *v) {
VarlinkServer *saved_server;
assert(v); assert(v);
if (!v->server) if (!v->server)
@ -1169,8 +1171,15 @@ static void varlink_detach_server(Varlink *v) {
v->server->n_connections--; v->server->n_connections--;
/* If this is a connection associated to a server, then let's disconnect the server and the /* If this is a connection associated to a server, then let's disconnect the server and the
* connection from each other. This drops the dangling reference that connect_callback() set up. */ * connection from each other. This drops the dangling reference that connect_callback() set up. But
v->server = varlink_server_unref(v->server); * before we release the references, let's call the disconnection callback if it is defined. */
saved_server = TAKE_PTR(v->server);
if (saved_server->disconnect_callback)
saved_server->disconnect_callback(saved_server, v, saved_server->userdata);
varlink_server_unref(saved_server);
varlink_unref(v); varlink_unref(v);
} }
@ -2413,6 +2422,16 @@ int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect callback) {
return 0; return 0;
} }
int varlink_server_bind_disconnect(VarlinkServer *s, VarlinkDisconnect callback) {
assert_return(s, -EINVAL);
if (callback && s->disconnect_callback && callback != s->disconnect_callback)
return -EBUSY;
s->disconnect_callback = callback;
return 0;
}
unsigned varlink_server_connections_max(VarlinkServer *s) { unsigned varlink_server_connections_max(VarlinkServer *s) {
int dts; int dts;
@ -2460,6 +2479,12 @@ int varlink_server_set_connections_max(VarlinkServer *s, unsigned m) {
return 0; return 0;
} }
unsigned varlink_server_current_connections(VarlinkServer *s) {
assert_return(s, UINT_MAX);
return s->n_connections;
}
int varlink_server_set_description(VarlinkServer *s, const char *description) { int varlink_server_set_description(VarlinkServer *s, const char *description) {
assert_return(s, -EINVAL); assert_return(s, -EINVAL);

View File

@ -51,6 +51,7 @@ typedef enum VarlinkServerFlags {
typedef int (*VarlinkMethod)(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata); typedef int (*VarlinkMethod)(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata);
typedef int (*VarlinkReply)(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata); typedef int (*VarlinkReply)(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata);
typedef int (*VarlinkConnect)(VarlinkServer *server, Varlink *link, void *userdata); typedef int (*VarlinkConnect)(VarlinkServer *server, Varlink *link, void *userdata);
typedef void (*VarlinkDisconnect)(VarlinkServer *server, Varlink *link, void *userdata);
int varlink_connect_address(Varlink **ret, const char *address); int varlink_connect_address(Varlink **ret, const char *address);
int varlink_connect_fd(Varlink **ret, int fd); int varlink_connect_fd(Varlink **ret, int fd);
@ -134,6 +135,7 @@ int varlink_server_bind_method(VarlinkServer *s, const char *method, VarlinkMeth
int varlink_server_bind_method_many_internal(VarlinkServer *s, ...); int varlink_server_bind_method_many_internal(VarlinkServer *s, ...);
#define varlink_server_bind_method_many(s, ...) varlink_server_bind_method_many_internal(s, __VA_ARGS__, NULL) #define varlink_server_bind_method_many(s, ...) varlink_server_bind_method_many_internal(s, __VA_ARGS__, NULL)
int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect connect); int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect connect);
int varlink_server_bind_disconnect(VarlinkServer *s, VarlinkDisconnect disconnect);
void* varlink_server_set_userdata(VarlinkServer *s, void *userdata); void* varlink_server_set_userdata(VarlinkServer *s, void *userdata);
void* varlink_server_get_userdata(VarlinkServer *s); void* varlink_server_get_userdata(VarlinkServer *s);
@ -150,6 +152,8 @@ unsigned varlink_server_connections_per_uid_max(VarlinkServer *s);
int varlink_server_set_connections_per_uid_max(VarlinkServer *s, unsigned m); int varlink_server_set_connections_per_uid_max(VarlinkServer *s, unsigned m);
int varlink_server_set_connections_max(VarlinkServer *s, unsigned m); int varlink_server_set_connections_max(VarlinkServer *s, unsigned m);
unsigned varlink_server_current_connections(VarlinkServer *s);
int varlink_server_set_description(VarlinkServer *s, const char *description); int varlink_server_set_description(VarlinkServer *s, const char *description);
DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink *, varlink_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink *, varlink_unref);

View File

@ -4007,6 +4007,8 @@ typedef struct UnitStatusInfo {
int exit_code, exit_status; int exit_code, exit_status;
const char *log_namespace;
usec_t condition_timestamp; usec_t condition_timestamp;
bool condition_result; bool condition_result;
LIST_HEAD(UnitCondition, conditions); LIST_HEAD(UnitCondition, conditions);
@ -4545,6 +4547,7 @@ static void print_status_info(
show_journal_by_unit( show_journal_by_unit(
stdout, stdout,
i->id, i->id,
i->log_namespace,
arg_output, arg_output,
0, 0,
i->inactive_exit_timestamp_monotonic, i->inactive_exit_timestamp_monotonic,
@ -5491,6 +5494,7 @@ static int show_one(
{ "ExecMainExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, exit_timestamp) }, { "ExecMainExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, exit_timestamp) },
{ "ExecMainCode", "i", NULL, offsetof(UnitStatusInfo, exit_code) }, { "ExecMainCode", "i", NULL, offsetof(UnitStatusInfo, exit_code) },
{ "ExecMainStatus", "i", NULL, offsetof(UnitStatusInfo, exit_status) }, { "ExecMainStatus", "i", NULL, offsetof(UnitStatusInfo, exit_status) },
{ "LogNamespace", "s", NULL, offsetof(UnitStatusInfo, log_namespace) },
{ "ConditionTimestamp", "t", NULL, offsetof(UnitStatusInfo, condition_timestamp) }, { "ConditionTimestamp", "t", NULL, offsetof(UnitStatusInfo, condition_timestamp) },
{ "ConditionResult", "b", NULL, offsetof(UnitStatusInfo, condition_result) }, { "ConditionResult", "b", NULL, offsetof(UnitStatusInfo, condition_result) },
{ "Conditions", "a(sbbsi)", map_conditions, 0 }, { "Conditions", "a(sbbsi)", map_conditions, 0 },

View File

@ -45,6 +45,18 @@ typedef void (*_sd_destroy_t)(void *userdata);
# define _sd_pure_ __attribute__((__pure__)) # define _sd_pure_ __attribute__((__pure__))
#endif #endif
/* Note that strictly speaking __deprecated__ has been available before GCC 6. However, starting with GCC 6
* it also works on enum values, which we are interested in. Since this is a developer-facing feature anyway
* (as opposed to build engineer-facing), let's hence conditionalize this to gcc 6, given that the developers
* are probably going to use something newer anyway. */
#ifndef _sd_deprecated_
# if __GNUC__ >= 6
# define _sd_deprecated_ __attribute__((__deprecated__))
# else
# define _sd_deprecated_
# endif
#endif
#ifndef _SD_STRINGIFY #ifndef _SD_STRINGIFY
# define _SD_XSTRINGIFY(x) #x # define _SD_XSTRINGIFY(x) #x
# define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x) # define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x)

View File

@ -69,8 +69,10 @@ enum {
SD_JOURNAL_SYSTEM = 1 << 2, SD_JOURNAL_SYSTEM = 1 << 2,
SD_JOURNAL_CURRENT_USER = 1 << 3, SD_JOURNAL_CURRENT_USER = 1 << 3,
SD_JOURNAL_OS_ROOT = 1 << 4, SD_JOURNAL_OS_ROOT = 1 << 4,
SD_JOURNAL_ALL_NAMESPACES = 1 << 5, /* Show all namespaces, not just the default or specified one */
SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE = 1 << 6, /* Show default namespace in addition to specified one */
SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM /* deprecated name */ SD_JOURNAL_SYSTEM_ONLY _sd_deprecated_ = SD_JOURNAL_SYSTEM /* deprecated name */
}; };
/* Wakeup event types */ /* Wakeup event types */
@ -81,11 +83,12 @@ enum {
}; };
int sd_journal_open(sd_journal **ret, int flags); int sd_journal_open(sd_journal **ret, int flags);
int sd_journal_open_namespace(sd_journal **ret, const char *name_space, int flags);
int sd_journal_open_directory(sd_journal **ret, const char *path, int flags); int sd_journal_open_directory(sd_journal **ret, const char *path, int flags);
int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags); int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags);
int sd_journal_open_files(sd_journal **ret, const char **paths, int flags); int sd_journal_open_files(sd_journal **ret, const char **paths, int flags);
int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags); int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags);
int sd_journal_open_container(sd_journal **ret, const char *machine, int flags); /* deprecated */ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) _sd_deprecated_; /* deprecated */
void sd_journal_close(sd_journal *j); void sd_journal_close(sd_journal *j);
int sd_journal_previous(sd_journal *j); int sd_journal_previous(sd_journal *j);

View File

@ -6,6 +6,9 @@ for header in sys.argv[2:]:
print('#include "{}"'.format(header.split('/')[-1])) print('#include "{}"'.format(header.split('/')[-1]))
print(''' print('''
/* We want to check deprecated symbols too, without complaining */
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
const void* symbols[] = {''') const void* symbols[] = {''')
for line in open(sys.argv[1]): for line in open(sys.argv[1]):

View File

@ -148,6 +148,7 @@ static void test_protect_kernel_logs(void) {
NULL, 0, NULL, 0,
NULL, NULL,
NULL, NULL,
NULL,
PROTECT_HOME_NO, PROTECT_HOME_NO,
PROTECT_SYSTEM_NO, PROTECT_SYSTEM_NO,
0, 0,

View File

@ -72,6 +72,7 @@ int main(int argc, char *argv[]) {
&(TemporaryFileSystem) { .path = (char*) "/var", .options = (char*) "ro" }, 1, &(TemporaryFileSystem) { .path = (char*) "/var", .options = (char*) "ro" }, 1,
tmp_dir, tmp_dir,
var_tmp_dir, var_tmp_dir,
NULL,
PROTECT_HOME_NO, PROTECT_HOME_NO,
PROTECT_SYSTEM_NO, PROTECT_SYSTEM_NO,
0, 0,

View File

@ -0,0 +1 @@
../TEST-01-BASIC/Makefile

View File

@ -0,0 +1,39 @@
#!/bin/bash
set -e
TEST_DESCRIPTION="test log namespaces"
. $TEST_BASE_DIR/test-functions
test_setup() {
create_empty_image_rootdir
(
LOG_LEVEL=5
eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
setup_basic_environment
mask_supporting_services
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
Description=Testsuite service
Before=getty-pre.target
Wants=getty-pre.target
Wants=systemd-journald@foobar.socket systemd-journald-varlink@foobar.socket
After=systemd-journald@foobar.socket systemd-journald-varlink@foobar.socket
[Service]
ExecStart=/testsuite.sh
Type=oneshot
LogTarget=foobar
EOF
cp testsuite.sh $initdir/
setup_testsuite
)
setup_nspawn_root
}
do_test "$@"

View File

@ -0,0 +1,19 @@
#!/bin/bash
set -ex
systemd-analyze log-level debug
systemd-run -p LogNamespace=foobar echo "hello world"
journalctl --namespace=foobar --sync
journalctl --namespace=foobar > /tmp/hello-world
journalctl > /tmp/no-hello-world
grep "hello world" /tmp/hello-world
! grep "hello world" /tmp/no-hello-world
systemd-analyze log-level info
echo OK > /testok
exit 0

View File

@ -737,7 +737,6 @@ install_config_files() {
inst /etc/shells inst /etc/shells
inst /etc/nsswitch.conf inst /etc/nsswitch.conf
inst /etc/pam.conf || : inst /etc/pam.conf || :
inst /etc/securetty || :
inst /etc/os-release inst /etc/os-release
inst /etc/localtime inst /etc/localtime
# we want an empty environment # we want an empty environment

View File

@ -32,17 +32,17 @@ Z /run/log/journal/%m ~2750 root systemd-journal - -
m4_ifdef(`HAVE_ACL',`m4_dnl m4_ifdef(`HAVE_ACL',`m4_dnl
m4_ifdef(`ENABLE_ADM_GROUP',`m4_dnl m4_ifdef(`ENABLE_ADM_GROUP',`m4_dnl
m4_ifdef(`ENABLE_WHEEL_GROUP',`` m4_ifdef(`ENABLE_WHEEL_GROUP',``
a+ /run/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x a+ /run/log/journal - - - - d:group::r-x,d:group:adm:r-x,d:group:wheel:r-x,group::r-x,group:adm:r-x,group:wheel:r-x
a+ /run/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x a+ /run/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x,group:adm:r-x,group:wheel:r-x
a+ /run/log/journal/%m/*.journal* - - - - group:adm:r--,group:wheel:r-- a+ /run/log/journal/%m/*.journal* - - - - group:adm:r--,group:wheel:r--
'',`` '',``
a+ /run/log/journal/%m - - - - d:group:adm:r-x a+ /run/log/journal - - - - d:group::r-x,d:group:adm:r-x,group::r-x,group:adm:r-x
a+ /run/log/journal/%m - - - - group:adm:r-x a+ /run/log/journal/%m - - - - d:group:adm:r-x,group:adm:r-x
a+ /run/log/journal/%m/*.journal* - - - - group:adm:r-- a+ /run/log/journal/%m/*.journal* - - - - group:adm:r--
'')',`m4_dnl '')',`m4_dnl
m4_ifdef(`ENABLE_WHEEL_GROUP',`` m4_ifdef(`ENABLE_WHEEL_GROUP',``
a+ /run/log/journal/%m - - - - d:group:wheel:r-x a+ /run/log/journal - - - - d:group::r-x,d:group:wheel:r-x,group::r-x,group:wheel:r-x
a+ /run/log/journal/%m - - - - group:wheel:r-x a+ /run/log/journal/%m - - - - d:group:wheel:r-x,group:wheel:r-x
a+ /run/log/journal/%m/*.journal* - - - - group:wheel:r-- a+ /run/log/journal/%m/*.journal* - - - - group:wheel:r--
'')')')m4_dnl '')')')m4_dnl
@ -52,23 +52,17 @@ z /var/log/journal/%m/system.journal 0640 root systemd-journal - -
m4_ifdef(`HAVE_ACL',`m4_dnl m4_ifdef(`HAVE_ACL',`m4_dnl
m4_ifdef(`ENABLE_ADM_GROUP',`m4_dnl m4_ifdef(`ENABLE_ADM_GROUP',`m4_dnl
m4_ifdef(`ENABLE_WHEEL_GROUP',`` m4_ifdef(`ENABLE_WHEEL_GROUP',``
a+ /var/log/journal - - - - d:group::r-x,d:group:adm:r-x,d:group:wheel:r-x a+ /var/log/journal - - - - d:group::r-x,d:group:adm:r-x,d:group:wheel:r-x,group::r-x,group:adm:r-x,group:wheel:r-x
a+ /var/log/journal - - - - group::r-x,group:adm:r-x,group:wheel:r-x a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x,group:adm:r-x,group:wheel:r-x
a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
a+ /var/log/journal/%m/system.journal - - - - group:adm:r--,group:wheel:r-- a+ /var/log/journal/%m/system.journal - - - - group:adm:r--,group:wheel:r--
'', `` '', ``
a+ /var/log/journal - - - - d:group::r-x,d:group:adm:r-x a+ /var/log/journal - - - - d:group::r-x,d:group:adm:r-x,group::r-x,group:adm:r-x
a+ /var/log/journal - - - - group::r-x,group:adm:r-x a+ /var/log/journal/%m - - - - d:group:adm:r-x,group:adm:r-x
a+ /var/log/journal/%m - - - - d:group:adm:r-x
a+ /var/log/journal/%m - - - - group:adm:r-x
a+ /var/log/journal/%m/system.journal - - - - group:adm:r-- a+ /var/log/journal/%m/system.journal - - - - group:adm:r--
'')',`m4_dnl '')',`m4_dnl
m4_ifdef(`ENABLE_WHEEL_GROUP',`` m4_ifdef(`ENABLE_WHEEL_GROUP',``
a+ /var/log/journal - - - - d:group::r-x,d:group:wheel:r-x a+ /var/log/journal - - - - d:group::r-x,d:group:wheel:r-x,group::r-x,group:wheel:r-x
a+ /var/log/journal - - - - group::r-x,group:wheel:r-x a+ /var/log/journal/%m - - - - d:group:wheel:r-x,group:wheel:r-x
a+ /var/log/journal/%m - - - - d:group:wheel:r-x
a+ /var/log/journal/%m - - - - group:wheel:r-x
a+ /var/log/journal/%m/system.journal - - - - group:wheel:r-- a+ /var/log/journal/%m/system.journal - - - - group:wheel:r--
'')')')m4_dnl '')')')m4_dnl

View File

@ -114,6 +114,8 @@ units = [
['systemd-kexec.service', ''], ['systemd-kexec.service', ''],
['systemd-machine-id-commit.service', '', ['systemd-machine-id-commit.service', '',
'sysinit.target.wants/'], 'sysinit.target.wants/'],
['systemd-journald@.socket', ''],
['systemd-journald-varlink@.socket', ''],
['systemd-networkd.socket', 'ENABLE_NETWORKD'], ['systemd-networkd.socket', 'ENABLE_NETWORKD'],
['systemd-poweroff.service', ''], ['systemd-poweroff.service', ''],
['systemd-reboot.service', ''], ['systemd-reboot.service', ''],
@ -180,6 +182,7 @@ in_units = [
['systemd-journal-upload.service', 'ENABLE_REMOTE HAVE_LIBCURL'], ['systemd-journal-upload.service', 'ENABLE_REMOTE HAVE_LIBCURL'],
['systemd-journald.service', '', ['systemd-journald.service', '',
'sysinit.target.wants/'], 'sysinit.target.wants/'],
['systemd-journald@.service', ''],
['systemd-localed.service', 'ENABLE_LOCALED', ['systemd-localed.service', 'ENABLE_LOCALED',
'dbus-org.freedesktop.locale1.service'], 'dbus-org.freedesktop.locale1.service'],
['systemd-logind.service', 'ENABLE_LOGIND', ['systemd-logind.service', 'ENABLE_LOGIND',

View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Journal Varlink Socket for Namespace %i
Documentation=man:systemd-journald.service(8) man:journald.conf(5)
StopWhenUnneeded=yes
[Socket]
Service=systemd-journald@%i.service
ListenStream=/run/systemd/journal.%i/io.systemd.journal
SocketMode=0600

View File

@ -16,7 +16,6 @@ After=systemd-journald.socket systemd-journald-dev-log.socket systemd-journald-a
Before=sysinit.target Before=sysinit.target
[Service] [Service]
OOMScoreAdjust=-250
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE
DeviceAllow=char-* rw DeviceAllow=char-* rw
ExecStart=@rootlibexecdir@/systemd-journald ExecStart=@rootlibexecdir@/systemd-journald
@ -25,12 +24,15 @@ IPAddressDeny=any
LockPersonality=yes LockPersonality=yes
MemoryDenyWriteExecute=yes MemoryDenyWriteExecute=yes
NoNewPrivileges=yes NoNewPrivileges=yes
OOMScoreAdjust=-250
Restart=always Restart=always
RestartSec=0 RestartSec=0
RestrictAddressFamilies=AF_UNIX AF_NETLINK RestrictAddressFamilies=AF_UNIX AF_NETLINK
RestrictNamespaces=yes RestrictNamespaces=yes
RestrictRealtime=yes RestrictRealtime=yes
RestrictSUIDSGID=yes RestrictSUIDSGID=yes
RuntimeDirectory=systemd/journal
RuntimeDirectoryPreserve=yes
Sockets=systemd-journald.socket systemd-journald-dev-log.socket systemd-journald-audit.socket Sockets=systemd-journald.socket systemd-journald-dev-log.socket systemd-journald-audit.socket
StandardOutput=null StandardOutput=null
SystemCallArchitectures=native SystemCallArchitectures=native

View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Journal Service for Namespace %i
Documentation=man:systemd-journald.service(8) man:journald.conf(5)
Requires=systemd-journald@%i.socket systemd-journald-varlink@%i.socket
After=systemd-journald@%i.socket systemd-journald-varlink@%i.socket
[Service]
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE
DevicePolicy=closed
ExecStart=@rootlibexecdir@/systemd-journald %i
FileDescriptorStoreMax=4224
Group=systemd-journal
IPAddressDeny=any
LockPersonality=yes
LogsDirectory=journal/%m.%i
LogsDirectoryMode=02755
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
RestrictAddressFamilies=AF_UNIX AF_NETLINK
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
RuntimeDirectory=systemd/journal.%i
RuntimeDirectoryPreserve=yes
Sockets=systemd-journald@%i.socket
StandardOutput=null
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
Type=notify
@SERVICE_WATCHDOG@
# If there are many split up journal files we need a lot of fds to access them
# all in parallel.
LimitNOFILE=@HIGH_RLIMIT_NOFILE@

View File

@ -0,0 +1,24 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Journal Socket for Namespace %i
Documentation=man:systemd-journald.service(8) man:journald.conf(5)
StopWhenUnneeded=yes
[Socket]
Service=systemd-journald@%i.service
ListenStream=/run/systemd/journal.%i/stdout
ListenDatagram=/run/systemd/journal.%i/socket
ListenDatagram=/run/systemd/journal.%i/dev-log
SocketMode=0666
PassCredentials=yes
PassSecurity=yes
ReceiveBuffer=8M
SendBuffer=8M