<listitem><para>If <replaceable>FILE</replaceable> exists and contains a
cursor, start showing entries <emphasis>after</emphasis> this location.
- Otherwise the show entries according the other given options. At the end,
+ Otherwise show entries according to the other given options. At the end,
write the cursor of the last entry to <replaceable>FILE</replaceable>. Use
this option to continually read the journal by sequentially calling
<command>journalctl</command>.</para></listitem>
<listitem><para>Takes a space-separated list of one or more valid prefix match strings for the
<ulink url="https://systemd.io/PORTABLE_SERVICES">Portable Services</ulink> logic. This field
serves two purposes: it is informational, identifying portable service images as such (and thus
- allowing them to be distinguished from other OS images, such as bootable system images). In is also
+ allowing them to be distinguished from other OS images, such as bootable system images). It is also
used when a portable service image is attached: the specified or implied portable service prefix is
checked against the list specified here, to enforce restrictions how images may be attached to a
system.</para></listitem>
<refnamediv>
<refname>pam_systemd_home</refname>
- <refpurpose>Automatically mount home directories managed by <filename>systemd-homed.service</filename> on
- login, and unmount them on logout</refpurpose>
+ <refpurpose>Authenticate users and mount home directories via <filename>systemd-homed.service</filename>
+ </refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><command>pam_systemd_home</command> ensures that home directories managed by
<citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
are automatically activated (mounted) on user login, and are deactivated (unmounted) when the last
- session of the user ends.</para>
+ session of the user ends. For such users, it also provides authentication (when per-user disk encryption
+ is used, the disk encryption key is derived from the authentication credential supplied at login time),
+ account management (the <ulink url="https://systemd.io/USER_RECORD/">JSON user record</ulink> embedded in
+ the home store contains account details), and implements the updating of the encryption password (which
+ is also used for user authentication).</para>
</refsect1>
<refsect1>
<refsect1>
<title>Module Types Provided</title>
- <para>The module provides all four management operations: <option>auth</option>, <option>account</option>,
- <option>session</option>, <option>password</option>.</para>
+ <para>The module implements all four PAM operations: <option>auth</option> (reason: to allow
+ authentication using the encrypted data), <option>account</option> (reason: users with
+ <filename>systemd-homed.service</filename> user accounts are described in a <ulink
+ url="https://systemd.io/USER_RECORD/">JSON user record</ulink> and may be configured in more detail than
+ in the traditional Linux user database), <option>session</option> (user sessions must be tracked in order
+ to implement automatic release when the last session of the user is gone), <option>password</option> (to
+ change the encryption password — also used for user authentication — through PAM).</para>
</refsect1>
<refsect1>
<varlistentry>
<term>BARRIER=1</term>
- <listitem><para>Tells the service manager that the client is explicitly requesting synchronization by means of
- closing the file descriptor sent with this command. The service manager guarantees that the processing of a <varname>
- BARRIER=1</varname> command will only happen after all previous notification messages sent before this command
- have been processed. Hence, this command accompanied with a single file descriptor can be used to synchronize
- against reception of all previous status messages. Note that this command cannot be mixed with other notifications,
- and has to be sent in a separate message to the service manager, otherwise all assignments will be ignored. Note that
- sending 0 or more than 1 file descriptor with this command is a violation of the protocol.</para></listitem>
+ <listitem><para>Tells the service manager that the client is explicitly requesting synchronization by
+ means of closing the file descriptor sent with this command. The service manager guarantees that the
+ processing of a <varname>BARRIER=1</varname> command will only happen after all previous notification
+ messages sent before this command have been processed. Hence, this command accompanied with a single
+ file descriptor can be used to synchronize against reception of all previous status messages. Note
+ that this command cannot be mixed with other notifications, and has to be sent in a separate message
+ to the service manager, otherwise all assignments will be ignored. Note that sending 0 or more than 1
+ file descriptor with this command is a violation of the protocol.</para></listitem>
</varlistentry>
</variablelist>
<para><function>sd_notify_barrier()</function> allows the caller to
synchronize against reception of previously sent notification messages
- and uses the <literal>BARRIER=1</literal> command. It takes a relative
+ and uses the <varname>BARRIER=1</varname> command. It takes a relative
<varname>timeout</varname> value in microseconds which is passed to
<citerefentry><refentrytitle>ppoll</refentrytitle><manvolnum>2</manvolnum>
</citerefentry>. A value of UINT64_MAX is interpreted as infinite timeout.
<refsect1>
<para id="singular">This option is only available for system services, or for services running in per-user
- instances of the service manager when unprivileged user namespaces are available.</para>
+ instances of the service manager when <varname>PrivateUsers=</varname> is enabled.</para>
<para id="plural">These options are only available for system services, or for services running in per-user
- instances of the service manager when unprivileged user namespaces are available.</para>
+ instances of the service manager when <varname>PrivateUsers=</varname> is enabled.</para>
</refsect1>
<option>-t</option>). If a PID is passed, show information
about the unit the process belongs to.</para>
- <para>This function is intended to generate human-readable
- output. If you are looking for computer-parsable output,
- use <command>show</command> instead. By default, this
- function only shows 10 lines of output and ellipsizes
- lines to fit in the terminal window. This can be changed
- with <option>--lines</option> and <option>--full</option>,
- see above. In addition, <command>journalctl
- --unit=<replaceable>NAME</replaceable></command> or
- <command>journalctl
- --user-unit=<replaceable>NAME</replaceable></command> use
- a similar filter for messages and might be more
- convenient.
- </para>
-
- <para>systemd implicitly loads units as necessary, so just running the <command>status</command> will
- attempt to load a file. The command is thus not useful for determining if something was already loaded or
- not. The units may possibly also be quickly unloaded after the operation is completed if there's no reason
- to keep it in memory thereafter.
- </para>
+ <para>This function is intended to generate human-readable output. If you are looking for
+ computer-parsable output, use <command>show</command> instead. By default, this function only
+ shows 10 lines of output and ellipsizes lines to fit in the terminal window. This can be changed
+ with <option>--lines</option> and <option>--full</option>, see above. In addition,
+ <command>journalctl --unit=<replaceable>NAME</replaceable></command> or <command>journalctl
+ --user-unit=<replaceable>NAME</replaceable></command> use a similar filter for messages and might
+ be more convenient.</para>
+
+ <para>Note that this operation only displays <emphasis>runtime</emphasis> status, i.e. information about
+ the current invocation of the unit (if it is running) or the most recent invocation (if it is not
+ running anymore, and has not been released from memory). Information about earlier invocations,
+ invocations from previous system boots, or prior invocations that have already been released from
+ memory may be retrieved via <command>journalctl --unit=</command>.</para>
+
+ <para>systemd implicitly loads units as necessary, so just running the <command>status</command>
+ will attempt to load a file. The command is thus not useful for determining if something was
+ already loaded or not. The units may possibly also be quickly unloaded after the operation is
+ completed if there's no reason to keep it in memory thereafter.</para>
<example>
<title>Example output from systemctl status </title>
<term><command>has-tpm2</command></term>
<listitem><para>Reports whether the system is equipped with a TPM2 device usable for protecting
- credentials. If the a TPM2 device has been discovered, is supported, and is being used by firmware,
+ credentials. If a TPM2 device has been discovered, is supported, and is being used by firmware,
by the OS kernel drivers and by userspace (i.e. systemd) this prints <literal>yes</literal> and exits
with exit status zero. If no such device is discovered/supported/used, prints
<literal>no</literal>. Otherwise prints <literal>partial</literal>. In either of these two cases
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-integritysetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry project='die-net'><refentrytitle>integritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>integritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
<listitem><para>Set soft and hard limits on various resources for executed processes. See
<citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
- details on the resource limit concept. Resource limits may be specified in two formats: either as
- single value to set a specific soft and hard limit to the same value, or as colon-separated pair
- <option>soft:hard</option> to set both limits individually (e.g. <literal>LimitAS=4G:16G</literal>).
- Use the string <option>infinity</option> to configure no limit on a specific resource. The
- multiplicative suffixes K, M, G, T, P and E (to the base 1024) may be used for resource limits
- measured in bytes (e.g. <literal>LimitAS=16G</literal>). For the limits referring to time values, the
- usual time units ms, s, min, h and so on may be used (see
+ details on the process resource limit concept. Process resource limits may be specified in two formats:
+ either as single value to set a specific soft and hard limit to the same value, or as colon-separated
+ pair <option>soft:hard</option> to set both limits individually
+ (e.g. <literal>LimitAS=4G:16G</literal>). Use the string <option>infinity</option> to configure no
+ limit on a specific resource. The multiplicative suffixes K, M, G, T, P and E (to the base 1024) may
+ be used for resource limits measured in bytes (e.g. <literal>LimitAS=16G</literal>). For the limits
+ referring to time values, the usual time units ms, s, min, h and so on may be used (see
<citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
details). Note that if no time unit is specified for <varname>LimitCPU=</varname> the default unit of
seconds is implied, while for <varname>LimitRTTIME=</varname> the default unit of microseconds is
<table>
<title>Resource limit directives, their equivalent <command>ulimit</command> shell commands and the unit used</title>
- <tgroup cols='3'>
+ <tgroup cols='4'>
<colspec colname='directive' />
<colspec colname='equivalent' />
<colspec colname='unit' />
+ <colspec colname='notes' />
<thead>
<row>
<entry>Directive</entry>
<entry><command>ulimit</command> equivalent</entry>
<entry>Unit</entry>
+ <entry>Notes</entry>
</row>
</thead>
<tbody>
<entry>LimitCPU=</entry>
<entry>ulimit -t</entry>
<entry>Seconds</entry>
+ <entry>-</entry>
</row>
<row>
<entry>LimitFSIZE=</entry>
<entry>ulimit -f</entry>
<entry>Bytes</entry>
+ <entry>-</entry>
</row>
<row>
<entry>LimitDATA=</entry>
<entry>ulimit -d</entry>
<entry>Bytes</entry>
+ <entry>Don't use. This limits the allowed address range, not memory use! Defaults to unlimited and should not be lowered. To limit memory use, see <varname>MemoryMax=</varname> in <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</entry>
</row>
<row>
<entry>LimitSTACK=</entry>
<entry>ulimit -s</entry>
<entry>Bytes</entry>
+ <entry>-</entry>
</row>
<row>
<entry>LimitCORE=</entry>
<entry>ulimit -c</entry>
<entry>Bytes</entry>
+ <entry>-</entry>
</row>
<row>
<entry>LimitRSS=</entry>
<entry>ulimit -m</entry>
<entry>Bytes</entry>
+ <entry>Don't use. No effect on Linux.</entry>
</row>
<row>
<entry>LimitNOFILE=</entry>
<entry>ulimit -n</entry>
<entry>Number of File Descriptors</entry>
+ <entry>Don't use. Be careful when raising the soft limit above 1024, since <function>select()</function> cannot function with file descriptors above 1023 on Linux. Nowadays, the hard limit defaults to 524288, a very high value compared to historical defaults. Typically applications should increase their soft limit to the hard limit on their own, if they are OK with working with file descriptors above 1023, i.e. do not use <function>select()</function>. Note that file descriptors are nowadays accounted like any other form of memory, thus there should not be any need to lower the hard limit. Use <varname>MemoryMax=</varname> to control overall service memory use, including file descriptor memory.</entry>
</row>
<row>
<entry>LimitAS=</entry>
<entry>ulimit -v</entry>
<entry>Bytes</entry>
+ <entry>Don't use. This limits the allowed address range, not memory use! Defaults to unlimited and should not be lowered. To limit memory use, see <varname>MemoryMax=</varname> in <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</entry>
</row>
<row>
<entry>LimitNPROC=</entry>
<entry>ulimit -u</entry>
<entry>Number of Processes</entry>
+ <entry>This limit is enforced based on the number of processes belonging to the user. Typically it's better to track processes per service, i.e. use <varname>TasksMax=</varname>, see <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</entry>
</row>
<row>
<entry>LimitMEMLOCK=</entry>
<entry>ulimit -l</entry>
<entry>Bytes</entry>
+ <entry>-</entry>
</row>
<row>
<entry>LimitLOCKS=</entry>
<entry>ulimit -x</entry>
<entry>Number of Locks</entry>
+ <entry>-</entry>
</row>
<row>
<entry>LimitSIGPENDING=</entry>
<entry>ulimit -i</entry>
<entry>Number of Queued Signals</entry>
+ <entry>-</entry>
</row>
<row>
<entry>LimitMSGQUEUE=</entry>
<entry>ulimit -q</entry>
<entry>Bytes</entry>
+ <entry>-</entry>
</row>
<row>
<entry>LimitNICE=</entry>
<entry>ulimit -e</entry>
<entry>Nice Level</entry>
+ <entry>-</entry>
</row>
<row>
<entry>LimitRTPRIO=</entry>
<entry>ulimit -r</entry>
<entry>Realtime Priority</entry>
+ <entry>-</entry>
</row>
<row>
<entry>LimitRTTIME=</entry>
- <entry>No equivalent</entry>
+ <entry>ulimit -R</entry>
<entry>Microseconds</entry>
+ <entry>-</entry>
</row>
</tbody>
</tgroup>
writing text to stderr will not work. To mitigate this use the construct <command>echo "hello"
>&2</command> instead, which is mostly equivalent and avoids this pitfall.</para>
- <para>This setting defaults to the value set with <varname>DefaultStandardOutput=</varname> in
+ <para>If <varname>StandardInput=</varname> is set to one of <option>tty</option>, <option>tty-force</option>,
+ <option>tty-fail</option>, <option>socket</option>, or <option>fd:<replaceable>name</replaceable></option>, this
+ setting defaults to <option>inherit</option>.</para>
+
+ <para>In other cases, this setting defaults to the value set with <varname>DefaultStandardOutput=</varname> in
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>, which
defaults to <option>journal</option>. Note that setting this parameter might result in additional dependencies
to be added to the unit (see above).</para></listitem>
<term><varname>$MONITOR_INVOCATION_ID</varname></term>
<term><varname>$MONITOR_UNIT</varname></term>
- <listitem><para>Only defined for the service unit type. Those environment variable are passed to
+ <listitem><para>Only defined for the service unit type. Those environment variables are passed to
all <varname>ExecStart=</varname> and <varname>ExecStartPre=</varname> processes which run in
services triggered by <varname>OnFailure=</varname> or <varname>OnSuccess=</varname> dependencies.
</para>
and <varname>$MONITOR_EXIT_STATUS</varname> take the same values as for
<varname>ExecStop=</varname> and <varname>ExecStopPost=</varname> processes. Variables
<varname>$MONITOR_INVOCATION_ID</varname> and <varname>$MONITOR_UNIT</varname> are set to the
- invocaton id and unit name of the service which triggered the dependency.</para>
+ invocation id and unit name of the service which triggered the dependency.</para>
<para>Note that when multiple services trigger the same unit, those variables will be
<emphasis>not</emphasis> be passed. Consider using a template handler unit for that case instead:
<refsect1>
<title><filename>fstab</filename></title>
- <para>Mount units may either be configured via unit files, or via
- <filename>/etc/fstab</filename> (see
+ <para>Mount units may either be configured via unit files, or via <filename>/etc/fstab</filename> (see
<citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for details). Mounts listed in <filename>/etc/fstab</filename>
- will be converted into native units dynamically at boot and when
- the configuration of the system manager is reloaded. In general,
- configuring mount points through <filename>/etc/fstab</filename>
- is the preferred approach. See
- <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- for details about the conversion.</para>
+ for details). Mounts listed in <filename>/etc/fstab</filename> will be converted into native units
+ dynamically at boot and when the configuration of the system manager is reloaded. In general, configuring
+ mount points through <filename>/etc/fstab</filename> is the preferred approach to manage mounts for
+ humans. For tooling, writing mount units should be preferred over editing <filename>/etc/fstab</filename>.
+ See <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ for details about the conversion from <filename>/etc/fstab</filename> to mount units.</para>
<para>The NFS mount option <option>bg</option> for NFS background mounts
as documented in <citerefentry project='man-pages'><refentrytitle>nfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>
<term><varname>PhysicalDevice=</varname></term>
<listitem>
<para>Specifies the name or index of the physical WLAN device (e.g. <literal>0</literal> or
- <literal>phy0</literal>). The list of the physical WLAN devices that exist os the host can be
+ <literal>phy0</literal>). The list of the physical WLAN devices that exist on the host can be
obtained by <command>iw phy</command> command. This option is mandatory.</para>
</listitem>
</varlistentry>
IGMP snooping since the switch would not replicate multicast packets on ports that did not
have IGMP reports for the multicast addresses. Linux vxlan interfaces created via
<command>ip link add vxlan</command> or networkd's netdev kind vxlan have the group option
- that enables then to do the required join. By extending ip address command with option
- <literal>autojoin</literal> we can get similar functionality for openvswitch (OVS) vxlan
- interfaces as well as other tunneling mechanisms that need to receive multicast traffic.
+ that enables them to do the required join. By extending <command>ip address</command> command
+ with option <literal>autojoin</literal> we can get similar functionality for openvswitch (OVS)
+ vxlan interfaces as well as other tunneling mechanisms that need to receive multicast traffic.
Defaults to <literal>no</literal>.</para>
</listitem>
</varlistentry>
<para>For IPv4 route, defaults to <literal>host</literal> if <varname>Type=</varname> is
<literal>local</literal> or <literal>nat</literal>, and <literal>link</literal> if
<varname>Type=</varname> is <literal>broadcast</literal>, <literal>multicast</literal>,
- <literal>anycast</literal>, or direct <literal>unicast</literal> routes. In other cases,
+ <literal>anycast</literal>, or <literal>unicast</literal>. In other cases,
defaults to <literal>global</literal>. The value is not used for IPv6.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>ServerAddress=</varname></term>
<listitem><para>Specifies server address for the DHCP server. Takes an IPv4 address with prefix
- length, for example <literal>192.168.0.1/24</literal>. This setting may be useful when the link on
+ length, for example 192.168.0.1/24. This setting may be useful when the link on
which the DHCP server is running has multiple static addresses. When unset, one of static addresses
in the link will be automatically selected. Defaults to unset.</para></listitem>
</varlistentry>
<listitem><para>The IPv6 route that is to be distributed to hosts. Similarly to configuring static
IPv6 routes, the setting is configured as an IPv6 prefix routes and its prefix route length,
- separated by a <literal>/</literal> character. Use multiple [IPv6PrefixRoutes] sections to configure
+ separated by a <literal>/</literal> character. Use multiple [IPv6RoutePrefix] sections to configure
multiple IPv6 prefix routes.</para></listitem>
</varlistentry>
<listitem><para>Similarly, a file <literal>https://download.example.com/foobarOS_47.verity.xz</literal>
should be downloaded, decompressed and written to a previously empty partition with GPT partition type
- UUID of 2c7357ed-ebd2-46d9-aec1-23d437ec2bf5 (i.e the partition type for Verity integrity information
+ UUID of 2c7357ed-ebd2-46d9-aec1-23d437ec2bf5 (i.e. the partition type for Verity integrity information
for x86-64 root file systems).</para></listitem>
<listitem><para>Finally, a file <literal>https://download.example.com/foobarOS_47.efi.xz</literal> (a
<itemizedlist>
<listitem><para>For partitions: the surrounding GPT partition table contains a list of defined
partitions, including a partition type UUID and a partition label (in this scheme the partition label
- plays a role for the partition similar to the filename for a regular file)</para></listitem>
+ plays a role for the partition similar to the filename for a regular file).</para></listitem>
<listitem><para>For regular files: the directory listing of the directory the files are contained in
provides a list of existing files in a straightforward way.</para></listitem>
<entry><literal>@r</literal></entry>
<entry>Read-only flag</entry>
<entry>Either <literal>0</literal> or <literal>1</literal></entry>
- <entry>Controls ReadOnly bit of the GPT partition flags, as per <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions Specification</ulink> and other output read-only flags, see <varname>ReadOnly=</varname> below.</entry>
+ <entry>Controls ReadOnly bit of the GPT partition flags, as per <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions Specification</ulink> and other output read-only flags, see <varname>ReadOnly=</varname> below</entry>
</row>
<row>
<entry><literal>@l</literal></entry>
<entry>Tries left</entry>
<entry>Formatted decimal integer</entry>
- <entry>Useful when operating with kernel images, as per <ulink url="https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT">Automatic Boot Assessment</ulink></entry>
+ <entry>Useful when operating with kernel image files, as per <ulink url="https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT">Automatic Boot Assessment</ulink></entry>
</row>
<row>
<entry><literal>@h</literal></entry>
<entry>SHA256 hash of compressed file</entry>
<entry>64 hexadecimal characters</entry>
- <entry>The SHA256 hash of the compressed file; not useful for <constant>url-file</constant> or <constant>url-tar</constant> where the SHA256 hash is already included in the manifest file anyway.</entry>
+ <entry>The SHA256 hash of the compressed file; not useful for <constant>url-file</constant> or <constant>url-tar</constant> where the SHA256 hash is already included in the manifest file anyway</entry>
</row>
</tbody>
</tgroup>
<refsect1>
<title>[Transfer] Section Options</title>
- <para>This section defines general properties of this transfer.</para>
+ <para>This section defines general properties of this transfer:</para>
<variablelist>
<varlistentry>
<listitem><para>Specifies a file system path where to look for already installed versions or place
newly downloaded versions of this configured resource. If <varname>Type=</varname> is set to
<constant>partition</constant>, expects a path to a (whole) block device node, or the special string
- <literal>auto</literal> in which case the block device the root file system of the currently booted
- system is automatically determined and used. If <varname>Type=</varname> is set to
+ <literal>auto</literal> in which case the block device which contains the root file system of the
+ currently booted system is automatically determined and used. If <varname>Type=</varname> is set to
<constant>regular-file</constant>, <constant>directory</constant> or <constant>subvolume</constant>,
must refer to a path in the local file system referencing the directory to find or place the version
files or directories under.</para>
MatchPattern=foobarOS_@v.efi.xz
[Target]
-Type=file
+Type=regular-file
Path=/efi/EFI/Linux
MatchPattern=foobarOS_@v+@l-@d.efi \
foobarOS_@v+@l.efi \
<para>The above installs a unified kernel image into the ESP (which is mounted to
<filename>/efi/</filename>), as per <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot
Loader Specification</ulink> Type #2. This defines three possible patterns for the names of the
- kernel images images, as per <ulink url="https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT">Automatic Boot
+ kernel images, as per <ulink url="https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT">Automatic Boot
Assessment</ulink>, and ensures when installing new kernels, they are set up with 3 tries left. No
more than two parallel kernels are kept.</para>
<para><command>udevadm lock</command> takes an (advisory) exclusive lock(s) on a block device (or
multiple thereof), as per <ulink url="https://systemd.io/BLOCK_DEVICE_LOCKING">Locking Block Device
Access</ulink> and invokes a program with the lock(s) taken. When the invoked program exits the lock(s)
- are automatically released.</para>
+ are automatically released and its return value is propagated as exit code of <command>udevadm
+ lock</command>.</para>
<para>This tool is in particular useful to ensure that
<citerefentry><refentrytitle>systemd-udevd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
#include <uchar.h>
#include <sys/mount.h>
#include <sys/stat.h>
-#include <linux/fs.h>
'''
foreach decl : ['char16_t',
# We get -1 if the size cannot be determined
have = cc.sizeof(decl, prefix : decl_headers, args : '-D_GNU_SOURCE') > 0
+ if decl == 'struct mount_attr'
+ if have
+ want_linux_fs_h = false
+ else
+ have = cc.sizeof(decl,
+ prefix : decl_headers + '#include <linux/fs.h>',
+ args : '-D_GNU_SOURCE') > 0
+ want_linux_fs_h = have
+ endif
+ endif
+
if decl == 'struct statx'
if have
want_linux_stat_h = false
endforeach
conf.set10('WANT_LINUX_STAT_H', want_linux_stat_h)
+conf.set10('WANT_LINUX_FS_H', want_linux_fs_h)
foreach ident : ['secure_getenv', '__secure_getenv']
conf.set10('HAVE_' + ident.to_upper(), cc.has_function(ident))
dependencies : [versiondep,
libseccomp],
install_rpath : rootlibexecdir,
- install : conf.get('ENABLE_ANALYZE'))
+ install : conf.get('ENABLE_ANALYZE') == 1)
executable(
'systemd-journald',
#include <errno.h>
#include <fcntl.h>
#include <linux/btrfs.h>
+#if WANT_LINUX_FS_H
#include <linux/fs.h>
+#endif
#include <linux/magic.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
return;
+ gcry_control(GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
assert_se(gcry_check_version("1.4.5"));
/* Turn off "secmem". Clients which wish to make use of this
* feature should initialize the library manually */
if (!secmem)
gcry_control(GCRYCTL_DISABLE_SECMEM);
+
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
}
#ifndef FS_PROJINHERIT_FL
#define FS_PROJINHERIT_FL 0x20000000
#endif
+
+/* linux/fscrypt.h */
+#ifndef FS_KEY_DESCRIPTOR_SIZE
+#define FS_KEY_DESCRIPTOR_SIZE 8
+#endif
return !!S_ISLNK(info.st_mode);
}
-int is_dir(const char* path, bool follow) {
+int is_dir_full(int atfd, const char* path, bool follow) {
struct stat st;
int r;
- assert(path);
+ assert(atfd >= 0 || atfd == AT_FDCWD);
+ assert(atfd >= 0 || path);
- if (follow)
- r = stat(path, &st);
+ if (path)
+ r = fstatat(atfd, path, &st, follow ? 0 : AT_SYMLINK_NOFOLLOW);
else
- r = lstat(path, &st);
+ r = fstat(atfd, &st);
if (r < 0)
return -errno;
return !!S_ISDIR(st.st_mode);
}
-int is_dir_fd(int fd) {
- struct stat st;
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- return !!S_ISDIR(st.st_mode);
-}
-
int is_device_node(const char *path) {
struct stat info;
#include "missing_stat.h"
int is_symlink(const char *path);
-int is_dir(const char *path, bool follow);
-int is_dir_fd(int fd);
+int is_dir_full(int atfd, const char *fname, bool follow);
+static inline int is_dir(const char *path, bool follow) {
+ return is_dir_full(AT_FDCWD, path, follow);
+}
+static inline int is_dir_fd(int fd) {
+ return is_dir_full(fd, NULL, false);
+}
int is_device_node(const char *path);
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup);
continue;
}
- r = set_consume(*names, TAKE_PTR(inst));
- if (r > 0)
- log_debug("Unit %s has alias %s.", unit_name, inst);
+ r = add_name(unit_name, names, inst);
} else
r = add_name(unit_name, names, *alias);
-
if (r < 0)
return r;
}
} dmi_vendor_table[] = {
{ "KVM", VIRTUALIZATION_KVM },
{ "OpenStack", VIRTUALIZATION_KVM }, /* Detect OpenStack instance as KVM in non x86 architecture */
+ { "KubeVirt", VIRTUALIZATION_KVM }, /* Detect KubeVirt instance as KVM in non x86 architecture */
{ "Amazon EC2", VIRTUALIZATION_AMAZON },
{ "QEMU", VIRTUALIZATION_QEMU },
{ "VMware", VIRTUALIZATION_VMWARE }, /* https://kb.vmware.com/s/article/1009458 */
'-include', version_h,
]
+# On some distros, sd-boot/-stub may trigger some bug somewhere that will cause
+# kernel execution to fail. The cause seems to be purely based on code size and
+# always compiling with at least -O1 will work around that.
+# https://github.com/systemd/systemd/issues/24202
+efi_cflags += '-O1'
+
efi_cflags += cc.get_supported_arguments({
'ia32': ['-mno-sse', '-mno-mmx'],
'x86_64': ['-mno-red-zone', '-mno-sse', '-mno-mmx'],
'-z', 'nocombreloc',
efi_crt0,
]
+
+possible_link_flags = [
+ '-Wl,--no-warn-execstack',
+ '-Wl,--no-warn-rwx-segments',
+]
+efi_ldflags += cc.get_supported_link_arguments(possible_link_flags)
+
if efi_arch[1] in ['aarch64', 'arm', 'riscv64']
efi_ldflags += ['-shared']
# Aarch64, ARM32 and 64bit RISC-V don't have an EFI capable objcopy.
_cleanup_close_ int fd = -1;
ssize_t n;
size_t l;
+ int r;
+
+ r = rearrange_stdio(-1, -1, -1);
+ if (r < 0) {
+ log_error_errno(r, "Failed to connect stdin/stdout/stderr with /dev/null: %m");
+ return EXIT_FAILURE;
+ }
if (argc != 2) {
log_error("Incorrect number of arguments.");
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
-const volatile __u8 is_allow_list = 0;
+const volatile __u8 is_allow_list SEC(".rodata") = 0;
/* Map containing the network interfaces indexes.
* The interpretation of the map depends on the value of is_allow_list.
#include "string-util.h"
#include "strv.h"
#include "strxcpyx.h"
+#include "umask-util.h"
#include "user-util.h"
#define CONNECTIONS_MAX 4096
if (fd < 0)
return log_error_errno(errno, "Failed to allocate private socket: %m");
- r = bind(fd, &sa.sa, sa_len);
+ RUN_WITH_UMASK(0077)
+ r = bind(fd, &sa.sa, sa_len);
if (r < 0)
return log_error_errno(errno, "Failed to bind private socket: %m");
if (nfd == -EEXIST)
continue;
if (nfd < 0)
- return r;
+ return nfd;
r = copy_bytes(cfd, nfd, st.st_size, 0);
if (r < 0) {
if (nfd == -EEXIST)
return 0;
if (nfd < 0)
- return r;
+ return nfd;
r = loop_write(nfd, colon, l, /* do_poll= */ false);
if (r < 0) {
rfd = openat(vfd, "raw", O_RDONLY|O_CLOEXEC);
if (rfd < 0) {
- log_warning_errno(r, "Failed to open '" QEMU_FWCFG_PATH "'/%s/raw, ignoring: %m", d->d_name);
+ log_warning_errno(errno, "Failed to open '" QEMU_FWCFG_PATH "'/%s/raw, ignoring: %m", d->d_name);
continue;
}
if (nfd == -EEXIST)
continue;
if (nfd < 0)
- return r;
+ return nfd;
r = copy_bytes(rfd, nfd, sz, 0);
if (r < 0) {
/* clear the kernel timestamp, because we are not PID 1 */
kernel_timestamp = DUAL_TIMESTAMP_NULL;
+ /* Clear ambient capabilities, so services do not inherit them implicitly. Dropping them does
+ * not affect the permitted and effective sets which are important for the manager itself to
+ * operate. */
+ capability_ambient_set_apply(0, /* also_inherit= */ false);
+
if (mac_selinux_init() < 0) {
error_message = "Failed to initialize SELinux support";
goto finish;
if (p && mount_is_bind(p)) {
r = mkdir_p_label(p->what, m->directory_mode);
/* mkdir_p_label() can return -EEXIST if the target path exists and is not a directory - which is
- * totally OK, in case the user wants us to overmount a non-directory inode. */
- if (r < 0 && r != -EEXIST) {
- log_unit_error_errno(UNIT(m), r, "Failed to make bind mount source '%s': %m", p->what);
- goto fail;
- }
+ * totally OK, in case the user wants us to overmount a non-directory inode. Also -EROFS can be
+ * returned on read-only filesystem. Moreover, -EACCES (and also maybe -EPERM?) may be returned
+ * when the path is on NFS. See issue #24120. All such errors will be logged in the debug level. */
+ if (r < 0 && r != -EEXIST)
+ log_unit_full_errno(UNIT(m),
+ (r == -EROFS || ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_WARNING,
+ r, "Failed to make bind mount source '%s', ignoring: %m", p->what);
}
if (p) {
#include <sys/file.h>
#include <sys/mount.h>
#include <unistd.h>
+#if WANT_LINUX_FS_H
#include <linux/fs.h>
+#endif
#include "alloc-util.h"
#include "base-filesystem.h"
return r;
}
if (r == 0) {
- log_unit_warning(u, "No PIDs left to attach to the scope's control group, refusing: %m");
+ log_unit_warning(u, "No PIDs left to attach to the scope's control group, refusing.");
scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
return -ECHILD;
}
struct iovec_wrapper *iovw;
int r;
+ /* When we're invoked by the kernel, stdout/stderr are closed which is dangerous because the fds
+ * could get reallocated. To avoid hard to debug issues, let's instead bind stdout/stderr to
+ * /dev/null. */
+ r = rearrange_stdio(STDIN_FILENO, -1, -1);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect stdout/stderr to /dev/null: %m");
+
log_debug("Processing coredump received from the kernel...");
iovw = iovw_new();
r = bus_home_path(h, l + k);
if (r < 0)
return r;
+
+ k++;
}
*nodes = TAKE_PTR(l);
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include <sys/mount.h>
+#if WANT_LINUX_FS_H
+#include <linux/fs.h>
+#endif
+
#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
#include <poll.h>
#include <sys/file.h>
#include <sys/ioctl.h>
-#include <sys/mount.h>
#include <sys/xattr.h>
#if HAVE_VALGRIND_MEMCHECK_H
#include <sched.h>
#include <sys/mount.h>
+#if WANT_LINUX_FS_H
#include <linux/fs.h>
+#endif
#include "alloc-util.h"
#include "fd-util.h"
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#include <linux/fs.h>
#include <sys/vfs.h>
#include "sd-id128.h"
+#include "cryptsetup-util.h"
#include "homework-password-cache.h"
#include "loop-util.h"
+#include "missing_fs.h" /* for FS_KEY_DESCRIPTOR_SIZE, do not include linux/fs.h */
#include "missing_keyctl.h"
#include "missing_syscall.h"
#include "user-record.h"
typedef enum PullFlags {
PULL_FORCE = 1 << 0, /* replace existing image */
PULL_READ_ONLY = 1 << 1, /* make generated image read-only */
- PULL_SETTINGS = 1 << 1, /* download .nspawn settings file */
- PULL_ROOTHASH = 1 << 2, /* only for raw: download .roothash file for verity */
- PULL_ROOTHASH_SIGNATURE = 1 << 3, /* only for raw: download .roothash.p7s file for verity */
- PULL_VERITY = 1 << 4, /* only for raw: download .verity file for verity */
- PULL_BTRFS_SUBVOL = 1 << 2, /* tar: preferably create images as btrfs subvols */
- PULL_BTRFS_QUOTA = 1 << 3, /* tar: set up btrfs quota for new subvolume as child of parent subvolume */
- PULL_CONVERT_QCOW2 = 1 << 4, /* raw: if we detect a qcow2 image, unpack it */
- PULL_DIRECT = 1 << 5, /* download without rename games */
- PULL_SYNC = 1 << 6, /* fsync() right before we are done */
+ PULL_SETTINGS = 1 << 2, /* download .nspawn settings file */
+ PULL_ROOTHASH = 1 << 3, /* only for raw: download .roothash file for verity */
+ PULL_ROOTHASH_SIGNATURE = 1 << 4, /* only for raw: download .roothash.p7s file for verity */
+ PULL_VERITY = 1 << 5, /* only for raw: download .verity file for verity */
+ PULL_BTRFS_SUBVOL = 1 << 6, /* tar: preferably create images as btrfs subvols */
+ PULL_BTRFS_QUOTA = 1 << 7, /* tar: set up btrfs quota for new subvolume as child of parent subvolume */
+ PULL_CONVERT_QCOW2 = 1 << 8, /* raw: if we detect a qcow2 image, unpack it */
+ PULL_DIRECT = 1 << 9, /* download without rename games */
+ PULL_SYNC = 1 << 10, /* fsync() right before we are done */
/* The supported flags for the tar and the raw pulling */
PULL_FLAGS_MASK_TAR = PULL_FORCE|PULL_READ_ONLY|PULL_SETTINGS|PULL_BTRFS_SUBVOL|PULL_BTRFS_QUOTA|PULL_DIRECT|PULL_SYNC,
return 0;
}
- if (!isempty(arg_existing_data_device)) {
- r = crypt_init_data_device(&cd, device, arg_existing_data_device);
- if (r < 0)
- return log_error_errno(r, "Failed to add separate data device: %m");
- }
-
r = crypt_load(cd,
CRYPT_INTEGRITY,
&(struct crypt_params_integrity) {
if (r < 0)
return log_error_errno(r, "Failed to load integrity superblock: %m");
+ if (!isempty(arg_existing_data_device)) {
+ r = crypt_set_data_device(cd, arg_existing_data_device);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add separate data device: %m");
+ }
+
r = crypt_activate_by_volume_key(cd, volume, key_buf, key_buf_size, arg_activate_flags);
if (r < 0)
return log_error_errno(r, "Failed to set up integrity device: %m");
if (buflen < offsetof(DHCP6Option, data))
return -EBADMSG;
- if (*offset >= buflen - offsetof(DHCP6Option, data))
+ if (*offset > buflen - offsetof(DHCP6Option, data))
return -EBADMSG;
len = unaligned_read_be16(buf + *offset + offsetof(DHCP6Option, len));
*ret_option_code = unaligned_read_be16(buf + *offset + offsetof(DHCP6Option, code));
*ret_option_data_len = len;
- *ret_option_data = buf + *offset + offsetof(DHCP6Option, data);
+ *ret_option_data = len == 0 ? NULL : buf + *offset + offsetof(DHCP6Option, data);
*offset += offsetof(DHCP6Option, data) + len;
return 0;
}
int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_status_message) {
- assert(data);
+ assert(data || data_len == 0);
if (data_len < sizeof(uint16_t))
return -EBADMSG;
struct in6_addr **addrs,
size_t *count) {
- assert(optval);
+ assert(optval || optlen == 0);
assert(addrs);
assert(count);
int r;
assert(data);
- assert(*data);
assert(len);
+ assert(*data || *len == 0);
assert(ret);
optval = *data;
_cleanup_free_ char *domain = NULL;
int r;
- assert(optval);
+ assert(optval || optlen == 0);
assert(ret);
r = parse_domain(&optval, &optlen, &domain);
_cleanup_strv_free_ char **names = NULL;
int r;
- assert(optval);
+ assert(optval || optlen == 0);
assert(ret);
if (optlen <= 1)
r = dhcp6_option_parse(message->options, len, &offset, &optcode, &optlen, &optval);
if (r < 0)
- return r;
+ return log_dhcp6_client_errno(client, r,
+ "Failed to parse option header at offset %zu of total length %zu: %m",
+ offset, len);
switch (optcode) {
case SD_DHCP6_OPTION_CLIENTID:
r = dhcp6_lease_set_clientid(lease, optval, optlen);
if (r < 0)
- return r;
+ return log_dhcp6_client_errno(client, r, "Failed to set client ID: %m");
break;
r = dhcp6_lease_set_serverid(lease, optval, optlen);
if (r < 0)
- return r;
+ return log_dhcp6_client_errno(client, r, "Failed to set server ID: %m");
break;
case SD_DHCP6_OPTION_PREFERENCE:
if (optlen != 1)
- return -EINVAL;
+ return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "Received invalid length for preference.");
r = dhcp6_lease_set_preference(lease, optval[0]);
if (r < 0)
- return r;
+ return log_dhcp6_client_errno(client, r, "Failed to set preference: %m");
break;
r = dhcp6_option_parse_status(optval, optlen, &msg);
if (r < 0)
- return r;
+ return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m");
if (r > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
r = dhcp6_option_parse_ia(client, client->ia_na.header.id, optcode, optlen, optval, &ia);
if (r == -ENOMEM)
- return r;
- if (r < 0)
+ return log_oom_debug();
+ if (r < 0) {
+ log_dhcp6_client_errno(client, r, "Failed to parse IA_NA option, ignoring: %m");
continue;
+ }
if (lease->ia_na) {
log_dhcp6_client(client, "Received duplicate matching IA_NA option, ignoring.");
r = dhcp6_option_parse_ia(client, client->ia_pd.header.id, optcode, optlen, optval, &ia);
if (r == -ENOMEM)
- return r;
- if (r < 0)
+ return log_oom_debug();
+ if (r < 0) {
+ log_dhcp6_client_errno(client, r, "Failed to parse IA_PD option, ignoring: %m");
continue;
+ }
if (lease->ia_pd) {
log_dhcp6_client(client, "Received duplicate matching IA_PD option, ignoring.");
break;
}
case SD_DHCP6_OPTION_RAPID_COMMIT:
+ if (optlen != 0)
+ log_dhcp6_client(client, "Received rapid commit option with an invalid length (%zu), ignoring.", optlen);
+
r = dhcp6_lease_set_rapid_commit(lease);
if (r < 0)
- return r;
+ return log_dhcp6_client_errno(client, r, "Failed to set rapid commit flag: %m");
break;
case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
if (optlen != 4)
- return -EINVAL;
+ return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
+ "Received information refresh time option with an invalid length (%zu).", optlen);
irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC;
break;
assert_se(dhcp6_lease_new_from_message(client, (const DHCP6Message*) msg, sizeof(msg), NULL, NULL, &lease) >= 0);
}
+TEST(client_parse_message_issue_24002) {
+ static const uint8_t msg[] = {
+ /* Message Type */
+ 0x07,
+ /* Transaction ID */
+ 0x0e, 0xa5, 0x7c,
+ /* Client ID */
+ 0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e,
+ 0x00, 0x02, /* DUID-EN */
+ 0x00, 0x00, 0xab, 0x11, /* pen */
+ 0x5c, 0x6b, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, /* id */
+ /* Server ID */
+ 0x00, 0x02, 0x00, 0x1a,
+ 0x00, 0x02, 0x00, 0x00, 0x05, 0x83, 0x30, 0x63, 0x3a, 0x38, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ /* IA_PD */
+ 0x00, 0x19, 0x00, 0x29,
+ 0xaa, 0xbb, 0xcc, 0xdd, /* iaid */
+ 0x00, 0x00, 0x03, 0x84, /* lifetime (T1) */
+ 0x00, 0x00, 0x05, 0xa0, /* lifetime (T2) */
+ /* IA_PD (iaprefix suboption) */
+ 0x00, 0x1a, 0x00, 0x19,
+ 0x00, 0x00, 0x07, 0x08, /* preferred lifetime */
+ 0x00, 0x00, 0x38, 0x40, /* valid lifetime */
+ 0x38, /* prefixlen */
+ 0x20, 0x03, 0x00, 0xff, 0xaa, 0xbb, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* prefix */
+ /* Rapid commit */
+ 0x00, 0x0e, 0x00, 0x00,
+ };
+ static const uint8_t duid[] = {
+ 0x00, 0x00, 0xab, 0x11, 0x5c, 0x6b, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ };
+ _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
+ _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
+
+ assert_se(sd_dhcp6_client_new(&client) >= 0);
+ assert_se(sd_dhcp6_client_set_iaid(client, 0xaabbccdd) >= 0);
+ assert_se(sd_dhcp6_client_set_duid(client, 2, duid, sizeof(duid)) >= 0);
+
+ assert_se(dhcp6_lease_new_from_message(client, (const DHCP6Message*) msg, sizeof(msg), NULL, NULL, &lease) >= 0);
+}
+
static const uint8_t msg_information_request[] = {
/* Message type */
DHCP6_MESSAGE_INFORMATION_REQUEST,
do { \
sd_bus_message *_mm = (m); \
log_debug("Got message type=%s sender=%s destination=%s path=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " signature=%s error-name=%s error-message=%s", \
- bus_message_type_to_string(_mm->header->type), \
+ strna(bus_message_type_to_string(_mm->header->type)), \
strna(sd_bus_message_get_sender(_mm)), \
strna(sd_bus_message_get_destination(_mm)), \
strna(sd_bus_message_get_path(_mm)), \
dev_t devnum;
char **properties_strv; /* the properties hashmap as a strv */
- uint8_t *properties_nulstr; /* the same as a nulstr */
+ char *properties_nulstr; /* the same as a nulstr */
size_t properties_nulstr_len;
char *syspath;
"sd-device-monitor: Invalid message header");
}
- r = device_new_from_nulstr(&device, (uint8_t*) &buf.raw[bufpos], buflen - bufpos);
+ r = device_new_from_nulstr(&device, &buf.raw[bufpos], buflen - bufpos);
if (r < 0)
return log_debug_errno(r, "sd-device-monitor: Failed to create device from received message: %m");
assert(m);
assert(device);
- r = device_get_properties_nulstr(device, (const uint8_t **) &buf, &blen);
+ r = device_get_properties_nulstr(device, &buf, &blen);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device-monitor: Failed to get device properties: %m");
if (blen < 32)
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to add tag '%s': %m", word);
}
+ } else if (streq(key, "UDEV_DATABASE_VERSION")) {
+ r = safe_atou(value, &device->database_version);
+ if (r < 0)
+ return log_device_debug_errno(device, r, "sd-device: Failed to parse udev database version '%s': %m", value);
} else {
r = device_add_property_internal(device, key, value);
if (r < 0)
return 0;
}
-int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
+int device_new_from_nulstr(sd_device **ret, char *nulstr, size_t len) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
const char *major = NULL, *minor = NULL;
int r;
char *key;
const char *end;
- key = (char*) &nulstr[i];
+ key = nulstr + i;
end = memchr(key, '\0', len - i);
if (!end)
return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
}
static int device_update_properties_bufs(sd_device *device) {
+ _cleanup_free_ char **buf_strv = NULL, *buf_nulstr = NULL;
+ size_t nulstr_len = 0, num = 0;
const char *val, *prop;
- _cleanup_free_ char **buf_strv = NULL;
- _cleanup_free_ uint8_t *buf_nulstr = NULL;
- size_t nulstr_len = 0, num = 0, i = 0;
assert(device);
if (!device->properties_buf_outdated)
return 0;
+ /* append udev database version */
+ buf_nulstr = newdup(char, "UDEV_DATABASE_VERSION=" STRINGIFY(LATEST_UDEV_DATABASE_VERSION) "\0",
+ STRLEN("UDEV_DATABASE_VERSION=" STRINGIFY(LATEST_UDEV_DATABASE_VERSION)) + 2);
+ if (!buf_nulstr)
+ return -ENOMEM;
+
+ nulstr_len += STRLEN("UDEV_DATABASE_VERSION=" STRINGIFY(LATEST_UDEV_DATABASE_VERSION)) + 1;
+ num++;
+
FOREACH_DEVICE_PROPERTY(device, prop, val) {
size_t len = 0;
if (!buf_nulstr)
return -ENOMEM;
- strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
+ strscpyl(buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
nulstr_len += len + 1;
- ++num;
+ num++;
}
/* build buf_strv from buf_nulstr */
- buf_strv = new0(char *, num + 1);
+ buf_strv = new0(char*, num + 1);
if (!buf_strv)
return -ENOMEM;
- NULSTR_FOREACH(val, (char*) buf_nulstr) {
- buf_strv[i] = (char *) val;
- assert(i < num);
- i++;
- }
+ size_t i = 0;
+ char *p;
+ NULSTR_FOREACH(p, buf_nulstr)
+ buf_strv[i++] = p;
+ assert(i == num);
free_and_replace(device->properties_nulstr, buf_nulstr);
device->properties_nulstr_len = nulstr_len;
free_and_replace(device->properties_strv, buf_strv);
device->properties_buf_outdated = false;
-
return 0;
}
-int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
+int device_get_properties_nulstr(sd_device *device, const char **ret_nulstr, size_t *ret_len) {
int r;
assert(device);
- assert(nulstr);
- assert(len);
r = device_update_properties_bufs(device);
if (r < 0)
return r;
- *nulstr = device->properties_nulstr;
- *len = device->properties_nulstr_len;
+ if (ret_nulstr)
+ *ret_nulstr = device->properties_nulstr;
+ if (ret_len)
+ *ret_len = device->properties_nulstr_len;
return 0;
}
-int device_get_properties_strv(sd_device *device, char ***strv) {
+int device_get_properties_strv(sd_device *device, char ***ret) {
int r;
assert(device);
- assert(strv);
r = device_update_properties_bufs(device);
if (r < 0)
return r;
- *strv = device->properties_strv;
+ if (ret)
+ *ret = device->properties_strv;
return 0;
}
#include "macro.h"
-int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len);
+int device_new_from_nulstr(sd_device **ret, char *nulstr, size_t len);
int device_new_from_strv(sd_device **ret, char **strv);
int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd);
static inline int device_new_from_watch_handle(sd_device **ret, int wd) {
uint64_t device_get_devlinks_generation(sd_device *device);
int device_properties_prepare(sd_device *device);
-int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len);
-int device_get_properties_strv(sd_device *device, char ***strv);
+int device_get_properties_nulstr(sd_device *device, const char **ret_nulstr, size_t *ret_len);
+int device_get_properties_strv(sd_device *device, char ***ret);
int device_rename(sd_device *device, const char *name);
int device_shallow_clone(sd_device *device, sd_device **ret);
"\0";
_cleanup_(sd_device_unrefp) sd_device *device = NULL, *from_nulstr = NULL;
- _cleanup_free_ uint8_t *nulstr_copy = NULL;
- const char *devlink;
- const uint8_t *nulstr;
+ _cleanup_free_ char *nulstr_copy = NULL;
+ const char *devlink, *nulstr;
size_t len;
assert_se(sd_device_new_from_syspath(&device, "/sys/class/net/lo") >= 0);
assert_se(set_contains(device->devlinks, devlink));
}
+ /* For issue #23799 */
+ assert_se(device_add_tag(device, "tag1", false) >= 0);
+ assert_se(device_add_tag(device, "tag2", false) >= 0);
+ assert_se(device_add_tag(device, "current-tag1", true) >= 0);
+ assert_se(device_add_tag(device, "current-tag2", true) >= 0);
+
/* These properties are necessary for device_new_from_nulstr(). See device_verify(). */
assert_se(device_add_property_internal(device, "SEQNUM", "1") >= 0);
assert_se(device_add_property_internal(device, "ACTION", "change") >= 0);
assert_se(device_get_properties_nulstr(device, &nulstr, &len) >= 0);
- assert_se(nulstr_copy = newdup(uint8_t, nulstr, len));
+ assert_se(nulstr_copy = newdup(char, nulstr, len));
assert_se(device_new_from_nulstr(&from_nulstr, nulstr_copy, len) >= 0);
+ assert_se(sd_device_has_tag(from_nulstr, "tag1") == 1);
+ assert_se(sd_device_has_tag(from_nulstr, "tag2") == 1);
+ assert_se(sd_device_has_tag(from_nulstr, "current-tag1") == 1);
+ assert_se(sd_device_has_tag(from_nulstr, "current-tag2") == 1);
+ assert_se(sd_device_has_current_tag(from_nulstr, "tag1") == 0);
+ assert_se(sd_device_has_current_tag(from_nulstr, "tag2") == 0);
+ assert_se(sd_device_has_current_tag(from_nulstr, "current-tag1") == 1);
+ assert_se(sd_device_has_current_tag(from_nulstr, "current-tag2") == 1);
+
NULSTR_FOREACH(devlink, devlinks) {
log_device_info(from_nulstr, "checking devlink: %s", devlink);
assert_se(set_contains(from_nulstr->devlinks, devlink));
return r;
r = copy_xattr(fileno(fr), fileno(fw), COPY_ALL_XATTRS);
if (r < 0)
- return r;
+ log_debug_errno(r, "Failed to copy all xattrs from old to new /etc/locale.gen file, ignoring: %m");
}
if (!write_new) {
assert(link);
assert(IN_SET(family, AF_INET, AF_INET6));
+ /* Currently, sd-dhcp-client supports only ethernet and infiniband. */
+ if (family == AF_INET && !IN_SET(link->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND))
+ return false;
+
if (family == AF_INET6 && !socket_ipv6_is_supported())
return false;
if (link->iftype == ARPHRD_CAN)
return false;
- if (!IN_SET(link->hw_addr.length, ETH_ALEN, INFINIBAND_ALEN) &&
- !streq_ptr(link->kind, "wwan"))
- /* Currently, only interfaces whose MAC address length is ETH_ALEN or INFINIBAND_ALEN
- * are supported. Note, wwan interfaces may be assigned MAC address slightly later.
- * Hence, let's wait for a while.*/
- return false;
-
if (!link->network)
return false;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return 0;
- if (!IN_SET(link->hw_addr.length, ETH_ALEN, INFINIBAND_ALEN) ||
- hw_addr_is_null(&link->hw_addr))
- /* No MAC address is assigned to the hardware, or non-supported MAC address length. */
- return 0;
-
r = dhcp4_configure_duid(link);
if (r <= 0)
return r;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return 0;
- if (!IN_SET(link->hw_addr.length, ETH_ALEN, INFINIBAND_ALEN) ||
- hw_addr_is_null(&link->hw_addr))
- /* No MAC address is assigned to the hardware, or non-supported MAC address length. */
- return 0;
-
r = dhcp_configure_duid(link, link_get_dhcp6_duid(link));
if (r <= 0)
return r;
if (r < 0)
return log_link_debug_errno(link, r, "Could not update MAC address for Router Advertisement: %m");
- if (link->ndisc) {
+ if (link->ndisc && link->hw_addr.length == ETH_ALEN) {
r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
if (r < 0)
return log_link_debug_errno(link, r, "Could not update MAC for NDisc: %m");
if (link->iftype == ARPHRD_CAN)
return false;
- if (link->hw_addr.length != ETH_ALEN && !streq_ptr(link->kind, "wwan"))
- /* Currently, only interfaces whose MAC address length is ETH_ALEN are supported.
- * Note, wwan interfaces may be assigned MAC address slightly later.
- * Hence, let's wait for a while.*/
- return false;
-
if (!link->network)
return false;
if (r < 0)
return r;
- r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
- if (r < 0)
- return r;
+ if (link->hw_addr.length == ETH_ALEN) {
+ r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
+ if (r < 0)
+ return r;
+ }
r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
if (r < 0)
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return 0;
- if (link->hw_addr.length != ETH_ALEN || hw_addr_is_null(&link->hw_addr))
- /* No MAC address is assigned to the hardware, or non-supported MAC address length. */
- return 0;
-
r = ndisc_configure(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Discovery: %m");
if (r < 0)
return r;
- r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
- if (r < 0)
- return r;
+ if (link->hw_addr.length == ETH_ALEN) {
+ r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
+ if (r < 0)
+ return r;
+ }
r = sd_radv_set_ifindex(link->radv, link->ifindex);
if (r < 0)
if (!link->radv)
return 0;
+ if (link->hw_addr.length != ETH_ALEN)
+ return 0;
+
restart = sd_radv_is_running(link->radv);
r = sd_radv_stop(link->radv);
r = maybe_resize_underlying_device(arg_target, devno);
if (r < 0)
- return r;
+ log_warning_errno(r, "Unable to resize underlying device of \"%s\", proceeding anyway: %m", arg_target);
mountfd = open(arg_target, O_RDONLY|O_CLOEXEC);
if (mountfd < 0)
return log_error_errno(errno, "Failed to query size of \"%s\": %m", devpath);
log_debug("Resizing \"%s\" to %"PRIu64" bytes...", arg_target, size);
+
+ if (arg_dry_run)
+ return 0;
+
r = resize_fs(mountfd, size, &newsize);
if (r < 0)
return log_error_errno(r, "Failed to resize \"%s\" to %"PRIu64" bytes: %m",
if (*backing_fd < 0) {
/* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */
- *backing_fd = fcntl(fdisk_get_devfd(c), F_DUPFD_CLOEXEC, 3);
+ *backing_fd = fd_reopen(fdisk_get_devfd(c), O_RDONLY|O_CLOEXEC);
if (*backing_fd < 0)
- return log_error_errno(errno, "Failed to duplicate fdisk fd: %m");
+ return log_error_errno(*backing_fd, "Failed to duplicate fdisk fd: %m");
}
/* Tell udev not to interfere while we are processing the device */
-# The "trusted" profile for services, i.e. no restrictions are applied
+# The "trusted" profile for services, i.e. no restrictions are applied apart from a private /tmp
[Service]
MountAPIVFS=yes
+PrivateTmp=yes
BindPaths=/run
BindReadOnlyPaths=/etc/machine-id
BindReadOnlyPaths=/etc/resolv.conf
return 1;
}
-int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
+int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p, usec_t ts, unsigned max_rr) {
unsigned ancount = 0;
DnsCacheItem *i;
int r;
assert(cache);
assert(p);
+ assert(p->protocol == DNS_PROTOCOL_MDNS);
HASHMAP_FOREACH(i, cache->by_key)
LIST_FOREACH(by_key, j, i) {
if (!j->shared_owner)
continue;
+ /* RFC6762 7.1: Don't append records with less than half the TTL remaining
+ * as known answers. */
+ if (usec_sub_unsigned(j->until, ts) < j->rr->ttl * USEC_PER_SEC / 2)
+ continue;
+
r = dns_packet_append_rr(p, j->rr, 0, NULL, NULL);
- if (r == -EMSGSIZE && p->protocol == DNS_PROTOCOL_MDNS) {
- /* For mDNS, if we're unable to stuff all known answers into the given packet,
- * allocate a new one, push the RR into that one and link it to the current one.
- */
+ if (r == -EMSGSIZE) {
+ if (max_rr == 0)
+ /* If max_rr == 0, do not allocate more packets. */
+ goto finalize;
+
+ /* If we're unable to stuff all known answers into the given packet, allocate
+ * a new one, push the RR into that one and link it to the current one. */
DNS_PACKET_HEADER(p)->ancount = htobe16(ancount);
ancount = 0;
return r;
ancount++;
+ if (max_rr > 0 && ancount >= max_rr) {
+ DNS_PACKET_HEADER(p)->ancount = htobe16(ancount);
+ ancount = 0;
+
+ r = dns_packet_new_query(&p->more, p->protocol, 0, true);
+ if (r < 0)
+ return r;
+
+ p = p->more;
+
+ max_rr = UINT_MAX;
+ }
}
+finalize:
DNS_PACKET_HEADER(p)->ancount = htobe16(ancount);
return 0;
unsigned dns_cache_size(DnsCache *cache);
-int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p);
+int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p, usec_t ts, unsigned max_rr);
if (has_search_domains && dns_name_is_single_label(domain))
return DNS_SCOPE_YES_BASE + 1;
+ /* If ResolveUnicastSingleLabel=yes and the query is single-label, then bump match result
+ to prevent LLMNR monopoly among candidates. */
+ if (s->manager->resolve_unicast_single_label && dns_name_is_single_label(domain))
+ return DNS_SCOPE_YES_BASE + 1;
+
/* Let's return the number of labels in the best matching result */
if (n_best >= 0) {
assert(n_best <= DNS_SCOPE_YES_END - DNS_SCOPE_YES_BASE);
return;
}
- assert(dns_question_size(p->question) == 1);
+ if (dns_question_size(p->question) != 1)
+ return (void) log_debug("Received LLMNR query without question or multiple questions, ignoring.");
+
key = dns_question_first_key(p->question);
r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative);
}
int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
- usec_t jitter;
int r;
assert(scope);
if (scope->conflict_event_source)
return 0;
- random_bytes(&jitter, sizeof(jitter));
- jitter %= LLMNR_JITTER_INTERVAL_USEC;
-
r = sd_event_add_time_relative(
scope->manager->event,
&scope->conflict_event_source,
CLOCK_BOOTTIME,
- jitter,
- LLMNR_JITTER_INTERVAL_USEC,
+ random_u64_range(LLMNR_JITTER_INTERVAL_USEC),
+ 0,
on_conflict_dispatch, scope);
if (r < 0)
return log_debug_errno(r, "Failed to add conflict dispatch event: %m");
&scope->announce_event_source,
CLOCK_BOOTTIME,
MDNS_ANNOUNCE_DELAY,
- MDNS_JITTER_RANGE_USEC,
+ 0,
on_announcement_timeout, scope);
if (r < 0)
return log_debug_errno(r, "Failed to schedule second announcement: %m");
return 0;
}
+static int dns_transaction_setup_timeout(
+ DnsTransaction *t,
+ usec_t timeout_usec /* relative */,
+ usec_t next_usec /* CLOCK_BOOTTIME */) {
+
+ int r;
+
+ assert(t);
+
+ dns_transaction_stop_timeout(t);
+
+ r = sd_event_add_time_relative(
+ t->scope->manager->event,
+ &t->timeout_event_source,
+ CLOCK_BOOTTIME,
+ timeout_usec, 0,
+ on_transaction_timeout, t);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout");
+
+ t->next_attempt_after = next_usec;
+ t->state = DNS_TRANSACTION_PENDING;
+ return 0;
+}
+
static usec_t transaction_get_resend_timeout(DnsTransaction *t) {
assert(t);
assert(t->scope);
return DNS_TIMEOUT_USEC;
case DNS_PROTOCOL_MDNS:
- assert(t->n_attempts > 0);
if (t->probing)
return MDNS_PROBING_INTERVAL_USEC;
- else
- return (1 << (t->n_attempts - 1)) * USEC_PER_SEC;
+
+ /* See RFC 6762 Section 5.1 suggests that timeout should be a few seconds. */
+ assert(t->n_attempts > 0);
+ return (1 << (t->n_attempts - 1)) * USEC_PER_SEC;
case DNS_PROTOCOL_LLMNR:
return t->scope->resend_timeout;
return 1;
}
+static int dns_packet_append_zone(DnsPacket *p, DnsTransaction *t, DnsResourceKey *k, unsigned *nscount) {
+ _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
+ bool tentative;
+ int r;
+
+ assert(p);
+ assert(t);
+ assert(k);
+
+ if (k->type != DNS_TYPE_ANY)
+ return 0;
+
+ r = dns_zone_lookup(&t->scope->zone, k, t->scope->link->ifindex, &answer, NULL, &tentative);
+ if (r < 0)
+ return r;
+
+ return dns_packet_append_answer(p, answer, nscount);
+}
+
static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- bool add_known_answers = false;
- DnsResourceKey *tkey;
_cleanup_set_free_ Set *keys = NULL;
- unsigned qdcount;
- unsigned nscount = 0;
+ unsigned qdcount, ancount = 0 /* avoid false maybe-uninitialized warning */, nscount;
+ bool add_known_answers = false;
usec_t ts;
int r;
/* Discard any previously prepared packet, so we can start over and coalesce again */
t->sent = dns_packet_unref(t->sent);
+ /* First, create a dummy packet to calculate packet size. */
r = dns_packet_new_query(&p, t->scope->protocol, 0, false);
if (r < 0)
return r;
if (dns_key_is_shared(dns_transaction_key(t)))
add_known_answers = true;
- if (dns_transaction_key(t)->type == DNS_TYPE_ANY) {
- r = set_ensure_put(&keys, &dns_resource_key_hash_ops, dns_transaction_key(t));
- if (r < 0)
- return r;
- }
+ r = dns_packet_append_zone(p, t, dns_transaction_key(t), NULL);
+ if (r < 0)
+ return r;
+
+ /* Save appended keys */
+ r = set_ensure_put(&keys, &dns_resource_key_hash_ops, dns_transaction_key(t));
+ if (r < 0)
+ return r;
/*
* For mDNS, we want to coalesce as many open queries in pending transactions into one single
assert_se(sd_event_now(t->scope->manager->event, CLOCK_BOOTTIME, &ts) >= 0);
- LIST_FOREACH(transactions_by_scope, other, t->scope->transactions) {
-
- /* Skip ourselves */
- if (other == t)
- continue;
+ for (bool restart = true; restart;) {
+ restart = false;
+ LIST_FOREACH(transactions_by_scope, other, t->scope->transactions) {
+ size_t saved_packet_size;
+ bool append = false;
- if (other->state != DNS_TRANSACTION_PENDING)
- continue;
-
- if (other->next_attempt_after > ts)
- continue;
-
- if (qdcount >= UINT16_MAX)
- break;
+ /* Skip ourselves */
+ if (other == t)
+ continue;
- r = dns_packet_append_key(p, dns_transaction_key(other), 0, NULL);
+ if (other->state != DNS_TRANSACTION_PENDING)
+ continue;
- /*
- * If we can't stuff more questions into the packet, just give up.
- * One of the 'other' transactions will fire later and take care of the rest.
- */
- if (r == -EMSGSIZE)
- break;
+ if (other->next_attempt_after > ts)
+ continue;
- if (r < 0)
- return r;
+ if (!set_contains(keys, dns_transaction_key(other))) {
+ r = dns_packet_append_key(p, dns_transaction_key(other), 0, &saved_packet_size);
+ /* If we can't stuff more questions into the packet, just give up.
+ * One of the 'other' transactions will fire later and take care of the rest. */
+ if (r == -EMSGSIZE)
+ break;
+ if (r < 0)
+ return r;
- r = dns_transaction_prepare(other, ts);
- if (r <= 0)
- continue;
+ r = dns_packet_append_zone(p, t, dns_transaction_key(other), NULL);
+ if (r == -EMSGSIZE)
+ break;
+ if (r < 0)
+ return r;
- ts += transaction_get_resend_timeout(other);
+ append = true;
+ }
- r = sd_event_add_time(
- other->scope->manager->event,
- &other->timeout_event_source,
- CLOCK_BOOTTIME,
- ts, 0,
- on_transaction_timeout, other);
- if (r < 0)
- return r;
+ r = dns_transaction_prepare(other, ts);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ if (append)
+ dns_packet_truncate(p, saved_packet_size);
- (void) sd_event_source_set_description(other->timeout_event_source, "dns-transaction-timeout");
+ /* In this case, not only this transaction, but multiple transactions may be
+ * freed. Hence, we need to restart the loop. */
+ restart = true;
+ break;
+ }
- other->state = DNS_TRANSACTION_PENDING;
- other->next_attempt_after = ts;
+ usec_t timeout = transaction_get_resend_timeout(other);
+ r = dns_transaction_setup_timeout(other, timeout, usec_add(ts, timeout));
+ if (r < 0)
+ return r;
- qdcount++;
+ if (dns_key_is_shared(dns_transaction_key(other)))
+ add_known_answers = true;
- if (dns_key_is_shared(dns_transaction_key(other)))
- add_known_answers = true;
+ if (append) {
+ r = set_ensure_put(&keys, &dns_resource_key_hash_ops, dns_transaction_key(other));
+ if (r < 0)
+ return r;
+ }
- if (dns_transaction_key(other)->type == DNS_TYPE_ANY) {
- r = set_ensure_put(&keys, &dns_resource_key_hash_ops, dns_transaction_key(other));
- if (r < 0)
- return r;
+ qdcount++;
+ if (qdcount >= UINT16_MAX)
+ break;
}
}
- DNS_PACKET_HEADER(p)->qdcount = htobe16(qdcount);
-
/* Append known answer section if we're asking for any shared record */
if (add_known_answers) {
- r = dns_cache_export_shared_to_packet(&t->scope->cache, p);
+ r = dns_cache_export_shared_to_packet(&t->scope->cache, p, ts, 0);
if (r < 0)
return r;
+
+ ancount = be16toh(DNS_PACKET_HEADER(p)->ancount);
}
- SET_FOREACH(tkey, keys) {
- _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
- bool tentative;
+ /* Then, create acctual packet. */
+ p = dns_packet_unref(p);
+ r = dns_packet_new_query(&p, t->scope->protocol, 0, false);
+ if (r < 0)
+ return r;
- r = dns_zone_lookup(&t->scope->zone, tkey, t->scope->link->ifindex, &answer, NULL, &tentative);
+ /* Questions */
+ DnsResourceKey *k;
+ SET_FOREACH(k, keys) {
+ r = dns_packet_append_key(p, k, 0, NULL);
if (r < 0)
return r;
+ }
+ DNS_PACKET_HEADER(p)->qdcount = htobe16(qdcount);
- r = dns_packet_append_answer(p, answer, &nscount);
+ /* Known answers */
+ if (add_known_answers) {
+ r = dns_cache_export_shared_to_packet(&t->scope->cache, p, ts, ancount);
+ if (r < 0)
+ return r;
+ }
+
+ /* Authorities */
+ nscount = 0;
+ SET_FOREACH(k, keys) {
+ r = dns_packet_append_zone(p, t, k, &nscount);
if (r < 0)
return r;
}
DNS_PACKET_HEADER(p)->nscount = htobe16(nscount);
t->sent = TAKE_PTR(p);
-
return 0;
}
if (!t->initial_jitter_scheduled &&
IN_SET(t->scope->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) {
- usec_t jitter, accuracy;
+ usec_t jitter;
- /* RFC 4795 Section 2.7 suggests all queries should be delayed by a random time from 0 to
- * JITTER_INTERVAL. */
+ /* RFC 4795 Section 2.7 suggests all LLMNR queries should be delayed by a random time from 0 to
+ * JITTER_INTERVAL.
+ * RFC 6762 Section 8.1 suggests initial probe queries should be delayed by a random time from
+ * 0 to 250ms. */
t->initial_jitter_scheduled = true;
+ t->n_attempts = 0;
switch (t->scope->protocol) {
case DNS_PROTOCOL_LLMNR:
jitter = random_u64_range(LLMNR_JITTER_INTERVAL_USEC);
- accuracy = LLMNR_JITTER_INTERVAL_USEC;
break;
case DNS_PROTOCOL_MDNS:
- jitter = usec_add(random_u64_range(MDNS_JITTER_RANGE_USEC), MDNS_JITTER_MIN_USEC);
- accuracy = MDNS_JITTER_RANGE_USEC;
+ if (t->probing)
+ jitter = random_u64_range(MDNS_PROBING_INTERVAL_USEC);
+ else
+ jitter = 0;
break;
default:
assert_not_reached();
}
- assert(!t->timeout_event_source);
-
- r = sd_event_add_time_relative(
- t->scope->manager->event,
- &t->timeout_event_source,
- CLOCK_BOOTTIME,
- jitter, accuracy,
- on_transaction_timeout, t);
+ r = dns_transaction_setup_timeout(t, jitter, ts);
if (r < 0)
return r;
- (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout");
-
- t->n_attempts = 0;
- t->next_attempt_after = ts;
- t->state = DNS_TRANSACTION_PENDING;
-
log_debug("Delaying %s transaction %" PRIu16 " for " USEC_FMT "us.",
dns_protocol_to_string(t->scope->protocol),
t->id,
return dns_transaction_go(t);
}
- ts += transaction_get_resend_timeout(t);
-
- r = sd_event_add_time(
- t->scope->manager->event,
- &t->timeout_event_source,
- CLOCK_BOOTTIME,
- ts, 0,
- on_transaction_timeout, t);
+ usec_t timeout = transaction_get_resend_timeout(t);
+ r = dns_transaction_setup_timeout(t, timeout, usec_add(ts, timeout));
if (r < 0)
return r;
- (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout");
-
- t->state = DNS_TRANSACTION_PENDING;
- t->next_attempt_after = ts;
-
return 1;
}
/* LLMNR Jitter interval, see RFC 4795 Section 7 */
#define LLMNR_JITTER_INTERVAL_USEC (100 * USEC_PER_MSEC)
-/* mDNS Jitter interval, see RFC 6762 Section 5.2 */
-#define MDNS_JITTER_MIN_USEC (20 * USEC_PER_MSEC)
-#define MDNS_JITTER_RANGE_USEC (100 * USEC_PER_MSEC)
-
/* mDNS probing interval, see RFC 6762 Section 8.1 */
#define MDNS_PROBING_INTERVAL_USEC (250 * USEC_PER_MSEC)
if (r < 0)
return r;
- assert(r > 0);
-
if (proposed_rrs_cmp(remote, r, our, size) > 0)
return 1;
}
/* All the questions in the query had a QU bit set, RFC 6762, section 5.4 */
- DNS_QUESTION_FOREACH_ITEM(item, p->question) {
+ DNS_QUESTION_FOREACH_ITEM(item, p->question)
if (!FLAGS_SET(item->flags, DNS_QUESTION_WANTS_UNICAST_REPLY))
return false;
- }
+
return true;
}
if (r < 0)
return log_debug_errno(r, "Failed to extract resource records from incoming packet: %m");
- assert_return((dns_question_size(p->question) > 0), -EINVAL);
+ if (dns_question_size(p->question) <= 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Received mDNS query without question, ignoring.");
unicast_reply = mdns_should_reply_using_unicast(p);
if (unicast_reply && !sender_on_local_subnet(s, p)) {
}
}
- LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
- r = dns_answer_match_key(p->answer, t->key, NULL);
- if (r < 0)
- log_debug_errno(r, "Failed to match resource key, ignoring: %m");
- else if (r > 0) /* This packet matches the transaction, let's pass it on as reply */
+ for (bool match = true; match;) {
+ match = false;
+ LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
+ if (t->state != DNS_TRANSACTION_PENDING)
+ continue;
+
+ r = dns_answer_match_key(p->answer, dns_transaction_key(t), NULL);
+ if (r <= 0) {
+ if (r < 0)
+ log_debug_errno(r, "Failed to match resource key, ignoring: %m");
+ continue;
+ }
+
+ /* This packet matches the transaction, let's pass it on as reply */
dns_transaction_process_reply(t, p, false);
+
+ /* The dns_transaction_process_reply() -> dns_transaction_complete() ->
+ * dns_query_candidate_stop() may free multiple transactions. Hence, restart
+ * the loop. */
+ match = true;
+ break;
+ }
}
dns_cache_put(&scope->cache, scope->manager->enable_cache, NULL, DNS_PACKET_RCODE(p), p->answer, NULL, false, _DNSSEC_RESULT_INVALID, UINT32_MAX, p->family, &p->sender);
static const BaseFilesystem table[] = {
{ "bin", 0, "usr/bin\0", NULL },
{ "lib", 0, "usr/lib\0", NULL },
- { "root", 0755, NULL, NULL, true },
+ { "root", 0750, NULL, NULL, true },
{ "sbin", 0, "usr/sbin\0", NULL },
{ "usr", 0755, NULL, NULL },
{ "var", 0755, NULL, NULL },
#include <sys/statvfs.h>
#include <unistd.h>
#include <linux/loop.h>
+#if WANT_LINUX_FS_H
#include <linux/fs.h>
+#endif
#include "alloc-util.h"
#include "chase-symlinks.h"
#HibernateState=disk
#HybridSleepMode=suspend platform shutdown
#HybridSleepState=disk
-#HibernateDelaySec=180min
+#HibernateDelaySec=120min
int unit_get_dependencies(sd_bus *bus, const char *name, char ***ret) {
_cleanup_strv_free_ char **deps = NULL;
- static const struct bus_properties_map map[_DEPENDENCY_MAX][6] = {
+ static const struct bus_properties_map map[_DEPENDENCY_MAX][7] = {
[DEPENDENCY_FORWARD] = {
{ "Requires", "as", NULL, 0 },
{ "Requisite", "as", NULL, 0 },
{ "Wants", "as", NULL, 0 },
{ "ConsistsOf", "as", NULL, 0 },
{ "BindsTo", "as", NULL, 0 },
+ { "Upholds", "as", NULL, 0 },
{}
},
[DEPENDENCY_REVERSE] = {
{ "WantedBy", "as", NULL, 0 },
{ "PartOf", "as", NULL, 0 },
{ "BoundBy", "as", NULL, 0 },
+ { "UpheldBy", "as", NULL, 0 },
{}
},
[DEPENDENCY_AFTER] = {
#endif
#ifndef _SD_ARRAY_STATIC
-# if __STDC_VERSION__ >= 199901L
+# if __STDC_VERSION__ >= 199901L && !defined(__cplusplus)
# define _SD_ARRAY_STATIC static
# else
# define _SD_ARRAY_STATIC
r = btrfs_is_subvol(empty_to_root(arg_root)) > 0;
}
if (!r)
- /* Don't create a subvolume unless the root directory is
- * one, too. We do this under the assumption that if the
- * root directory is just a plain directory (i.e. very
- * light-weight), we shouldn't try to split it up into
- * subvolumes (i.e. more heavy-weight). Thus, chroot()
- * environments and suchlike will get a full brtfs
- * subvolume set up below their tree only if they
- * specifically set up a btrfs subvolume for the root
- * dir too. */
+ /* Don't create a subvolume unless the root directory is one, too. We do this under
+ * the assumption that if the root directory is just a plain directory (i.e. very
+ * light-weight), we shouldn't try to split it up into subvolumes (i.e. more
+ * heavy-weight). Thus, chroot() environments and suchlike will get a full brtfs
+ * subvolume set up below their tree only if they specifically set up a btrfs
+ * subvolume for the root dir too. */
subvol = false;
else {
if (!IN_SET(r, -EEXIST, -EROFS))
return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", path);
- k = is_dir_fd(pfd);
+ k = is_dir_full(pfd, basename(path), /* follow= */ false);
if (k == -ENOENT && r == -EROFS)
return log_error_errno(r, "%s does not exist and cannot be created as the file system is read-only.", path);
if (k < 0)
r = udev_rules_apply_static_dev_perms(manager->rules);
if (r < 0)
- log_error_errno(r, "Failed to apply permissions on static device nodes: %m");
+ log_warning_errno(r, "Failed to apply permissions on static device nodes, ignoring: %m");
notify_ready();
fi
dd if=/dev/zero of="${image_dir}/image" bs=1048576 count=64 || exit 1
+dd if=/dev/zero of="${image_dir}/data" bs=1048576 count=64 || exit 1
loop="$(losetup --show -f "${image_dir}/image")"
if [[ ! -e ${loop} ]]; then
exit 1
fi
+# Do one iteration with a separate data device, to test those branches
+separate_data=1
+
for algorithm in crc32c crc32 sha1 sha256
do
- integritysetup format "${loop}" --batch-mode -I "${algorithm}" || exit 1
- integritysetup open -I "${algorithm}" "${loop}" "${DM_NAME}" || exit 1
+ if [ "${separate_data}" -eq 1 ]; then
+ data_option="--data-device=${image_dir}/data"
+ else
+ data_option=""
+ fi
+ integritysetup format "${loop}" --batch-mode -I "${algorithm}" "${data_option}" || exit 1
+ integritysetup open -I "${algorithm}" "${loop}" "${DM_NAME}" "${data_option}" || exit 1
mkfs.ext4 -U "${FS_UUID}" "${FULL_DM_DEV_NAME}" || exit 1
# Give userspace time to handle udev events for new FS showing up ...
integritysetup close "${DM_NAME}" || exit 1
# create integritytab, generate units, start service
- build_integrity_tab ${algorithm}
+ if [ "${separate_data}" -eq 1 ]; then
+ data_option=",data-device=${image_dir}/data"
+ else
+ data_option=""
+ fi
+ build_integrity_tab "${algorithm}${data_option}"
# Cause the generator to re-run
systemctl daemon-reload || exit 1
# Check the signature on the FS to ensure we can retrieve it and that is matches
if [ -e "${FULL_DM_DEV_NAME}" ]; then
- if [ "${FULL_DM_DEV_NAME}" != "$(blkid -U "${FS_UUID}")" ]; then
+ # If a separate device is used for the metadata storage, then blkid will return one of the loop devices
+ if [ "${separate_data}" -eq 1 ]; then
+ dev_name="$(integritysetup status ${DM_NAME} | grep '^\s*device:' | awk '{print $2}')"
+ else
+ dev_name="${FULL_DM_DEV_NAME}"
+ fi
+ if [ "${dev_name}" != "$(blkid -U "${FS_UUID}")" ]; then
echo "Failed to locate FS with matching UUID!"
exit 1
fi
exit 1
fi
+ separate_data=0
done
echo OK >/testok