Compare commits
52 Commits
279be556f8
...
af06ddf51a
Author | SHA1 | Date |
---|---|---|
Yu Watanabe | af06ddf51a | |
Frantisek Sumsal | 2273ecfeda | |
Lennart Poettering | 5ee69e144e | |
Lennart Poettering | ad23785246 | |
Lennart Poettering | 2b6b8bd3f7 | |
Lennart Poettering | 241c8f67f6 | |
Lennart Poettering | 5b0a76d107 | |
Lennart Poettering | 7d8155b3df | |
Lennart Poettering | 6bc4361997 | |
Lennart Poettering | efcbcd0d04 | |
Lennart Poettering | 23d8c56046 | |
Lennart Poettering | 340cb115b3 | |
Lennart Poettering | 5591cd4e20 | |
Lennart Poettering | fb38a7beb8 | |
Lennart Poettering | 0f5a4f9cd9 | |
Lennart Poettering | db23d83bd4 | |
Lennart Poettering | dc5437c78b | |
Lennart Poettering | 65c398c031 | |
Lennart Poettering | 6d4d600260 | |
Lennart Poettering | c4f601f205 | |
Lennart Poettering | d98580e438 | |
Lennart Poettering | 2435269171 | |
Lennart Poettering | d93dda3afe | |
Lennart Poettering | 21fa231ece | |
Lennart Poettering | 6b25db87a1 | |
Lennart Poettering | 31e99dd2cc | |
Lennart Poettering | 456aa87906 | |
Lennart Poettering | 2f5435a147 | |
Lennart Poettering | 33ff74643e | |
Lennart Poettering | 68312977db | |
Lennart Poettering | e7238caf0c | |
Lennart Poettering | 0491150b5c | |
Lennart Poettering | a6214d9643 | |
Lennart Poettering | 91dd5f7cbe | |
Lennart Poettering | 839d1b2014 | |
Lennart Poettering | 1ee51fbd70 | |
Lennart Poettering | b1852c48c1 | |
Lennart Poettering | d6f46470f5 | |
Lennart Poettering | 4f60310373 | |
Lennart Poettering | 4e00337b16 | |
Lennart Poettering | 46e2348a58 | |
Lennart Poettering | b42b9479a8 | |
Lennart Poettering | 74dd8f5759 | |
Lennart Poettering | 8548f4f09b | |
Lennart Poettering | 7e7ef3bfb2 | |
Lennart Poettering | a30e35f85a | |
Lennart Poettering | 2066f4fe30 | |
Lennart Poettering | a2735a4549 | |
Lennart Poettering | dbac262578 | |
Lennart Poettering | 99d0d05a10 | |
Lennart Poettering | 659a77bec6 | |
Lennart Poettering | d83f7e4c92 |
5
TODO
5
TODO
|
@ -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.
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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'],
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 },
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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]):
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
../TEST-01-BASIC/Makefile
|
|
@ -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 "$@"
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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@
|
|
@ -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
|
Loading…
Reference in New Issue