under /usr is strongly encouraged.
Additional packages are necessary to run some tests:
- - busybox (used by test/TEST-13-NSPAWN-SMOKE)
- nc (used by test/TEST-12-ISSUE-3171)
- python (test-udev which is installed is in python)
- python-pyparsing
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivoTecnologiaSA:pn*:pvr*:rvnPositivoTecnologiaSA:rnK116*
KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
+# Positivo (CG15D)
+evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn*:pvr*:rvn*:rnCG15D*
# Positivo Motion (N14DP6, N14DP7, N14DP7-V2, N14DP9, N14JP6, N14KP6)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn*:pvr*:rvn*:rnN14[DJK]P*
KEYBOARD_KEY_76=f21 # Fn+f2 toggle touchpad
parse_hwdb_py = find_program('parse_hwdb.py')
test('parse-hwdb',
parse_hwdb_py,
- suite : 'dist-check',
+ suite : 'dist',
args : [hwdb_files_test,
auto_suspend_rules],
timeout : 90)
allows one to ship multiple sets of Secure Boot variables and choose which one to enroll at runtime.
</para>
- <para>Supported Secure Boot variables are one database for authorized images, one key exchange key
- (KEK) and one platform key (PK). For more information, refer to the <ulink
- url="https://uefi.org/specifications">UEFI specification</ulink>, under Secure Boot and Driver
+ <para>Supported Secure Boot variables are one database for authorized images, one for the key
+ exchange key (KEK) and one for the platform key (PK). For more information, refer to the
+ <ulink url="https://uefi.org/specifications">UEFI specification</ulink>, under Secure Boot and Driver
Signing. Another resource that describe the interplay of the different variables is the
<ulink url="https://edk2-docs.gitbook.io/understanding-the-uefi-secure-boot-chain/secure_boot_chain_in_uefi/uefi_secure_boot">
EDK2 documentation</ulink>.</para>
if conf.get('BUILD_MODE_DEVELOPER') == 1
test('dbus-docs-fresh',
update_dbus_docs_py,
- suite : 'dist-check',
+ suite : 'dist',
args : ['--build-dir', project_build_root, '--test', dbus_docs],
depends : dbus_programs)
endif
<term><varname>$SYSTEMD_NSS_RESOLVE_CACHE</varname></term>
<listitem><para>Takes a boolean argument. When false, the cache of previously queried records will
- not be used by <command>systemd-resolved</command>.</para></listitem>
+ not be used by
+ <citerefentry><refentrytitle>systemd-resolved</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ </para></listitem>
</varlistentry>
</variablelist>
<term><varname>$SYSTEMD_NSS_RESOLVE_NETWORK</varname></term>
<listitem><para>Takes a boolean argument. When false, answers will be returned without using the
- network, i.e. either from local sources or the cache in <command>systemd-resolved</command>.
+ network, i.e. either from local sources or the cache in
+ <citerefentry><refentrytitle>systemd-resolved</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
</variablelist>
only provided in a best effort fashion: it is not guaranteed to be set, and it is not guaranteed to be
the only trigger. It is only guaranteed to be a valid trigger that caused the activation job to be
enqueued and complete successfully. The key value pairs correspond (in lowercase) to the environment
- variables described in the <literal>Environment Variables Set on Triggered Units</literal> section in
- <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
- Note that new key value pair may be added at any time in future versions. Existing entries will not be
+ variables described in the <literal>Environment Variables Set or Propagated by the Service
+ Manager</literal> section in
+ <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>. Note
+ that new key value pair may be added at any time in future versions. Existing entries will not be
removed.</para>
</refsect2>
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u RestartSteps = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
- readonly t RestartUSecMax = ...;
+ readonly t RestartMaxDelayUSec = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t RestartUSecNext = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
<!--property RestartSteps is not documented!-->
- <!--property RestartUSecMax is not documented!-->
+ <!--property RestartMaxDelayUSec is not documented!-->
<!--property RestartUSecNext is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="RestartSteps"/>
- <variablelist class="dbus-property" generated="True" extra-ref="RestartUSecMax"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="RestartMaxDelayUSec"/>
<variablelist class="dbus-property" generated="True" extra-ref="RestartUSecNext"/>
<para>Note that <varname>CopyFiles=</varname> will skip copying files that aren't supported by the
target filesystem (e.g symlinks, fifos, sockets and devices on vfat). When an unsupported file type
- is encountered, repart will skip copying this file and write a log message about it.</para>
+ is encountered, <command>systemd-repart</command> will skip copying this file and write a log message
+ about it.</para>
<para>Note that <command>systemd-repart</command> does not change the UIDs/GIDs of any copied files
and directories. When running <command>systemd-repart</command> as an unprivileged user to build an
<para>Note that when populating XFS filesystems with <command>systemd-repart</command> and loop
devices are not available, populating XFS filesystems with files containing spaces, tabs or newlines
- will fail due to limitations of mkfs.xfs's protofile format.</para>
+ will fail due to limitations of <citerefentry
+ project='man-pages'><refentrytitle>mkfs.xfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ protofile format.</para>
<para>This option cannot be combined with <varname>CopyBlocks=</varname>.</para>
<term><varname>SplitName=</varname></term>
<listitem><para>Configures the suffix to append to split artifacts when the <option>--split</option>
- option of <command>systemd-repart</command> is used. Simple specifier expansion is supported, see
- below. Defaults to <literal>%t</literal>. To disable split artifact generation for a partition, set
- <varname>SplitName=</varname> to <literal>-</literal>.</para></listitem>
+ option of
+ <citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry> is
+ used. Simple specifier expansion is supported, see below. Defaults to <literal>%t</literal>. To
+ disable split artifact generation for a partition, set <varname>SplitName=</varname> to
+ <literal>-</literal>.</para></listitem>
</varlistentry>
<varlistentry>
times. Specifically:</para>
<orderedlist>
- <listitem><para>In UEFI mode, the <filename>systemd-boot</filename> or
- <filename>systemd-stub</filename> components load the boot loader random seed off the ESP, hash it with
- available entropy and the system token, and then update it on disk. A derived seed is passed to the
- kernel which writes it to its entropy pool.</para></listitem>
+ <listitem><para>In UEFI mode, the
+ <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> or
+ <citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ components load the boot loader random seed from the ESP, hash it with available entropy and the system
+ token, and then update it on disk. A derived seed is passed to the kernel which writes it to its
+ entropy pool.</para></listitem>
<listitem><para>In userspace the <filename>systemd-random-seed.service</filename> service loads the OS
random seed, writes it to the kernel entropy pool, and then updates it on disk with a new value derived
</refsect1>
<refsect1>
- <title>Using systemd-boot in virtual machines.</title>
+ <title>Using <command>systemd-boot</command> in virtual machines</title>
<para>When using qemu with OVMF (UEFI Firmware for virtual machines) the <option>-kernel</option> switch
works not only for linux kernels, but for any EFI binary, including sd-boot and unified linux
- kernels. Example command line for loading sd-boot on x64:</para>
+ kernels. Example command line for loading <command>systemd-boot</command> on x64:</para>
<para>
<command>qemu-system-x86_64 <replaceable>[ ... ]</replaceable>
<term><option>--mtree</option></term>
<term><option>-l</option></term>
- <listitem><para>Generates a BSD <citerefentry
- project='die-net'><refentrytitle>mtree</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <listitem><para>Generates a BSD
+ <citerefentry project='die-net'><refentrytitle>mtree</refentrytitle><manvolnum>8</manvolnum></citerefentry>
compatible file manifest of the specified disk image. This is useful for comparing disk image
contents in detail, including inode information and other metadata. While the generated manifest will
contain detailed inode information, it currently excludes extended attributes, file system
- capabilities, MAC labels, <citerefentry
- project='man-pages'><refentrytitle>chattr</refentrytitle><manvolnum>1</manvolnum></citerefentry> file
- flags, btrfs subvolume information, and various other file metadata. File content information is
- shown via a SHA256 digest. Additional fields might be added in future. Note that inode information
- such as link counts, inode numbers and timestamps is excluded from the output on purpose, as it
- typically complicates reproducibility.</para></listitem>
+ capabilities, MAC labels,
+ <citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ file flags,
+ <citerefentry project='url'><refentrytitle url='https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)'>btrfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ subvolume information, and various other file metadata. File content information is shown via a
+ SHA256 digest. Additional fields might be added in future. Note that inode information such as link
+ counts, inode numbers and timestamps is excluded from the output on purpose, as it typically
+ complicates reproducibility.</para></listitem>
</varlistentry>
<varlistentry>
cycle. This is equivalent to <command>systemd-notify RELOADING=1</command> (but implicitly also sets
a <varname>MONOTONIC_USEC=</varname> field as required for <varname>Type=notify-reload</varname>
services, see
- <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details). For details about the semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<option>0 … y</option> seen from inside of the container is mapped to <option>x + z</option> in the
<option>x … x + y</option> range on the host. Other host users are mapped to
<option>nobody</option> inside the container.</para></listitem>
+
<listitem><para>If <option>idmap</option> is used, any user <option>z</option> in the UID range
<option>0 … y</option> as seen from inside the container is mapped to the same <option>z</option>
- in the same <option>0 … y</option> range on the host. All host users outside of that range are
- mapped to <option>nobody</option> inside the container.</para></listitem>
+ in the same <option>0 … y</option> range on the host. Other host users are mapped to
+ <option>nobody</option> inside the container.</para></listitem>
+
<listitem><para>If <option>rootidmap</option> is used, the user <option>0</option> seen from inside
- of the container is mapped to <option>p</option> on the host. All host users outside of that range
- are mapped to <option>nobody</option> inside the container.</para></listitem>
+ of the container is mapped to <option>p</option> on the host. Other host users are mapped to
+ <option>nobody</option> inside the container.</para></listitem>
</itemizedlist></para>
<para>Whichever ID mapping option is used, the same mapping will be used for users and groups IDs. If
<listitem><para><literal>enter-initrd</literal> — early when the initrd initializes, before activating
system extension images for the initrd. It acts as a barrier between the time where the kernel
initializes and where the initrd starts operating and enables system extension images, i.e. code
- shipped outside of the UKI. (This extension happens when
- <filename>systemd-pcrphase-initrd.service</filename> is started.)</para></listitem>
+ shipped outside of the UKI. (This extension happens when the
+ <citerefentry><refentrytitle>systemd-pcrphase-initrd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ service is started.)</para></listitem>
<listitem><para><literal>leave-initrd</literal> — when the initrd is about to transition into the host
- file system. It acts as barrier between initrd code and host OS code. (This extension happens when
- <filename>systemd-pcrphase-initrd.service</filename> is stopped.)</para></listitem>
+ file system. It acts as barrier between initrd code and host OS code. (This extension happens when the
+ <filename>systemd-pcrphase-initrd.service</filename> service is stopped.)</para></listitem>
<listitem><para><literal>sysinit</literal> — when basic system initialization is complete (which
includes local file systems having been mounted), and the system begins starting regular system
- services. (This extension happens when <filename>systemd-pcrphase-sysinit.service</filename> is
- started.)</para></listitem>
+ services. (This extension happens when the
+ <citerefentry><refentrytitle>systemd-pcrphase-sysinit.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ service is started.)</para></listitem>
<listitem><para><literal>ready</literal> — during later boot-up, after remote file systems have been
activated (i.e. after <filename>remote-fs.target</filename>), but before users are permitted to log in
(i.e. before <filename>systemd-user-sessions.service</filename>). It acts as barrier between the time
where unprivileged regular users are still prohibited to log in and where they are allowed to log in.
- (This extension happens when <filename>systemd-pcrphase.service</filename> is started.)
+ (This extension happens when the <filename>systemd-pcrphase.service</filename> service is started.)
</para></listitem>
<listitem><para><literal>shutdown</literal> — when the system shutdown begins. It acts as barrier
between the time the system is fully up and running and where it is about to shut down. (This extension
- happens when <filename>systemd-pcrphase.service</filename> is stopped.)</para></listitem>
+ happens when the <filename>systemd-pcrphase.service</filename> service is stopped.)</para></listitem>
<listitem><para><literal>final</literal> — at the end of system shutdown. It acts as barrier between
the time the service manager still runs and when it transitions into the final shutdown phase where
- service management is not available anymore. (This extension happens when
- <filename>systemd-pcrphase-sysinit.service</filename> is stopped.)</para></listitem>
+ service management is not available anymore. (This extension happens when the
+ <citerefentry><refentrytitle>systemd-pcrphase-sysinit.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ service is stopped.)</para></listitem>
</orderedlist>
<para>During a regular system lifecycle, PCR 11 is extended with the strings
<listitem><para>This option specifies for which partition types <command>systemd-repart</command>
should defer. All partitions that are deferred using this option are still taken into account when
calculating the sizes and offsets of other partitions, but aren't actually written to the disk image.
- The net effect of this option is that if you run <command>systemd-repart</command> again without
- these options, the missing partitions will be added as if they had not been deferred the first time
+ The net effect of this option is that if you run <command>systemd-repart</command> again without this
+ option, the missing partitions will be added as if they had not been deferred the first time
<command>systemd-repart</command> was executed.</para></listitem>
</varlistentry>
<listitem><para>This option allows configuring the sector size of the image produced by
<command>systemd-repart</command>. It takes a value that is a power of <literal>2</literal> between
<literal>512</literal> and <literal>4096</literal>. This option is useful when building images for
- disks that use a different sector size as the disk on which the image is produced.</para></listitem>.
+ disks that use a different sector size as the disk on which the image is produced.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<term><varname>HibernateMode=</varname></term>
<term><varname>HybridSleepMode=</varname></term>
- <listitem><para>The string to be written to
- <filename>/sys/power/disk</filename> by,
- respectively,
+ <listitem><para>The string to be written to <filename>/sys/power/disk</filename> by, respectively,
<citerefentry><refentrytitle>systemd-suspend.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd-hibernate.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, or
+ <citerefentry><refentrytitle>systemd-hibernate.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ or
<citerefentry><refentrytitle>systemd-hybrid-sleep.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
- More than one value can be specified by separating
- multiple values with whitespace. They will be tried
- in turn, until one is written without error. If
- neither succeeds, the operation will be aborted.
- </para>
-
- <para><citerefentry><refentrytitle>systemd-suspend-then-hibernate.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- uses the value of <varname>SuspendMode=</varname> when suspending and the value of <varname>HibernateMode=</varname> when hibernating.
- </para></listitem>
+ More than one value can be specified by separating multiple values with whitespace. They will be
+ tried in turn, until one is written without error. If none of the writes succeed, the operation will
+ be aborted.</para>
+
+ <para>The allowed set of values is determined by the kernel and is shown in the file itself (use
+ <command>cat /sys/power/disk</command> to display). See <ulink
+ url="https://www.kernel.org/doc/html/latest/admin-guide/pm/sleep-states.html#basic-sysfs-interfaces-for-system-suspend-and-hibernation">the
+ kernel documentation</ulink> for more details.</para>
+
+ <para>
+ <citerefentry><refentrytitle>systemd-suspend-then-hibernate.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ uses the value of <varname>SuspendMode=</varname> when suspending and the value of
+ <varname>HibernateMode=</varname> when hibernating.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>HibernateState=</varname></term>
<term><varname>HybridSleepState=</varname></term>
- <listitem><para>The string to be written to
- <filename>/sys/power/state</filename> by,
- respectively,
+ <listitem><para>The string to be written to <filename>/sys/power/state</filename> by, respectively,
<citerefentry><refentrytitle>systemd-suspend.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd-hibernate.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, or
+ <citerefentry><refentrytitle>systemd-hibernate.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ or
<citerefentry><refentrytitle>systemd-hybrid-sleep.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
- More than one value can be specified by separating
- multiple values with whitespace. They will be tried
- in turn, until one is written without error. If
- neither succeeds, the operation will be aborted.
+ More than one value can be specified by separating multiple values with whitespace. They will be
+ tried in turn, until one is written without error. If none of the writes succeed, the operation will
+ be aborted.
</para>
- <para><citerefentry><refentrytitle>systemd-suspend-then-hibernate.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- uses the value of <varname>SuspendState=</varname> when suspending and the value of <varname>HibernateState=</varname> when hibernating.
- </para></listitem>
+ <para>The allowed set of values is determined by the kernel and is shown in the file itself (use
+ <command>cat /sys/power/state</command> to display). See <ulink
+ url="https://www.kernel.org/doc/html/latest/admin-guide/pm/sleep-states.html#basic-sysfs-interfaces-for-system-suspend-and-hibernation">the
+ kernel documentation</ulink> for more details.</para>
+
+ <para>
+ <citerefentry><refentrytitle>systemd-suspend-then-hibernate.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ uses the value of <varname>SuspendState=</varname> when suspending and the value of
+ <varname>HibernateState=</varname> when hibernating.</para></listitem>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>ProtectClock=</varname></term>
- <listitem><para>Takes a boolean argument. If set, writes to the hardware clock or system clock will be denied.
- It is recommended to turn this on for most services that do not need modify the clock. Defaults to off. Enabling
- this option removes <constant>CAP_SYS_TIME</constant> and <constant>CAP_WAKE_ALARM</constant> from the
- capability bounding set for this unit, installs a system call filter to block calls that can set the
- clock, and <varname>DeviceAllow=char-rtc r</varname> is implied. This ensures <filename>/dev/rtc0</filename>,
- <filename>/dev/rtc1</filename>, etc. are made read-only to the service. See
+ <listitem><para>Takes a boolean argument. If set, writes to the hardware clock or system clock will
+ be denied. Defaults to off. Enabling this option removes <constant>CAP_SYS_TIME</constant> and
+ <constant>CAP_WAKE_ALARM</constant> from the capability bounding set for this unit, installs a system
+ call filter to block calls that can set the clock, and <varname>DeviceAllow=char-rtc r</varname> is
+ implied. Note that the system calls are blocked altogether, the filter does not take into account
+ that some of the calls can be used to read the clock state with some parameter combinations.
+ Effectively, <filename>/dev/rtc0</filename>, <filename>/dev/rtc1</filename>, etc. are made read-only
+ to the service. See
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for the details about <varname>DeviceAllow=</varname>. If this setting is on, but the unit
- doesn't have the <constant>CAP_SYS_ADMIN</constant> capability (e.g. services for which
+ for the details about <varname>DeviceAllow=</varname>. If this setting is on, but the unit doesn't
+ have the <constant>CAP_SYS_ADMIN</constant> capability (e.g. services for which
<varname>User=</varname> is set), <varname>NoNewPrivileges=yes</varname> is implied.</para>
+ <para>It is recommended to turn this on for most services that do not need modify the clock or check
+ its state.</para>
+
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
</varlistentry>
<term><varname>LogRateLimitIntervalSec=</varname></term>
<term><varname>LogRateLimitBurst=</varname></term>
- <listitem><para>Configures the rate limiting that is applied to log messages generated by this
- unit. If, in the time interval defined by <varname>LogRateLimitIntervalSec=</varname>, more messages
- than specified in <varname>LogRateLimitBurst=</varname> are logged by a service, all further messages
+ <listitem><para>Configures the rate limiting that is applied to log messages generated by this unit.
+ If, in the time interval defined by <varname>LogRateLimitIntervalSec=</varname>, more messages than
+ specified in <varname>LogRateLimitBurst=</varname> are logged by a service, all further messages
within the interval are dropped until the interval is over. A message about the number of dropped
messages is generated. The time specification for <varname>LogRateLimitIntervalSec=</varname> may be
- specified in the following units: "s", "min", "h", "ms", "us" (see
+ specified in the following units: "s", "min", "h", "ms", "us". See
<citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
- details). The default settings are set by <varname>RateLimitIntervalSec=</varname> and
+ details. The default settings are set by <varname>RateLimitIntervalSec=</varname> and
<varname>RateLimitBurst=</varname> configured in
- <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Note
- that this only applies to log messages that are processed by the logging subsystem, i.e. by
- <filename>systemd-journald.service</filename>. This means, if you connect a service's stderr directly
- to a file via <varname>StandardOutput=file:…</varname> or a similar setting the rate limiting will
- not be applied to messages written that way (but they will be enforced for messages generated via
- <function>syslog()</function> or similar).</para></listitem>
+ <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ Note that this only applies to log messages that are processed by the logging subsystem, i.e. by
+ <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ This means that if you connect a service's stderr directly to a file via
+ <varname>StandardOutput=file:…</varname> or a similar setting, the rate limiting will not be applied
+ to messages written that way (but it will be enforced for messages generated via
+ <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ and similar functions).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ID_NET_NAME_ONBOARD=<replaceable>prefix</replaceable><constant>d</constant><replaceable>number</replaceable></varname></term>
<listitem><para>This name is set based on the numeric ordering information given by the firmware
- for on-board devices. Different schemes are used depending on the firmware type, as described in the table below.</para>
+ for on-board devices. Different schemes are used depending on the firmware type, as described in
+ the table below.</para>
<table>
- <title>Onboard naming schemes</title>
+ <title>On-board naming schemes</title>
<tgroup cols='2'>
<thead>
<tbody>
<row>
<entry><replaceable>prefix</replaceable><constant>o</constant><replaceable>number</replaceable></entry>
- <entry>PCI onboard index</entry>
+ <entry>PCI on-board index</entry>
</row>
<row>
numbers, which could either result in an incorrect value of the <varname>ID_NET_NAME_SLOT</varname>
property or none at all.</para>
- <para>Some firmware and hypervisor implementations report unreasonably high numbers for the onboard
- index. To prevent the generation of bogus onbard interface names, index numbers greater than 16381
- (2¹⁴-1) were ignored. For s390 PCI devices index values up to 65535 (2¹⁶-1) are valid. To account
- for that, the limit was increased to 65535.</para>
+ <para>Some firmware and hypervisor implementations report unreasonably high numbers for the
+ on-board index. To prevent the generation of bogus onbard interface names, index numbers greater
+ than 16381 (2¹⁴-1) were ignored. For s390 PCI devices index values up to 65535 (2¹⁶-1) are valid.
+ To account for that, the limit was increased to 65535.</para>
<para>The udev rule <varname>NAME=</varname> replaces <literal>:</literal>,
<literal>/</literal>, and <literal>%</literal> with an underscore (<literal>_</literal>), and
<refsect1>
<title>See Also</title>
<para>Environment variables with details on the trigger will be set for triggered units. See the
- <literal>Environment Variables Set on Triggered Units</literal> section in
+ section <literal>Environment Variables Set or Propagated by the Service Manager</literal> in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for more details.</para>
<para>
<option>notify</option>. However, it extends the logic in one way: the
<constant>SIGHUP</constant> UNIX process signal is sent to the service's main process when the
service is asked to reload. (The signal to send can be tweaked via
- <varname>ReloadSignal=</varname>, see below.). When
+ <varname>ReloadSignal=</varname>, see below.) When
initiating the reload process the service is then expected to reply with a notification message
via <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
that contains the <literal>RELOADING=1</literal> field in combination with
<varlistentry>
<term><varname>RestartSteps=</varname></term>
<listitem><para>Configures the number of steps to take to increase the interval
- of auto-restarts from <varname>RestartSec=</varname> to <varname>RestartSecMax=</varname>.
+ of auto-restarts from <varname>RestartSec=</varname> to <varname>RestartMaxDelaySec=</varname>.
Takes a positive integer or 0 to disable it. Defaults to 0.</para>
- <para>This setting is effective only if <varname>RestartSecMax=</varname> is also set.</para></listitem>
+ <para>This setting is effective only if <varname>RestartMaxDelaySec=</varname> is also set.</para></listitem>
</varlistentry>
<varlistentry>
- <term><varname>RestartSecMax=</varname></term>
+ <term><varname>RestartMaxDelaySec=</varname></term>
<listitem><para>Configures the longest time to sleep before restarting a service
as the interval goes up with <varname>RestartSteps=</varname>. Takes a value
in the same format as <varname>RestartSec=</varname>, or <literal>infinity</literal>
limiting configured with <varname>StartLimitIntervalSec=</varname>
and <varname>StartLimitBurst=</varname>, see
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for details. A restarted service enters the failed state only
- after the start limits are reached.</para>
+ for details.</para>
<para>Setting this to <option>on-failure</option> is the
recommended choice for long-running services, in order to
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details.</para>
- <para>This setting also applies to <command>systemd-oomd</command>. Similarly to the kernel OOM
- kills, this setting determines the state of the unit after <command>systemd-oomd</command> kills a
- cgroup associated with it.</para></listitem>
+ <para>This setting also applies to
+ <citerefentry><refentrytitle>systemd-oomd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ Similarly to the kernel OOM kills performed by the kernel, this setting determines the state of the
+ unit after <command>systemd-oomd</command> kills a cgroup associated with it.</para></listitem>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>vmm.notify_socket</varname></term>
<listitem>
- <para>This credential is parsed looking for an <constant>AF_VSOCK</constant> or
- <constant>AF_UNIX</constant> address where to send a <constant>READY=1</constant>
- notification datagram when the system has finished booting. See:
- <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- This is useful for hypervisors/VMMs or other processes on the host
- to receive a notification via VSOCK when a virtual machine has finished booting.
- Note that in case the hypervisor does not support <constant>SOCK_DGRAM</constant>
- over <constant>AF_VSOCK</constant>, <constant>SOCK_SEQPACKET</constant> will be
- tried instead. The credential payload for <constant>AF_VSOCK</constant> should be
- in the form: <literal>vsock:CID:PORT</literal>.</para>
+ <para>Contains a <constant>AF_VSOCK</constant> or <constant>AF_UNIX</constant> address where to
+ send a <constant>READY=1</constant> notification datagram when the system has finished booting. See
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> for
+ more information. Note that in case the hypervisor does not support <constant>SOCK_DGRAM</constant>
+ over <constant>AF_VSOCK</constant>, <constant>SOCK_SEQPACKET</constant> will be tried instead. The
+ credential payload for <constant>AF_VSOCK</constant> should be in the form
+ <literal>vsock:CID:PORT</literal>.</para>
+
+ <para>This feature is useful for hypervisors/VMMs or other processes on the host to receive a
+ notification via VSOCK when a virtual machine has finished booting.</para>
</listitem>
</varlistentry>
<refsect1>
<title>See Also</title>
<para>Environment variables with details on the trigger will be set for triggered units. See the
- <literal>Environment Variables Set on Triggered Units</literal> section in
+ <literal>Environment Variables Set or Propagated by the Service Manager</literal> section in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for more details.</para>
<para>
<term><varname>OnFailure=</varname></term>
<listitem><para>A space-separated list of one or more units that are activated when this unit enters
- the <literal>failed</literal> state. A service unit using <varname>Restart=</varname> enters the
- failed state only after the start limits are reached.</para></listitem>
+ the <literal>failed</literal> state.</para></listitem>
</varlistentry>
<varlistentry>
<constant>subvolume</constant>. For details about the resource types, see above. This option is
mandatory.</para>
- <para>Note that only some combinations of source and target resource types are supported, see
+ <para>Note that only certain combinations of source and target resource types are supported, see
above.</para></listitem>
</varlistentry>
</variablelist>
<para>For example:<programlisting>
# Files created and modified, and directories accessed more than
# an hour ago in "/tmp/foo/bar", are subject to time-based cleanup.
-d /tmp/foo/bar - - - - bmA:1h -</programlisting></para>
+d /tmp/foo/bar - - - bmA:1h -</programlisting></para>
<para>Note that while the aging algorithm is run an exclusive BSD file lock (see <citerefentry
project='man-pages'><refentrytitle>flock</refentrytitle><manvolnum>2</manvolnum></citerefentry>) is
<term><option>--measure</option></term>
<term><option>--no-measure</option></term>
- <listitem><para>Enable or disable a call to <command>systemd-measure</command> to print
- pre-calculated PCR values. Defaults to false.</para></listitem>
+ <listitem><para>Enable or disable a call to
+ <citerefentry><refentrytitle>systemd-measure</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ to print pre-calculated PCR values. Defaults to false.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>SigningEngine=<replaceable>ENGINE</replaceable></varname></term>
<term><option>--signing-engine=<replaceable>ENGINE</replaceable></option></term>
- <listitem><para>An "engine" to for signing of the resulting binary. This option is currently passed
+ <listitem><para>An "engine" for signing of the resulting binary. This option is currently passed
verbatim to the <option>--engine=</option> option of
<citerefentry project='archlinux'><refentrytitle>sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
</para></listitem>
if want_tests != 'false'
test('hwdb-test',
hwdb_test_sh,
- suite : 'dist-check',
+ suite : 'dist',
args : [systemd_hwdb.full_path()],
timeout : 90)
endif
if want_tests != 'false'
test('udev-rules-check',
udevadm,
- suite : 'dist-check',
+ suite : 'dist',
args : ['verify', '--resolve-names=never', all_rules])
endif
fuzz_in = tuple[1]
test('@0@_@1@'.format(name, fuzz_in),
exe,
- suite : 'fuzzers',
+ suite : 'fuzz',
args : [fuzz_dir != '' ? project_source_root / fuzz_dir / name / fuzz_in
: fuzz_generated_in_dir / '@0@_@1@'.format(name, fuzz_in)])
endforeach
if get_option('mode') == 'developer' and want_tests != 'false' and jekyll.found()
test('github-pages',
jekyll,
- suite : 'dist-check',
+ suite : 'dist',
args : ['build',
'--source', project_source_root / 'docs',
'--destination', project_build_root / '_site'])
if want_tests != 'false'
test('check-help-' + name,
check_help,
- suite : 'dist-check',
+ suite : 'dist',
args : exec.full_path(),
depends: exec)
test('check-version-' + name,
check_version,
- suite : 'dist-check',
+ suite : 'dist',
args : [exec.full_path(),
meson.project_version()],
depends: exec)
enable systemd-networkd.service
enable systemd-networkd-wait-online.service
-# We install dnf in some images but it's only going to be used rarely to install extra packages so let's not
-# have dnf create its cache.
-disable dnf-makecache.timer
-disable dnf-makecache.service
+# We install dnf in some images but it's only going to be used rarely,
+# so let's not have dnf create its cache.
+disable dnf-makecache.*
# We have journald to receive audit data so let's make sure we're not running auditd as well
disable auditd.service
n++;
}
- printf("%s%s%s\n",
+ printf("%s%s %s\n",
prefix,
special_glyph(has_more ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT),
*l);
SD_BUS_PROPERTY("NotifyAccess", "s", property_get_notify_access, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestartSteps", "u", bus_property_get_unsigned, offsetof(Service, restart_steps), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RestartUSecMax", "t", bus_property_get_usec, offsetof(Service, restart_usec_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RestartMaxDelayUSec", "t", bus_property_get_usec, offsetof(Service, restart_max_delay_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestartUSecNext", "t", property_get_restart_usec_next, 0, 0),
SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
if (streq(name, "RestartSteps"))
return bus_set_transient_unsigned(u, name, &s->restart_steps, message, flags, error);
- if (streq(name, "RestartUSecMax"))
- return bus_set_transient_usec(u, name, &s->restart_usec_max, message, flags, error);
+ if (streq(name, "RestartMaxDelayUSec"))
+ return bus_set_transient_usec(u, name, &s->restart_max_delay_usec, message, flags, error);
if (streq(name, "TimeoutStartUSec")) {
r = bus_set_transient_usec(u, name, &s->timeout_start_usec, message, flags, error);
#include "sd-messages.h"
#include "alloc-util.h"
-#include "bus-error.h"
+#include "bus-common-errors.h"
#include "dbus-device.h"
#include "dbus-unit.h"
#include "device-private.h"
r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, NULL, &error, NULL);
if (r < 0)
- log_unit_warning_errno(u, r, "Failed to enqueue SYSTEMD_WANTS= job, ignoring: %s", bus_error_message(&error, r));
+ log_unit_full_errno(u, sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to enqueue %s job, ignoring: %s", property, bus_error_message(&error, r));
}
return strv_free_and_replace(d->wants_property, added);
Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command)
Service.RestartSec, config_parse_sec, 0, offsetof(Service, restart_usec)
Service.RestartSteps, config_parse_unsigned, 0, offsetof(Service, restart_steps)
-Service.RestartSecMax, config_parse_sec, 0, offsetof(Service, restart_usec_max)
+Service.RestartMaxDelaySec, config_parse_sec, 0, offsetof(Service, restart_max_delay_usec)
Service.TimeoutSec, config_parse_service_timeout, 0, 0
Service.TimeoutStartSec, config_parse_service_timeout, 0, 0
Service.TimeoutStopSec, config_parse_sec_fix_0, 0, offsetof(Service, timeout_stop_usec)
s->timeout_abort_usec = u->manager->default_timeout_abort_usec;
s->timeout_abort_set = u->manager->default_timeout_abort_set;
s->restart_usec = u->manager->default_restart_usec;
- s->restart_usec_max = USEC_INFINITY;
+ s->restart_max_delay_usec = USEC_INFINITY;
s->runtime_max_usec = USEC_INFINITY;
s->type = _SERVICE_TYPE_INVALID;
s->socket_fd = -EBADF;
if (n_restarts_next <= 1 ||
s->restart_steps == 0 ||
- s->restart_usec_max == USEC_INFINITY ||
- s->restart_usec >= s->restart_usec_max)
+ s->restart_max_delay_usec == USEC_INFINITY ||
+ s->restart_usec >= s->restart_max_delay_usec)
value = s->restart_usec;
else if (n_restarts_next > s->restart_steps)
- value = s->restart_usec_max;
+ value = s->restart_max_delay_usec;
else {
/* Enforced in service_verify() and above */
- assert(s->restart_usec_max > s->restart_usec);
+ assert(s->restart_max_delay_usec > s->restart_usec);
/* ((restart_usec_max - restart_usec)^(1/restart_steps))^(n_restart_next - 1) */
value = usec_add(s->restart_usec,
- (usec_t) powl(s->restart_usec_max - s->restart_usec,
+ (usec_t) powl(s->restart_max_delay_usec - s->restart_usec,
(long double) (n_restarts_next - 1) / s->restart_steps));
}
if (s->exit_type == SERVICE_EXIT_CGROUP && cg_unified() < CGROUP_UNIFIED_SYSTEMD)
log_unit_warning(UNIT(s), "Service has ExitType=cgroup set, but we are running with legacy cgroups v1, which might not work correctly. Continuing.");
- if (s->restart_usec_max == USEC_INFINITY && s->restart_steps > 0)
- log_unit_warning(UNIT(s), "Service has RestartSteps= but no RestartSecMax= setting. Ignoring.");
+ if (s->restart_max_delay_usec == USEC_INFINITY && s->restart_steps > 0)
+ log_unit_warning(UNIT(s), "Service has RestartSteps= but no RestartMaxDelaySec= setting. Ignoring.");
- if (s->restart_usec_max != USEC_INFINITY && s->restart_steps == 0)
- log_unit_warning(UNIT(s), "Service has RestartSecMax= but no RestartSteps= setting. Ignoring.");
+ if (s->restart_max_delay_usec != USEC_INFINITY && s->restart_steps == 0)
+ log_unit_warning(UNIT(s), "Service has RestartMaxDelaySec= but no RestartSteps= setting. Ignoring.");
- if (s->restart_usec_max < s->restart_usec) {
- log_unit_warning(UNIT(s), "RestartSecMax= has a value smaller than RestartSec=, resetting RestartSec= to RestartSecMax=.");
- s->restart_usec = s->restart_usec_max;
+ if (s->restart_max_delay_usec < s->restart_usec) {
+ log_unit_warning(UNIT(s), "RestartMaxDelaySec= has a value smaller than RestartSec=, resetting RestartSec= to RestartMaxDelaySec=.");
+ s->restart_usec = s->restart_max_delay_usec;
}
return 0;
fprintf(f,
"%sRestartSec: %s\n"
"%sRestartSteps: %u\n"
- "%sRestartSecMax: %s\n"
+ "%sRestartMaxDelaySec: %s\n"
"%sTimeoutStartSec: %s\n"
"%sTimeoutStopSec: %s\n"
"%sTimeoutStartFailureMode: %s\n"
"%sTimeoutStopFailureMode: %s\n",
prefix, FORMAT_TIMESPAN(s->restart_usec, USEC_PER_SEC),
prefix, s->restart_steps,
- prefix, FORMAT_TIMESPAN(s->restart_usec_max, USEC_PER_SEC),
+ prefix, FORMAT_TIMESPAN(s->restart_max_delay_usec, USEC_PER_SEC),
prefix, FORMAT_TIMESPAN(s->timeout_start_usec, USEC_PER_SEC),
prefix, FORMAT_TIMESPAN(s->timeout_stop_usec, USEC_PER_SEC),
prefix, service_timeout_failure_mode_to_string(s->timeout_start_failure_mode),
usec_t restart_usec;
unsigned restart_steps;
- usec_t restart_usec_max;
+ usec_t restart_max_delay_usec;
usec_t timeout_start_usec;
usec_t timeout_stop_usec;
usec_t timeout_abort_usec;
assert_return(bus, -EINVAL);
assert_return(bus = bus_resolve(bus), -ENOPKG);
assert_return(description, -EINVAL);
- assert_return(bus->description, -ENXIO);
- assert_return(!bus_origin_changed(bus), -ECHILD);
- if (bus->description)
- *description = bus->description;
- else
- *description = runtime_scope_to_string(bus->runtime_scope);
+ const char *d = bus->description;
+ if (!d)
+ d = runtime_scope_to_string(bus->runtime_scope);
+ if (!d)
+ return -ENXIO;
+ *description = d;
return 0;
}
_public_ int sd_event_source_get_description(sd_event_source *s, const char **description) {
assert_return(s, -EINVAL);
assert_return(description, -EINVAL);
- assert_return(!event_origin_changed(s->event), -ECHILD);
if (!s->description)
return -ENXIO;
r = chase(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].where);
+ return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), mount_table[k].where);
/* Skip this entry if it is not a remount. */
if (mount_table[k].what) {
* for those. */
r = chase(mount_table[k].what, dest, CHASE_PREFIX_ROOT, &prefixed, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].what);
+ return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), mount_table[k].what);
}
r = mount_verbose_full(
}
static int network_iface_pair_parse(const char* iftype, char ***l, const char *p, const char* ifprefix) {
- _cleanup_free_ char *a = NULL, *b = NULL;
int r;
- r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
- if (r < 0)
- return log_error_errno(r, "Failed to extract first word in %s parameter: %m", iftype);
- if (r == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Short read while reading %s parameter: %m", iftype);
- if (!ifname_valid(a))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s, interface name not valid: %s", iftype, a);
-
- if (isempty(p)) {
- if (ifprefix)
- b = strjoin(ifprefix, a);
- else
- b = strdup(a);
- } else
- b = strdup(p);
- if (!b)
- return log_oom();
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
+ const char *interface;
- if (!ifname_valid(b))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s, interface name not valid: %s", iftype, b);
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse interface name: %m");
+ if (r == 0)
+ break;
- r = strv_push_pair(l, a, b);
- if (r < 0)
- return log_oom();
+ interface = word;
+ r = extract_first_word(&interface, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return log_error_errno(r, "Failed to extract first word in %s parameter: %m", iftype);
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Short read while reading %s parameter: %m", iftype);
+ if (!ifname_valid(a))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s, interface name not valid: %s", iftype, a);
+
+ if (isempty(interface)) {
+ if (ifprefix)
+ b = strjoin(ifprefix, a);
+ else
+ b = strdup(a);
+ } else
+ b = strdup(interface);
+ if (!b)
+ return log_oom();
+
+ if (!ifname_valid(b))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s, interface name not valid: %s", iftype, b);
+
+ r = strv_consume_pair(l, TAKE_PTR(a), TAKE_PTR(b));
+ if (r < 0)
+ return log_oom();
+ }
- a = b = NULL;
return 0;
}
}
static int oci_terminal(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- Settings *s = userdata;
+ Settings *s = ASSERT_PTR(userdata);
/* If not specified, or set to true, we'll default to either an interactive or a read-only
* console. If specified as false, we'll forcibly move to "pipe" mode though. */
}
static int oci_console_size(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+ Settings *s = ASSERT_PTR(userdata);
static const JsonDispatch table[] = {
{ "height", JSON_VARIANT_UNSIGNED, oci_console_dimension, offsetof(Settings, console_height), JSON_MANDATORY },
{}
};
- return json_dispatch(v, table, oci_unexpected, flags, userdata);
+ return json_dispatch(v, table, oci_unexpected, flags, s);
}
static int oci_absolute_path(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
static int oci_rlimit_type(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
const char *z;
- int t, *type = userdata;
-
- assert_se(type);
+ int *type = ASSERT_PTR(userdata);
+ int t;
z = startswith(json_variant_string(v), "RLIMIT_");
if (!z)
}
static int oci_rlimit_value(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- rlim_t z, *value = ASSERT_PTR(userdata);
+ rlim_t *value = ASSERT_PTR(userdata);
+ rlim_t z;
if (json_variant_is_negative(v))
z = RLIM_INFINITY;
}
static int oci_rlimits(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
-
Settings *s = ASSERT_PTR(userdata);
JsonVariant *e;
int r;
}
static int oci_capability_array(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- uint64_t *mask = userdata, m = 0;
+ uint64_t *mask = ASSERT_PTR(userdata);
+ uint64_t m = 0;
JsonVariant *e;
JSON_VARIANT_ARRAY_FOREACH(e, v) {
}
static int oci_uid_gid(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- uid_t *uid = userdata, u;
+ uid_t *uid = ASSERT_PTR(userdata);
+ uid_t u;
uint64_t k;
- assert(uid);
assert_cc(sizeof(uid_t) == sizeof(gid_t));
k = json_variant_unsigned(v);
}
static int oci_user(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
static const JsonDispatch table[] = {
{ "uid", JSON_VARIANT_UNSIGNED, oci_uid_gid, offsetof(Settings, uid), JSON_MANDATORY },
{ "gid", JSON_VARIANT_UNSIGNED, oci_uid_gid, offsetof(Settings, gid), JSON_MANDATORY },
}
static int oci_root(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- Settings *s = userdata;
+ Settings *s = ASSERT_PTR(userdata);
int r;
static const JsonDispatch table[] = {
char **options;
} oci_mount_data;
-static void cleanup_oci_mount_data(oci_mount_data *data) {
+static void oci_mount_data_done(oci_mount_data *data) {
free(data->destination);
free(data->source);
- strv_free(data->options);
free(data->type);
+ strv_free(data->options);
}
+DEFINE_TRIVIAL_DESTRUCTOR(oci_mount_data_donep, oci_mount_data, oci_mount_data_done);
+
static int oci_mounts(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
Settings *s = ASSERT_PTR(userdata);
JsonVariant *e;
};
_cleanup_free_ char *joined_options = NULL;
+ _cleanup_(oci_mount_data_donep) oci_mount_data data = {};
CustomMount *m;
- _cleanup_(cleanup_oci_mount_data) oci_mount_data data = {};
r = json_dispatch(e, table, oci_unexpected, flags, &data);
if (r < 0)
return 0;
}
+struct namespace_data {
+ unsigned long type;
+ char *path;
+};
+
+static void namespace_data_done(struct namespace_data *p) {
+ assert(p);
+
+ free(p->path);
+}
+
+DEFINE_TRIVIAL_DESTRUCTOR(namespace_data_donep, struct namespace_data, namespace_data_done);
+
static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- Settings *s = userdata;
+ Settings *s = ASSERT_PTR(userdata);
unsigned long n = 0;
JsonVariant *e;
int r;
- assert_se(s);
-
JSON_VARIANT_ARRAY_FOREACH(e, v) {
-
- struct namespace_data {
- unsigned long type;
- char *path;
- } data = {};
+ _cleanup_(namespace_data_donep) struct namespace_data data = {};
static const JsonDispatch table[] = {
{ "type", JSON_VARIANT_STRING, oci_namespace_type, offsetof(struct namespace_data, type), JSON_MANDATORY },
};
r = json_dispatch(e, table, oci_unexpected, flags, &data);
- if (r < 0) {
- free(data.path);
+ if (r < 0)
return r;
- }
if (data.path) {
- if (data.type != CLONE_NEWNET) {
- free(data.path);
+ if (data.type != CLONE_NEWNET)
return json_log(e, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
"Specifying namespace path for non-network namespace is not supported.");
- }
- if (s->network_namespace_path) {
- free(data.path);
+ if (s->network_namespace_path)
return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
"Network namespace path specified more than once, refusing.");
- }
- free(s->network_namespace_path);
- s->network_namespace_path = data.path;
+ free_and_replace(s->network_namespace_path, data.path);
}
if (FLAGS_SET(n, data.type))
}
static int oci_uid_gid_range(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- uid_t *uid = userdata, u;
+ uid_t *uid = ASSERT_PTR(userdata);
+ uid_t u;
uint64_t k;
- assert(uid);
assert_cc(sizeof(uid_t) == sizeof(gid_t));
/* This is very much like oci_uid_gid(), except the checks are a bit different, as this is a UID range rather
}
static int oci_device_major(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- unsigned *u = userdata;
+ unsigned *u = ASSERT_PTR(userdata);
uint64_t k;
- assert_se(u);
-
k = json_variant_unsigned(v);
if (!DEVICE_MAJOR_VALID(k))
return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
}
static int oci_device_minor(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- unsigned *u = userdata;
+ unsigned *u = ASSERT_PTR(userdata);
uint64_t k;
- assert_se(u);
-
k = json_variant_unsigned(v);
if (!DEVICE_MINOR_VALID(k))
return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
}
static int oci_device_file_mode(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- mode_t *mode = userdata, m;
+ mode_t *mode = ASSERT_PTR(userdata);
+ mode_t m;
uint64_t k;
- assert(mode);
-
k = json_variant_unsigned(v);
m = (mode_t) k;
}
static int oci_cgroup_device_type(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- mode_t *mode = userdata;
+ mode_t *mode = ASSERT_PTR(userdata);
const char *n;
assert_se(n = json_variant_string(v));
};
static int oci_cgroup_device_access(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- struct device_data *d = userdata;
+ struct device_data *d = ASSERT_PTR(userdata);
bool r = false, w = false, m = false;
const char *s;
size_t i;
}
static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
-
_cleanup_free_ struct device_data *list = NULL;
Settings *s = ASSERT_PTR(userdata);
size_t n_list = 0, i;
{}
};
- Settings *s = userdata;
+ Settings *s = ASSERT_PTR(userdata);
int r;
r = json_dispatch(v, table, oci_unexpected, flags, &data);
.period = UINT64_MAX,
};
- Settings *s = userdata;
+ Settings *s = ASSERT_PTR(userdata);
int r;
r = json_dispatch(v, table, oci_unexpected, flags, &data);
size_t n_arguments;
};
-static void syscall_rule_free(struct syscall_rule *rule) {
+static void syscall_rule_done(struct syscall_rule *rule) {
assert(rule);
strv_free(rule->names);
free(rule->arguments);
};
+DEFINE_TRIVIAL_DESTRUCTOR(syscall_rule_donep, struct syscall_rule, syscall_rule_done);
+
static int oci_seccomp_action(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
uint32_t *action = ASSERT_PTR(userdata);
int r;
{ "args", JSON_VARIANT_ARRAY, oci_seccomp_args, 0, 0 },
{}
};
- struct syscall_rule rule = {
+ _cleanup_(syscall_rule_donep) struct syscall_rule rule = {
.action = UINT32_MAX,
};
r = json_dispatch(e, table, oci_unexpected, flags, &rule);
if (r < 0)
- goto fail_rule;
+ return r;
if (strv_isempty(rule.names)) {
json_log(e, flags, 0, "System call name list is empty.");
- r = -EINVAL;
- goto fail_rule;
+ return -EINVAL;
}
STRV_FOREACH(i, rule.names) {
r = seccomp_rule_add_array(sc, rule.action, nr, rule.n_arguments, rule.arguments);
if (r < 0)
- goto fail_rule;
+ return r;
}
-
- syscall_rule_free(&rule);
- continue;
-
- fail_rule:
- syscall_rule_free(&rule);
- return r;
}
return 0;
}
static int oci_hook_timeout(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- usec_t *u = userdata;
+ usec_t *u = ASSERT_PTR(userdata);
uint64_t k;
k = json_variant_unsigned(v);
goto try_again;
if (error_shall_fallback(error_id))
goto fail;
+ if (streq(error_id, "io.systemd.Resolve.NoSuchResourceRecord"))
+ goto no_data;
goto not_found;
}
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
+no_data:
+ *h_errnop = NO_DATA;
+ return NSS_STATUS_NOTFOUND;
+
try_again:
UNPROTECT_ERRNO;
*errnop = -r;
goto try_again;
if (error_shall_fallback(error_id))
goto fail;
+ if (streq(error_id, "io.systemd.Resolve.NoSuchResourceRecord"))
+ goto no_data;
goto not_found;
}
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
+no_data:
+ *h_errnop = NO_DATA;
+ return NSS_STATUS_NOTFOUND;
+
try_again:
UNPROTECT_ERRNO;
*errnop = -r;
r = safe_atollu(swap, &s);
if (r < 0 || s == 0)
- log_warning("Swap is currently not detected; memory pressure usage will be degraded");
+ log_warning("No swap; memory pressure usage will be degraded");
if (!is_pressure_supported())
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Pressure Stall Information (PSI) is not supported");
.bypass = dns_packet_ref(bypass),
.current_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID,
.clamp_feature_level_servfail = _DNS_SERVER_FEATURE_LEVEL_INVALID,
- .clamp_feature_level_nxdomain = _DNS_SERVER_FEATURE_LEVEL_INVALID,
.id = pick_new_id(s->manager),
};
/* If we changed the server invalidate the feature level clamping, as the new server might have completely
* different properties. */
- if (server != t->server) {
+ if (server != t->server)
t->clamp_feature_level_servfail = _DNS_SERVER_FEATURE_LEVEL_INVALID;
- t->clamp_feature_level_nxdomain = _DNS_SERVER_FEATURE_LEVEL_INVALID;
- }
t->current_feature_level = dns_server_possible_feature_level(server);
if (t->clamp_feature_level_servfail != _DNS_SERVER_FEATURE_LEVEL_INVALID &&
t->current_feature_level > t->clamp_feature_level_servfail)
t->current_feature_level = t->clamp_feature_level_servfail;
- if (t->clamp_feature_level_nxdomain != _DNS_SERVER_FEATURE_LEVEL_INVALID &&
- t->current_feature_level > t->clamp_feature_level_nxdomain)
- t->current_feature_level = t->clamp_feature_level_nxdomain;
log_debug("Using feature level %s for transaction %u.", dns_server_feature_level_to_string(t->current_feature_level), t->id);
return;
}
- if (t->scope->protocol == DNS_PROTOCOL_DNS &&
- !t->bypass &&
- DNS_PACKET_RCODE(p) == DNS_RCODE_NXDOMAIN &&
- p->opt && !DNS_PACKET_DO(p) &&
- DNS_SERVER_FEATURE_LEVEL_IS_EDNS0(t->current_feature_level) &&
- DNS_SERVER_FEATURE_LEVEL_IS_UDP(t->current_feature_level) &&
- t->scope->dnssec_mode != DNSSEC_YES) {
-
- /* Some captive portals are special in that the Aruba/Datavalet hardware will miss
- * replacing the packets with the local server IP to point to the authenticated side
- * of the network if EDNS0 is enabled. Instead they return NXDOMAIN, with DO bit set
- * to zero... nothing to see here, yet respond with the captive portal IP, when using
- * the more simple UDP level.
- *
- * Common portal names that fail like so are:
- * secure.datavalet.io
- * securelogin.arubanetworks.com
- * securelogin.networks.mycompany.com
- *
- * Thus retry NXDOMAIN RCODES with a lower feature level.
- *
- * Do not lower the server's tracked feature level, as the captive portal should not
- * be lying for the wider internet (e.g. _other_ queries were observed fine with
- * EDNS0 on these networks, post auth), i.e. let's just lower the level transaction's
- * feature level.
- *
- * This is reported as https://github.com/dns-violations/dns-violations/blob/master/2018/DVE-2018-0001.md
- */
-
- t->clamp_feature_level_nxdomain = DNS_SERVER_FEATURE_LEVEL_UDP;
-
- log_debug("Server returned error %s in EDNS0 mode, retrying transaction with reduced feature level %s (DVE-2018-0001 mitigation)",
- FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)),
- dns_server_feature_level_to_string(t->clamp_feature_level_nxdomain));
-
- dns_transaction_retry(t, false /* use the same server */);
- return;
- }
-
if (t->server) {
/* Report that we successfully received a valid packet with a good rcode after we initially got a bad
* rcode and subsequently downgraded the protocol */
/* The features of the DNS server at time of transaction start */
DnsServerFeatureLevel current_feature_level;
- /* If we got SERVFAIL back, we retry the lookup, using a lower feature level than we used
- * before. Similar, if we get NXDOMAIN in pure EDNS0 mode, we check in EDNS0-less mode before giving
- * up (as mitigation for DVE-2018-0001). */
+ /* If we got SERVFAIL back, we retry the lookup, using a lower feature level than we used before. */
DnsServerFeatureLevel clamp_feature_level_servfail;
- DnsServerFeatureLevel clamp_feature_level_nxdomain;
uint16_t id;
return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, "RestartSec",
+ "RestartMaxDelaySec",
"TimeoutStartSec",
"TimeoutStopSec",
"TimeoutAbortSec",
return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
}
- if (streq(field, "FileDescriptorStoreMax"))
+ if (STR_IN_SET(field, "FileDescriptorStoreMax",
+ "RestartSteps"))
return bus_append_safe_atou(m, field, eq);
if (STR_IN_SET(field, "ExecCondition",
test_append_files() {
local workspace="${1:?}"
+ local container="$workspace/testsuite-13-container-template"
- # On openSUSE the static linked version of busybox is named "busybox-static".
- busybox="$(type -P busybox-static || type -P busybox)"
- inst_simple "$busybox" "$(dirname "$busybox")/busybox"
+ # Create a dummy container "template" with a minimal toolset, which we can
+ # then use as a base for our nspawn/machinectl tests
+ initdir="$container" setup_basic_dirs
+ initdir="$container" image_install \
+ bash \
+ cat \
+ hostname \
+ grep \
+ ip \
+ ls \
+ md5sum \
+ mountpoint \
+ nc \
+ ps \
+ seq \
+ sleep \
+ stat \
+ touch \
+ true
- if command -v selinuxenabled >/dev/null && selinuxenabled; then
- image_install chcon selinuxenabled
- cp -ar /etc/selinux "$workspace/etc/selinux"
- sed -i "s/^SELINUX=.*$/SELINUX=permissive/" "$workspace/etc/selinux/config"
- fi
-
- "$TEST_BASE_DIR/create-busybox-container" "$workspace/testsuite-13.nc-container"
- initdir="$workspace/testsuite-13.nc-container" image_install nc ip md5sum
+ cp /etc/os-release "$container/usr/lib/os-release"
+ cat >"$container/sbin/init" <<EOF
+#!/bin/bash
+echo "Hello from dummy init, beautiful day, innit?"
+ip link
+EOF
+ chmod +x "$container/sbin/init"
}
do_test "$@"
test_append_files() {
local workspace="${1:?}"
- printf "556f48e837bc4424a710fa2e2c9d3e3c\ne3d\n" >"$workspace/etc/machine-id"
+ if ! get_bool "${TEST_PREFER_NSPAWN:-}" && ! get_bool "${TEST_NO_QEMU:-}"; then
+ # Check if we can correctly boot with an invalid machine ID only if we run
+ # the QEMU test, as nspawn refuses the invalid machine ID with -EUCLEAN
+ printf "556f48e837bc4424a710fa2e2c9d3e3c\ne3d\n" >"$workspace/etc/machine-id"
+ fi
}
do_test "$@"
+++ /dev/null
-#!/usr/bin/env bash
-# SPDX-License-Identifier: LGPL-2.1-or-later
-
-set -eu
-set -o pipefail
-
-root="${1:?Usage: $0 container-root}"
-mkdir -p "$root"
-mkdir -p "$root/usr/bin"
-
-# On openSUSE the static linked version of busybox is named "busybox-static".
-busybox="$(type -P busybox-static || type -P busybox)"
-cp "$busybox" "$root/usr/bin/busybox"
-
-mkdir "$root/var"
-mkdir -p "$root/usr/lib"
-touch "$root/usr/lib/os-release"
-
-ln -s busybox "$root/usr/bin/cat"
-ln -s busybox "$root/usr/bin/hostname"
-ln -s busybox "$root/usr/bin/ip"
-ln -s busybox "$root/usr/bin/md5sum"
-ln -s busybox "$root/usr/bin/mountpoint"
-ln -s busybox "$root/usr/bin/ps"
-ln -s busybox "$root/usr/bin/seq"
-ln -s busybox "$root/usr/bin/sh"
-ln -s busybox "$root/usr/bin/sleep"
-ln -s busybox "$root/usr/bin/stat"
-ln -s busybox "$root/usr/bin/test"
-ln -s busybox "$root/usr/bin/touch"
-ln -s busybox "$root/usr/bin/tr"
-ln -s busybox "$root/usr/bin/true"
-ln -s busybox "$root/usr/bin/usleep"
-
-# Mock the bare minimum of getent to make systemd-nspawn --user= "work"
-cat >"$root/usr/bin/getent" <<\EOF
-#!/bin/sh
-
-if [[ $# - eq 0 ]]; then
- :
-elif [[ $1 == passwd ]]; then
- echo "testuser:x:1000:1000:testuser:/:/bin/sh"
-elif [[ $1 == initgroups ]]; then
- echo "testuser"
-fi
-EOF
-chmod +x "$root/usr/bin/getent"
-
-mkdir -p "$root/usr/sbin"
-cat >"$root/usr/sbin/init" <<\EOF
-#!/bin/sh
-
-printf "ps aufx:\n"
-ps aufx
-
-printf "/proc/1/cmdline:\n"
-printf "%s\n\n" "$(tr '\0' ' ' </proc/1/cmdline)"
-
-printf "/proc/1/environ:\n"
-printf "%s\n\n" "$(tr '\0' '\n' </proc/1/environ)"
-
-printf "/proc/1/mountinfo:\n"
-cat /proc/self/mountinfo
-printf "\n"
-
-printf "/proc/1/cgroup:\n"
-printf "%s\n\n" "$(cat /proc/1/cgroup)"
-
-printf "/proc/1/uid_map:\n"
-printf "%s\n\n" "$(cat /proc/1/uid_map)"
-
-printf "/proc/1/setgroups:\n"
-printf "%s\n\n" "$(cat /proc/1/setgroups)"
-
-printf "/proc/1/gid_map:\n"
-printf "%s\n\n" "$(cat /proc/1/gid_map)"
-
-printf "ip link:\n"
-ip link
-EOF
-chmod +x "$root/usr/sbin/init"
-
-ln -srf "$root/usr/bin" "$root/bin"
-ln -srf "$root/usr/sbin" "$root/sbin"
-ln -srf "$root/usr/lib" "$root/lib"
install_dir : testdata_dir)
endif
- install_data('create-busybox-container',
- install_mode : 'rwxr-xr-x',
- install_dir : testdata_dir)
-
# The unit tests implemented as shell scripts expect to find testdata/
# in the directory where they are stored.
meson.add_install_script(meson_make_symlink,
if want_tests != 'false'
test('rule-syntax-check',
rule_syntax_check_py,
- suite : 'dist-check',
+ suite : 'dist',
args : all_rules)
endif
if want_tests != 'false'
test('test-rpm-macros',
test_rpm_macros,
- suite : 'dist-check',
+ suite : 'dist',
args : [project_build_root])
endif
else
test(name,
udev_dmi_memory_id_test,
- suite : 'dist-check',
+ suite : 'dist',
args : [udev_prog_paths['dmi_memory_id'].full_path(),
source,
source + '.txt'],
script
sed
seq
+ setfacl
setfattr
setfont
setpriv
kernel_params+=("rd.hostonly=0")
fi
+ # Debian/Ubuntu's initramfs tries to check if it can resume from hibernation
+ # and wastes a minute or so probing disks, skip that as it's not useful here
kernel_params+=(
"root=LABEL=systemd_boot"
"rw"
"SYSTEMD_UNIT_PATH=/usr/lib/systemd/tests/testdata/testsuite-$1.units:/usr/lib/systemd/tests/testdata/units:"
"systemd.unit=testsuite.target"
"systemd.wants=testsuite-$1.service"
+ "noresume"
)
if ! get_bool "$INTERACTIVE_DEBUG"; then
# Let's make one to prevent unexpected "<bin> not found" issues in the future
export PATH="/sbin:/bin:/usr/sbin:/usr/bin"
-mount -t proc proc /proc
-mount -t sysfs sysfs /sys
+mountpoint -q /proc || mount -t proc proc /proc
+mountpoint -q /sys || mount -t sysfs sysfs /sys
mount -o remount,rw /
DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT ASAN_RT_PATH=$ASAN_RT_PATH"
install_modules() {
dinfo "Install modules"
- instmods dummy vfat veth
+ instmods bridge dummy ipvlan macvlan vfat veth
instmods loop =block
instmods nls_ascii =nls
instmods overlay =overlayfs
# Same as above, but we need to wrap certain libraries unconditionally
#
- # chown, getent, login, su, useradd, userdel - dlopen() (not only) systemd's PAM modules
+ # chown, getent, login, setfacl, su, useradd, userdel
+ # - dlopen() (not only) systemd's PAM modules
# ls, mkfs.*, mksquashfs, mkswap, setpriv, stat
- # - pull in nss_systemd with certain options (like ls -l) when
- # nsswitch.conf uses [SUCCESS=merge] (like on Arch Linux)
+ # - pull in nss_systemd with certain options (like ls -l) when
+ # nsswitch.conf uses [SUCCESS=merge] (like on Arch Linux)
# delv, dig - pull in nss_resolve if `resolve` is in nsswitch.conf
# tar - called by machinectl in TEST-25
- bin_rx='/(chown|delv|dig|getent|login|ls|mkfs\.[a-z0-9]+|mksquashfs|mkswap|setpriv|stat|su|tar|useradd|userdel)$'
+ bin_rx='/(chown|delv|dig|getent|login|ls|mkfs\.[a-z0-9]+|mksquashfs|mkswap|setfacl|setpriv|stat|su|tar|useradd|userdel)$'
if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ $bin_rx ]]; then
wrap_binary=1
fi
set -eux
set -o pipefail
-export PAGER=
+# shellcheck source=test/units/util.sh
+. "$(dirname "$0")"/util.sh
-CREATE_BB_CONTAINER="/usr/lib/systemd/tests/testdata/create-busybox-container"
+export PAGER=
at_exit() {
set +e
machinectl status long-running >/dev/null && machinectl kill --signal=KILL long-running
mountpoint -q /var/lib/machines && timeout 10 sh -c "while ! umount /var/lib/machines; do sleep .5; done"
[[ -n "${NSPAWN_FRAGMENT:-}" ]] && rm -f "/etc/systemd/nspawn/$NSPAWN_FRAGMENT" "/var/lib/machines/$NSPAWN_FRAGMENT"
+ rm -f /run/systemd/nspawn/*.nspawn
}
trap at_exit EXIT
# Create a couple of containers we can refer to in tests
for i in {0..4}; do
- "$CREATE_BB_CONTAINER" "/var/lib/machines/container$i"
+ create_dummy_container "/var/lib/machines/container$i"
machinectl start "container$i"
done
# Create one "long running" container with some basic signal handling
-"$CREATE_BB_CONTAINER" /var/lib/machines/long-running
+create_dummy_container /var/lib/machines/long-running
cat >/var/lib/machines/long-running/sbin/init <<\EOF
-#!/bin/sh -x
-#
+#!/usr/bin/bash -x
+
PID=0
-# sh doesn't recognize RTMIN+4, so we have to use the signal number directly
-trap "touch /poweroff" 38
+trap "touch /poweroff" RTMIN+4
trap "touch /reboot" INT
trap "touch /trap" TRAP
trap 'kill $PID' EXIT
test ! -L /etc/systemd/system/machines.target.wants/systemd-nspawn@long-running.service
machinectl disable long-running long-running long-running container1
-[[ "$(machinectl shell testuser@ /bin/sh -c 'echo -ne $FOO')" == "" ]]
-[[ "$(machinectl shell --setenv=FOO=bar testuser@ /bin/sh -c 'echo -ne $FOO')" == "bar" ]]
+[[ "$(machinectl shell testuser@ /usr/bin/bash -c 'echo -ne $FOO')" == "" ]]
+[[ "$(machinectl shell --setenv=FOO=bar testuser@ /usr/bin/bash -c 'echo -ne $FOO')" == "bar" ]]
[[ "$(machinectl show --property=State --value long-running)" == "running" ]]
# Equivalent to machinectl kill --signal=SIGRTMIN+4 --kill-whom=leader
rm -f /var/lib/machines/long-running/poweroff
machinectl poweroff long-running
-timeout 10 sh -c "while ! test -e /var/lib/machines/long-running/poweroff; do sleep .5; done"
+timeout 10 bash -c "while ! test -e /var/lib/machines/long-running/poweroff; do sleep .5; done"
machinectl poweroff long-running long-running long-running
# Equivalent to machinectl kill --signal=SIGINT --kill-whom=leader
rm -f /var/lib/machines/long-running/reboot
machinectl reboot long-running
-timeout 10 sh -c "while ! test -e /var/lib/machines/long-running/reboot; do sleep .5; done"
+timeout 10 bash -c "while ! test -e /var/lib/machines/long-running/reboot; do sleep .5; done"
machinectl reboot long-running long-running long-running
# Skip machinectl terminate for now, as it doesn't play well with our "init"
rm -f /var/lib/machines/long-running/trap
machinectl kill --signal=SIGTRAP --kill-whom=leader long-running
-timeout 10 sh -c "while ! test -e /var/lib/machines/long-running/trap; do sleep .5; done"
+timeout 10 bash -c "while ! test -e /var/lib/machines/long-running/trap; do sleep .5; done"
machinectl kill --signal=SIGTRAP --kill-whom=leader long-running long-running long-running
# All used signals should've been caught by a handler
[[ "$(machinectl show --property=State --value long-running)" == "running" ]]
machinectl start container-dir
rm -fr /tmp/container.dir
-timeout 10 sh -c "while ! machinectl clean --all; do sleep .5; done"
+timeout 10 bash -c "while ! machinectl clean --all; do sleep .5; done"
NSPAWN_FRAGMENT="machinectl-test-$RANDOM.nspawn"
cat >"/var/lib/machines/$NSPAWN_FRAGMENT" <<EOF
set -eux
set -o pipefail
+# shellcheck source=test/units/util.sh
+. "$(dirname "$0")"/util.sh
+
export SYSTEMD_LOG_LEVEL=debug
export SYSTEMD_LOG_TARGET=journal
-CREATE_BB_CONTAINER="/usr/lib/systemd/tests/testdata/create-busybox-container"
# shellcheck disable=SC2317
at_exit() {
[[ -n "${DEV:-}" ]] && rm -f "$DEV"
[[ -n "${NETNS:-}" ]] && umount "$NETNS" && rm -f "$NETNS"
[[ -n "${TMPDIR:-}" ]] && rm -fr "$TMPDIR"
+ rm -f /run/systemd/nspawn/*.nspawn
}
trap at_exit EXIT
TMPDIR="$(mktemp -d)"
touch "$TMPDIR/hello"
OCI="$(mktemp -d /var/lib/machines/testsuite-13.oci-bundle.XXX)"
-"$CREATE_BB_CONTAINER" "$OCI/rootfs"
+create_dummy_container "$OCI/rootfs"
mkdir -p "$OCI/rootfs/opt/var"
mkdir -p "$OCI/rootfs/opt/readonly"
]
}
EOF
-systemd-nspawn --oci-bundle="$OCI" sh -xec 'mountpoint /root'
+systemd-nspawn --oci-bundle="$OCI" bash -xec 'mountpoint /root'
# And now for something a bit more involved
# Notes:
],
"cwd" : "/root",
"args" : [
- "sh",
+ "bash",
"-xe",
"/entrypoint.sh"
],
# Create a simple "entrypoint" script that validates that the container
# is created correctly according to the OCI config
cat >"$OCI/rootfs/entrypoint.sh" <<EOF
-#!/bin/sh -e
+#!/usr/bin/bash -e
# Mounts
mountpoint /root
exit 0
EOF
-systemd-nspawn --oci-bundle="$OCI"
+timeout 30 systemd-nspawn --oci-bundle="$OCI"
+
+# Test a couple of invalid configs
+INVALID_SNIPPETS=(
+ # Invalid object
+ '"foo" : { }'
+ '"process" : { "foo" : [ ] }'
+ # Non-absolute mount
+ '"mounts" : [ { "destination" : "foo", "type" : "tmpfs", "source" : "tmpfs" } ]'
+ # Invalid rlimit
+ '"process" : { "rlimits" : [ { "type" : "RLIMIT_FOO", "soft" : 0, "hard" : 0 } ] }'
+ # rlimit without RLIMIT_ prefix
+ '"process" : { "rlimits" : [ { "type" : "CORE", "soft" : 0, "hard" : 0 } ] }'
+ # Invalid env assignment
+ '"process" : { "env" : [ "foo" ] }'
+ '"process" : { "env" : [ "foo=bar", 1 ] }'
+ # Invalid process args
+ '"process" : { "args" : [ ] }'
+ '"process" : { "args" : [ "" ] }'
+ '"process" : { "args" : [ "foo", 1 ] }'
+ # Invalid capabilities
+ '"process" : { "capabilities" : { "bounding" : [ 1 ] } }'
+ '"process" : { "capabilities" : { "bounding" : [ "FOO_BAR" ] } }'
+ # Unsupported option (without JSON_PERMISSIVE)
+ '"linux" : { "resources" : { "cpu" : { "realtimeRuntime" : 1 } } }'
+ # Invalid namespace
+ '"linux" : { "namespaces" : [ { "type" : "foo" } ] }'
+ # Namespace path for a non-network namespace
+ '"linux" : { "namespaces" : [ { "type" : "user", "path" : "/foo/bar" } ] }'
+ # Duplicate namespace
+ '"linux" : { "namespaces" : [ { "type" : "ipc" }, { "type" : "ipc" } ] }'
+ # Invalid device type
+ '"linux" : { "devices" : [ { "type" : "foo", "path" : "/dev/foo" } ] }'
+ # Invalid cgroups path
+ '"linux" : { "cgroupsPath" : "/foo/bar/baz" }'
+ '"linux" : { "cgroupsPath" : "foo/bar/baz" }'
+ # Invalid sysctl assignments
+ '"linux" : { "sysctl" : { "vm.swappiness" : 60 } }'
+ '"linux" : { "sysctl" : { "foo..bar" : "baz" } }'
+ # Invalid seccomp assignments
+ '"linux" : { "seccomp" : { } }'
+ '"linux" : { "seccomp" : { "defaultAction" : 1 } }'
+ '"linux" : { "seccomp" : { "defaultAction" : "foo" } }'
+ '"linux" : { "seccomp" : { "defaultAction" : "SCMP_ACT_ALLOW", "syscalls" : [ { "action" : "SCMP_ACT_ERRNO", "names" : [ ] } ] } }'
+ # Invalid masked paths
+ '"linux" : { "maskedPaths" : [ "/foo", 1 ] }'
+ '"linux" : { "maskedPaths" : [ "/foo", "bar" ] }'
+ # Invalid read-only paths
+ '"linux" : { "readonlyPaths" : [ "/foo", 1 ] }'
+ '"linux" : { "readonlyPaths" : [ "/foo", "bar" ] }'
+ # Invalid hooks
+ '"hooks" : { "prestart" : [ { "path" : "/bin/sh", "timeout" : 0 } ] }'
+ # Invalid annotations
+ '"annotations" : { "" : "bar" }'
+ '"annotations" : { "foo" : 1 }'
+)
+
+for snippet in "${INVALID_SNIPPETS[@]}"; do
+ : "Snippet: $snippet"
+ cat >"$OCI/config.json" <<EOF
+{
+ "ociVersion" : "1.0.0",
+ "root" : {
+ "path" : "rootfs"
+ },
+ $snippet
+}
+EOF
+ (! systemd-nspawn --oci-bundle="$OCI" sh -c 'echo hello')
+done
+
+# Invalid OCI bundle version
+cat >"$OCI/config.json" <<EOF
+{
+ "ociVersion" : "6.6.6",
+ "root" : {
+ "path" : "rootfs"
+ }
+}
+EOF
+(! systemd-nspawn --oci-bundle="$OCI" sh -c 'echo hello')
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
# shellcheck disable=SC2016
+#
+# Notes on coverage: when collecting coverage we need the $BUILD_DIR present
+# and writable in the container as well. To do this in the least intrusive way,
+# two things are going on in the background (only when built with -Db_coverage=true):
+# 1) the systemd-nspawn@.service is copied to /etc/systemd/system/ with
+# --bind=$BUILD_DIR appended to the ExecStart= line
+# 2) each create_dummy_container() call also creates an .nspawn file in /run/systemd/nspawn/
+# with the last fragment from the path used as a name
+#
+# The first change is quite self-contained and applies only to containers run
+# with machinectl. The second one might cause some unexpected side-effects, namely:
+# - nspawn config (setting) files don't support dropins, so tests that test
+# the config files might need some tweaking (as seen below with
+# the $COVERAGE_BUILD_DIR shenanigans) since they overwrite the .nspawn file
+# - also a note - if /etc/systemd/nspawn/cont-name.nspawn exists, it takes
+# precedence and /run/systemd/nspawn/cont-name.nspawn won't be read even
+# if it exists
+# - in some cases we don't create a test container using create_dummy_container(),
+# so in that case an explicit call to coverage_create_nspawn_dropin() is needed
set -eux
set -o pipefail
+# shellcheck source=test/units/util.sh
+. "$(dirname "$0")"/util.sh
+
export SYSTEMD_LOG_LEVEL=debug
export SYSTEMD_LOG_TARGET=journal
-CREATE_BB_CONTAINER="/usr/lib/systemd/tests/testdata/create-busybox-container"
at_exit() {
set +e
mountpoint -q /var/lib/machines && umount /var/lib/machines
+ rm -f /run/systemd/nspawn/*.nspawn
}
trap at_exit EXIT
# with enabled user namespaces support. By setting this value explicitly
# we can ensure the user namespaces support to be detected correctly.
sysctl -w user.max_user_namespaces=10000
-if unshare -U sh -c :; then
+if unshare -U bash -c :; then
IS_USERNS_SUPPORTED=yes
fi
mkdir -p /var/lib/machines
mount -t tmpfs tmpfs /var/lib/machines
-testcase_sanity_check() {
+testcase_sanity() {
local template root image uuid tmpdir
tmpdir="$(mktemp -d)"
template="$(mktemp -d /tmp/nspawn-template.XXX)"
- "$CREATE_BB_CONTAINER" "$template"
+ create_dummy_container "$template"
# Create a simple image from the just created container template
image="$(mktemp /var/lib/machines/testsuite-13.image-XXX.img)"
dd if=/dev/zero of="$image" bs=1M count=32
# --template=
root="$(mktemp -u -d /var/lib/machines/testsuite-13.sanity.XXX)"
- (! systemd-nspawn --directory="$root" sh -xec 'echo hello')
+ coverage_create_nspawn_dropin "$root"
+ (! systemd-nspawn --directory="$root" bash -xec 'echo hello')
# Initialize $root from $template (the $root directory must not exist, hence
# the `mktemp -u` above)
- systemd-nspawn --directory="$root" --template="$template" sh -xec 'echo hello'
- systemd-nspawn --directory="$root" sh -xec 'echo hello; touch /initialized'
+ systemd-nspawn --directory="$root" --template="$template" bash -xec 'echo hello'
+ systemd-nspawn --directory="$root" bash -xec 'echo hello; touch /initialized'
test -e "$root/initialized"
# Check if the $root doesn't get re-initialized once it's not empty
- systemd-nspawn --directory="$root" --template="$template" sh -xec 'echo hello'
+ systemd-nspawn --directory="$root" --template="$template" bash -xec 'echo hello'
test -e "$root/initialized"
- systemd-nspawn --directory="$root" --ephemeral sh -xec 'touch /ephemeral'
+ systemd-nspawn --directory="$root" --ephemeral bash -xec 'touch /ephemeral'
test ! -e "$root/ephemeral"
(! systemd-nspawn --directory="$root" \
--bind="${COVERAGE_BUILD_DIR:-$tmpdir}" \
--read-only \
- sh -xec 'touch /nope')
+ bash -xec 'touch /nope')
test ! -e "$root/nope"
- systemd-nspawn --image="$image" sh -xec 'echo hello'
+ systemd-nspawn --image="$image" bash -xec 'echo hello'
# --volatile=
touch "$root/usr/has-usr"
# volatile(=yes): rootfs is tmpfs, /usr/ from the OS tree is mounted read only
systemd-nspawn --directory="$root"\
--volatile \
- sh -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope'
+ bash -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope'
test ! -e "$root/nope"
test ! -e "$root/usr/read-only"
systemd-nspawn --directory="$root"\
--volatile=yes \
- sh -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope'
+ bash -xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope'
test ! -e "$root/nope"
test ! -e "$root/usr/read-only"
# volatile=state: rootfs is read-only, /var/ is tmpfs
systemd-nspawn --directory="$root" \
--bind="${COVERAGE_BUILD_DIR:-$tmpdir}" \
--volatile=state \
- sh -xec 'test -e /usr/has-usr; mountpoint /var; touch /read-only && exit 1; touch /var/nope'
+ bash -xec 'test -e /usr/has-usr; mountpoint /var; touch /read-only && exit 1; touch /var/nope'
test ! -e "$root/read-only"
test ! -e "$root/var/nope"
# volatile=state: tmpfs overlay is mounted over rootfs
systemd-nspawn --directory="$root" \
--volatile=overlay \
- sh -xec 'test -e /usr/has-usr; touch /nope; touch /var/also-nope; touch /usr/nope-too'
+ bash -xec 'test -e /usr/has-usr; touch /nope; touch /var/also-nope; touch /usr/nope-too'
test ! -e "$root/nope"
test ! -e "$root/var/also-nope"
test ! -e "$root/usr/nope-too"
# --machine=, --hostname=
systemd-nspawn --directory="$root" \
--machine="foo-bar.baz" \
- sh -xec '[[ $(hostname) == foo-bar.baz ]]'
+ bash -xec '[[ $(hostname) == foo-bar.baz ]]'
systemd-nspawn --directory="$root" \
--hostname="hello.world.tld" \
- sh -xec '[[ $(hostname) == hello.world.tld ]]'
+ bash -xec '[[ $(hostname) == hello.world.tld ]]'
systemd-nspawn --directory="$root" \
--machine="foo-bar.baz" \
--hostname="hello.world.tld" \
- sh -xec '[[ $(hostname) == hello.world.tld ]]'
+ bash -xec '[[ $(hostname) == hello.world.tld ]]'
# --uuid=
rm -f "$root/etc/machine-id"
uuid="deadbeef-dead-dead-beef-000000000000"
systemd-nspawn --directory="$root" \
--uuid="$uuid" \
- sh -xec "[[ \$container_uuid == $uuid ]]"
+ bash -xec "[[ \$container_uuid == $uuid ]]"
# --as-pid2
- systemd-nspawn --directory="$root" sh -xec '[[ $$ -eq 1 ]]'
- systemd-nspawn --directory="$root" --as-pid2 sh -xec '[[ $$ -eq 2 ]]'
+ systemd-nspawn --directory="$root" bash -xec '[[ $$ -eq 1 ]]'
+ systemd-nspawn --directory="$root" --as-pid2 bash -xec '[[ $$ -eq 2 ]]'
# --user=
- systemd-nspawn --directory="$root" sh -xec '[[ $USER == root ]]'
- systemd-nspawn --directory="$root" --user=testuser sh -xec '[[ $USER == testuser ]]'
+ # "Fake" getent passwd's bare minimum, so we don't have to pull it in
+ # with all the DSO shenanigans
+ cat >"$root/bin/getent" <<\EOF
+#!/bin/bash
+
+if [[ $# -eq 0 ]]; then
+ :
+elif [[ $1 == passwd ]]; then
+ echo "testuser:x:1000:1000:testuser:/:/bin/sh"
+elif [[ $1 == initgroups ]]; then
+ echo "testuser"
+fi
+EOF
+ chmod +x "$root/bin/getent"
+ systemd-nspawn --directory="$root" bash -xec '[[ $USER == root ]]'
+ systemd-nspawn --directory="$root" --user=testuser bash -xec '[[ $USER == testuser ]]'
# --settings= + .nspawn files
mkdir -p /run/systemd/nspawn/
systemd-nspawn --directory="$root" \
--machine=foo-bar \
--settings=yes \
- sh -xec '[[ $container_uuid == deadbeef-dead-dead-beef-111111111111 ]]'
+ bash -xec '[[ $container_uuid == deadbeef-dead-dead-beef-111111111111 ]]'
systemd-nspawn --directory="$root" \
--machine=foo-bar \
--uuid="$uuid" \
--settings=yes \
- sh -xec "[[ \$container_uuid == $uuid ]]"
+ bash -xec "[[ \$container_uuid == $uuid ]]"
systemd-nspawn --directory="$root" \
--machine=foo-bar \
--uuid="$uuid" \
--settings=override \
- sh -xec '[[ $container_uuid == deadbeef-dead-dead-beef-111111111111 ]]'
+ bash -xec '[[ $container_uuid == deadbeef-dead-dead-beef-111111111111 ]]'
systemd-nspawn --directory="$root" \
--machine=foo-bar \
--uuid="$uuid" \
--settings=trusted \
- sh -xec "[[ \$container_uuid == $uuid ]]"
+ bash -xec "[[ \$container_uuid == $uuid ]]"
# Mounts
mkdir "$tmpdir"/{1,2,3}
# --bind=
systemd-nspawn --directory="$root" \
--bind="$tmpdir:/foo" \
- sh -xec 'test -e /foo/foo; touch /foo/bar'
+ bash -xec 'test -e /foo/foo; touch /foo/bar'
test -e "$tmpdir/bar"
# --bind-ro=
systemd-nspawn --directory="$root" \
--bind-ro="$tmpdir:/foo" \
- sh -xec 'test -e /foo/foo; touch /foo/baz && exit 1; true'
+ bash -xec 'test -e /foo/foo; touch /foo/baz && exit 1; true'
# --inaccessible=
systemd-nspawn --directory="$root" \
--inaccessible=/var \
- sh -xec 'touch /var/foo && exit 1; true'
+ bash -xec 'touch /var/foo && exit 1; true'
# --tmpfs=
systemd-nspawn --directory="$root" \
--tmpfs=/var:rw,nosuid,noexec \
- sh -xec 'touch /var/nope'
+ bash -xec 'touch /var/nope'
test ! -e "$root/var/nope"
# --overlay=
systemd-nspawn --directory="$root" \
--overlay="$tmpdir/1:$tmpdir/2:$tmpdir/3:/var" \
- sh -xec 'test -e /var/one; test -e /var/two; test -e /var/three; touch /var/foo'
+ bash -xec 'test -e /var/one; test -e /var/two; test -e /var/three; touch /var/foo'
test -e "$tmpdir/3/foo"
# --overlay-ro=
systemd-nspawn --directory="$root" \
--overlay-ro="$tmpdir/1:$tmpdir/2:$tmpdir/3:/var" \
- sh -xec 'test -e /var/one; test -e /var/two; test -e /var/three; touch /var/nope && exit 1; true'
+ bash -xec 'test -e /var/one; test -e /var/two; test -e /var/three; touch /var/nope && exit 1; true'
test ! -e "$tmpdir/3/nope"
rm -fr "$tmpdir"
+ # --port (sanity only)
+ systemd-nspawn --network-veth --directory="$root" --port=80 --port=90 true
+ systemd-nspawn --network-veth --directory="$root" --port=80:8080 true
+ systemd-nspawn --network-veth --directory="$root" --port=tcp:80 true
+ systemd-nspawn --network-veth --directory="$root" --port=tcp:80:8080 true
+ systemd-nspawn --network-veth --directory="$root" --port=udp:80 true
+ systemd-nspawn --network-veth --directory="$root" --port=udp:80:8080 --port=tcp:80:8080 true
+ (! systemd-nspawn --network-veth --directory="$root" --port= true)
+ (! systemd-nspawn --network-veth --directory="$root" --port=-1 true)
+ (! systemd-nspawn --network-veth --directory="$root" --port=: true)
+ (! systemd-nspawn --network-veth --directory="$root" --port=icmp:80:8080 true)
+ (! systemd-nspawn --network-veth --directory="$root" --port=tcp::8080 true)
+ (! systemd-nspawn --network-veth --directory="$root" --port=8080: true)
+
# Assorted tests
- systemd-nspawn --directory="$root" --suppress-sync=yes sh -xec 'echo hello'
+ systemd-nspawn --directory="$root" --suppress-sync=yes bash -xec 'echo hello'
systemd-nspawn --capability=help
systemd-nspawn --resolv-conf=help
systemd-nspawn --timezone=help
(! systemd-nspawn --rlimit==)
}
-testcase_check_bind_tmp_path() {
+nspawn_settings_cleanup() {
+ for dev in sd-host-only sd-shared{1,2} sd-macvlan{1,2} sd-ipvlan{1,2}; do
+ ip link del "$dev" || :
+ done
+
+ return 0
+}
+
+testcase_nspawn_settings() {
+ local root container dev private_users
+
+ mkdir -p /run/systemd/nspawn
+ root="$(mktemp -d /var/lib/machines/testsuite-13.nspawn-settings.XXX)"
+ container="$(basename "$root")"
+ create_dummy_container "$root"
+ rm -f "/etc/systemd/nspawn/$container.nspawn"
+ mkdir -p "$root/tmp" "$root"/opt/{tmp,inaccessible,also-inaccessible}
+
+ for dev in sd-host-only sd-shared{1,2} sd-macvlan{1,2} sd-ipvlan{1,2}; do
+ ip link add "$dev" type dummy
+ done
+ udevadm settle
+ ip link
+ trap nspawn_settings_cleanup RETURN
+
+ # Let's start with one huge config to test as much as we can at once
+ cat >"/run/systemd/nspawn/$container.nspawn" <<EOF
+[Exec]
+Boot=no
+Ephemeral=no
+ProcessTwo=no
+Parameters=bash /entrypoint.sh "foo bar" 'bar baz'
+Environment=FOO=bar
+Environment=BAZ="hello world"
+User=root
+WorkingDirectory=/tmp
+Capability=CAP_BLOCK_SUSPEND CAP_BPF CAP_CHOWN
+DropCapability=CAP_AUDIT_CONTROL CAP_AUDIT_WRITE
+AmbientCapability=CAP_BPF CAP_CHOWN
+NoNewPrivileges=no
+MachineID=f28f129b51874b1280a89421ec4b4ad4
+PrivateUsers=no
+NotifyReady=no
+SystemCallFilter=@basic-io @chown
+SystemCallFilter=~ @clock
+LimitNOFILE=1024:2048
+LimitRTPRIO=8:16
+OOMScoreAdjust=32
+CPUAffinity=0,0-5,1-5
+Hostname=nspawn-settings
+ResolvConf=copy-host
+Timezone=delete
+LinkJournal=no
+SuppressSync=no
+
+[Files]
+ReadOnly=no
+Volatile=no
+TemporaryFileSystem=/tmp
+TemporaryFileSystem=/opt/tmp
+Inaccessible=/opt/inaccessible
+Inaccessible=/opt/also-inaccessible
+PrivateUsersOwnership=auto
+Overlay=+/var::/var
+${COVERAGE_BUILD_DIR:+"Bind=$COVERAGE_BUILD_DIR"}
+
+[Network]
+Private=yes
+VirtualEthernet=yes
+VirtualEthernetExtra=my-fancy-veth1
+VirtualEthernetExtra=fancy-veth2:my-fancy-veth2
+Interface=sd-shared1 sd-shared2:sd-shared2
+MACVLAN=sd-macvlan1 sd-macvlan2:my-macvlan2
+IPVLAN=sd-ipvlan1 sd-ipvlan2:my-ipvlan2
+Zone=sd-zone0
+Port=80
+Port=81:8181
+Port=tcp:60
+Port=udp:60:61
+EOF
+ cat >"$root/entrypoint.sh" <<\EOF
+#!/bin/bash -ex
+
+[[ "$1" == "foo bar" ]]
+[[ "$2" == "bar baz" ]]
+
+[[ "$USER" == root ]]
+[[ "$FOO" == bar ]]
+[[ "$BAZ" == "hello world" ]]
+[[ "$PWD" == /tmp ]]
+[[ "$(</etc/machine-id)" == f28f129b51874b1280a89421ec4b4ad4 ]]
+[[ "$(ulimit -S -n)" -eq 1024 ]]
+[[ "$(ulimit -H -n)" -eq 2048 ]]
+[[ "$(ulimit -S -r)" -eq 8 ]]
+[[ "$(ulimit -H -r)" -eq 16 ]]
+[[ "$(</proc/self/oom_score_adj)" -eq 32 ]]
+[[ "$(hostname)" == nspawn-settings ]]
+[[ -e /etc/resolv.conf ]]
+[[ ! -e /etc/localtime ]]
+
+mountpoint /tmp
+touch /tmp/foo
+mountpoint /opt/tmp
+touch /opt/tmp/foo
+touch /opt/inaccessible/foo && exit 1
+touch /opt/also-inaccessible/foo && exit 1
+mountpoint /var
+
+ip link
+ip link | grep host-only && exit 1
+ip link | grep host0@
+ip link | grep my-fancy-veth1@
+ip link | grep my-fancy-veth2@
+ip link | grep sd-shared1
+ip link | grep sd-shared2
+ip link | grep mv-sd-macvlan1@
+ip link | grep my-macvlan2@
+ip link | grep iv-sd-ipvlan1@
+ip link | grep my-ipvlan2@
+EOF
+ timeout 30 systemd-nspawn --directory="$root"
+
+ # And now for stuff that needs to run separately
+ #
+ # Note on the condition below: since our container tree is owned by root,
+ # both "yes" and "identity" private users settings will behave the same
+ # as PrivateUsers=0:65535, which makes BindUser= fail as the UID already
+ # exists there, so skip setting it in such case
+ for private_users in "131072:65536" yes identity pick; do
+ cat >"/run/systemd/nspawn/$container.nspawn" <<EOF
+[Exec]
+Hostname=private-users
+PrivateUsers=$private_users
+
+[Files]
+PrivateUsersOwnership=auto
+BindUser=
+$([[ "$private_users" =~ (yes|identity) ]] || echo "BindUser=testuser")
+${COVERAGE_BUILD_DIR:+"Bind=$COVERAGE_BUILD_DIR"}
+EOF
+ cat "/run/systemd/nspawn/$container.nspawn"
+ chown -R root:root "$root"
+ systemd-nspawn --directory="$root" bash -xec '[[ "$(hostname)" == private-users ]]'
+ done
+
+ rm -fr "$root" "/run/systemd/nspawn/$container.nspawn"
+}
+
+bind_user_cleanup() {
+ userdel --force --remove nspawn-bind-user-1
+ userdel --force --remove nspawn-bind-user-2
+}
+
+testcase_bind_user() {
+ local root
+
+ root="$(mktemp -d /var/lib/machines/testsuite-13.bind-user.XXX)"
+ create_dummy_container "$root"
+ useradd --create-home --user-group nspawn-bind-user-1
+ useradd --create-home --user-group nspawn-bind-user-2
+ trap bind_user_cleanup RETURN
+ touch /home/nspawn-bind-user-1/foo
+ touch /home/nspawn-bind-user-2/bar
+ # Add a couple of POSIX ACLs to test the patch-uid stuff
+ mkdir -p "$root/opt"
+ setfacl -R -m 'd:u:nspawn-bind-user-1:rwX' -m 'u:nspawn-bind-user-1:rwX' "$root/opt"
+ setfacl -R -m 'd:g:nspawn-bind-user-1:rwX' -m 'g:nspawn-bind-user-1:rwX' "$root/opt"
+
+ systemd-nspawn --directory="$root" \
+ --private-users=pick \
+ --bind-user=nspawn-bind-user-1 \
+ bash -xec 'test -e /run/host/home/nspawn-bind-user-1/foo'
+
+ systemd-nspawn --directory="$root" \
+ --private-users=pick \
+ --private-users-ownership=chown \
+ --bind-user=nspawn-bind-user-1 \
+ --bind-user=nspawn-bind-user-2 \
+ bash -xec 'test -e /run/host/home/nspawn-bind-user-1/foo; test -e /run/host/home/nspawn-bind-user-2/bar'
+ chown -R root:root "$root"
+
+ # User/group name collision
+ echo "nspawn-bind-user-2:x:1000:1000:nspawn-bind-user-2:/home/nspawn-bind-user-2:/bin/bash" >"$root/etc/passwd"
+ (! systemd-nspawn --directory="$root" \
+ --private-users=pick \
+ --bind-user=nspawn-bind-user-1 \
+ --bind-user=nspawn-bind-user-2 \
+ true)
+ rm -f "$root/etc/passwd"
+
+ echo "nspawn-bind-user-2:x:1000:" >"$root/etc/group"
+ (! systemd-nspawn --directory="$root" \
+ --private-users=pick \
+ --bind-user=nspawn-bind-user-1 \
+ --bind-user=nspawn-bind-user-2 \
+ true)
+ rm -f "$root/etc/group"
+
+ rm -fr "$root"
+}
+
+testcase_bind_tmp_path() {
# https://github.com/systemd/systemd/issues/4789
local root
root="$(mktemp -d /var/lib/machines/testsuite-13.bind-tmp-path.XXX)"
- "$CREATE_BB_CONTAINER" "$root"
+ create_dummy_container "$root"
: >/tmp/bind
systemd-nspawn --register=no \
--directory="$root" \
--bind=/tmp/bind \
- /bin/sh -c 'test -e /tmp/bind'
+ bash -c 'test -e /tmp/bind'
rm -fr "$root" /tmp/bind
}
-testcase_check_norbind() {
+testcase_norbind() {
# https://github.com/systemd/systemd/issues/13170
local root
echo -n "outer" >/tmp/binddir/subdir/file
mount -t tmpfs tmpfs /tmp/binddir/subdir
echo -n "inner" >/tmp/binddir/subdir/file
- "$CREATE_BB_CONTAINER" "$root"
+ create_dummy_container "$root"
systemd-nspawn --register=no \
--directory="$root" \
--bind=/tmp/binddir:/mnt:norbind \
- /bin/sh -c 'CONTENT=$(cat /mnt/subdir/file); if [[ $CONTENT != "outer" ]]; then echo "*** unexpected content: $CONTENT"; return 1; fi'
+ bash -c 'CONTENT=$(cat /mnt/subdir/file); if [[ $CONTENT != "outer" ]]; then echo "*** unexpected content: $CONTENT"; exit 1; fi'
umount /tmp/binddir/subdir
rm -fr "$root" /tmp/binddir/
}
-check_rootidmap_cleanup() {
+rootidmap_cleanup() {
local dir="${1:?}"
mountpoint -q "$dir/bind" && umount "$dir/bind"
rm -fr "$dir"
}
-testcase_check_rootidmap() {
+testcase_rootidmap() {
local root cmd permissions
local owner=1000
dd if=/dev/zero of=/tmp/rootidmap/ext4.img bs=4k count=2048
mkfs.ext4 /tmp/rootidmap/ext4.img
mount /tmp/rootidmap/ext4.img /tmp/rootidmap/bind
- trap "check_rootidmap_cleanup /tmp/rootidmap/" RETURN
+ trap "rootidmap_cleanup /tmp/rootidmap/" RETURN
touch /tmp/rootidmap/bind/file
chown -R "$owner:$owner" /tmp/rootidmap/bind
- "$CREATE_BB_CONTAINER" "$root"
+ create_dummy_container "$root"
cmd='PERMISSIONS=$(stat -c "%u:%g" /mnt/file); if [[ $PERMISSIONS != "0:0" ]]; then echo "*** wrong permissions: $PERMISSIONS"; return 1; fi; touch /mnt/other_file'
if ! SYSTEMD_LOG_TARGET=console \
systemd-nspawn --register=no \
--directory="$root" \
--bind=/tmp/rootidmap/bind:/mnt:rootidmap \
- /bin/sh -c "$cmd" |& tee nspawn.out; then
+ bash -c "$cmd" |& tee nspawn.out; then
if grep -q "Failed to map ids for bind mount.*: Function not implemented" nspawn.out; then
echo "idmapped mounts are not supported, skipping the test..."
return 0
fi
}
-testcase_check_notification_socket() {
+testcase_notification_socket() {
# https://github.com/systemd/systemd/issues/4944
- local cmd='echo a | $(busybox which nc) -U -u -w 1 /run/host/notify'
+ local root
+ local cmd='echo a | nc -U -u -w 1 /run/host/notify'
+
+ root="$(mktemp -d /var/lib/machines/testsuite-13.check_notification_socket.XXX)"
+ create_dummy_container "$root"
- # /testsuite-13.nc-container is prepared by test.sh
- systemd-nspawn --register=no --directory=/testsuite-13.nc-container /bin/sh -x -c "$cmd"
- systemd-nspawn --register=no --directory=/testsuite-13.nc-container -U /bin/sh -x -c "$cmd"
+ systemd-nspawn --register=no --directory="$root" bash -x -c "$cmd"
+ systemd-nspawn --register=no --directory="$root" -U bash -x -c "$cmd"
+
+ rm -fr "$root"
}
-testcase_check_os_release() {
+testcase_os_release() {
local root entrypoint os_release_source
- root="$(mktemp -d /var/lib/machines/testsuite-13.check-os-release.XXX)"
- "$CREATE_BB_CONTAINER" "$root"
+ root="$(mktemp -d /var/lib/machines/testsuite-13.os-release.XXX)"
+ create_dummy_container "$root"
entrypoint="$root/entrypoint.sh"
cat >"$entrypoint" <<\EOF
-#!/bin/sh -ex
+#!/usr/bin/bash -ex
. /tmp/os-release
[[ -n "${ID:-}" && "$ID" != "$container_host_id" ]] && exit 1
rm -fr "$root"
}
-testcase_check_machinectl_bind() {
+testcase_machinectl_bind() {
local service_path service_name root container_name ec
- local cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; usleep 500000; done; exit 1;'
+ local cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; sleep .5; done; exit 1;'
- root="$(mktemp -d /var/lib/machines/testsuite-13.check-machinectl-bind.XXX)"
- "$CREATE_BB_CONTAINER" "$root"
- container_name="${root##*/}"
+ root="$(mktemp -d /var/lib/machines/testsuite-13.machinectl-bind.XXX)"
+ create_dummy_container "$root"
+ container_name="$(basename "$root")"
service_path="$(mktemp /run/systemd/system/nspawn-machinectl-bind-XXX.service)"
service_name="${service_path##*/}"
cat >"$service_path" <<EOF
[Service]
Type=notify
-ExecStart=systemd-nspawn --directory="$root" --notify-ready=no /bin/sh -xec "$cmd"
+ExecStart=systemd-nspawn --directory="$root" --notify-ready=no /usr/bin/bash -xec "$cmd"
EOF
systemctl daemon-reload
timeout 10 bash -c "while [[ '\$(systemctl show -P SubState $service_name)' == running ]]; do sleep .2; done"
ec="$(systemctl show -P ExecMainStatus "$service_name")"
+ systemctl stop "$service_name"
rm -fr "$root" "$service_path"
return "$ec"
}
-testcase_check_selinux() {
+testcase_selinux() {
# Basic test coverage to avoid issues like https://github.com/systemd/systemd/issues/19976
if ! command -v selinuxenabled >/dev/null || ! selinuxenabled; then
echo >&2 "SELinux is not enabled, skipping SELinux-related tests"
local root
- root="$(mktemp -d /var/lib/machines/testsuite-13.check-selinux.XXX)"
- "$CREATE_BB_CONTAINER" "$root"
+ root="$(mktemp -d /var/lib/machines/testsuite-13.selinux.XXX)"
+ create_dummy_container "$root"
chcon -R -t container_t "$root"
systemd-nspawn --register=no \
rm -fr "$root"
}
-testcase_check_ephemeral_config() {
+testcase_ephemeral_config() {
# https://github.com/systemd/systemd/issues/13297
local root container_name
- root="$(mktemp -d /var/lib/machines/testsuite-13.check-ephemeral-config.XXX)"
- "$CREATE_BB_CONTAINER" "$root"
- container_name="${root##*/}"
+ root="$(mktemp -d /var/lib/machines/testsuite-13.ephemeral-config.XXX)"
+ create_dummy_container "$root"
+ container_name="$(basename "$root")"
mkdir -p /run/systemd/nspawn/
+ rm -f "/etc/systemd/nspawn/$container_name.nspawn"
cat >"/run/systemd/nspawn/$container_name.nspawn" <<EOF
[Files]
+${COVERAGE_BUILD_DIR:+"Bind=$COVERAGE_BUILD_DIR"}
BindReadOnly=/tmp/ephemeral-config
EOF
touch /tmp/ephemeral-config
systemd-nspawn --register=no \
--directory="$root" \
--ephemeral \
- /bin/sh -x -c "test -f /tmp/ephemeral-config"
+ bash -x -c "test -f /tmp/ephemeral-config"
systemd-nspawn --register=no \
--directory="$root" \
--ephemeral \
--machine=foobar \
- /bin/sh -x -c "! test -f /tmp/ephemeral-config"
+ bash -x -c "! test -f /tmp/ephemeral-config"
- rm -fr "$root" "/run/systemd/nspawn/$container_name"
+ rm -fr "$root" "/run/systemd/nspawn/$container_name.nspawn"
}
matrix_run_one() {
fi
root="$(mktemp -d "/var/lib/machines/testsuite-13.unified-$1-cgns-$2-api-vfs-writable-$3.XXX")"
- "$CREATE_BB_CONTAINER" "$root"
+ create_dummy_container "$root"
SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
systemd-nspawn --register=no \
systemd-nspawn --register=no \
--directory="$root" \
--network-namespace-path=/run/netns/nspawn_test \
- /bin/ip a | grep -v -E '^1: lo.*UP'
+ ip a | grep -v -E '^1: lo.*UP'
ip netns del nspawn_test
rm -fr "$root"
systemctl bind --mkdir testsuite-23-namespaced.service /run/testsuite-23-marker-runtime /tmp/testfile-marker-runtime
-timeout 10 sh -xec 'while [[ "$(systemctl show -P SubState testsuite-23-namespaced.service)" == running ]]; do sleep .5; done'
+timeout 10 bash -xec 'while [[ "$(systemctl show -P SubState testsuite-23-namespaced.service)" == running ]]; do sleep .5; done'
systemctl is-active testsuite-23-namespaced.service
# Now test that systemctl bind fails when attempted on a non-namespaced unit
(! systemctl bind --mkdir testsuite-49-non-namespaced.service /run/testsuite-23-marker-runtime /tmp/testfile-marker-runtime)
-timeout 10 sh -xec 'while [[ "$(systemctl show -P SubState testsuite-23-non-namespaced.service)" == running ]]; do sleep .5; done'
+timeout 10 bash -xec 'while [[ "$(systemctl show -P SubState testsuite-23-non-namespaced.service)" == running ]]; do sleep .5; done'
(! systemctl is-active testsuite-23-non-namespaced.service)
shift
XDG_RUNTIME_DIR=/run/user/"$(id -u "$userid")" setpriv --reuid="$userid" --init-groups "$@"
}
+
+coverage_create_nspawn_dropin() {
+ # If we're collecting coverage, bind mount the $BUILD_DIR into the nspawn
+ # container so gcov can update the counters. This is mostly for standalone
+ # containers, as machinectl stuff is handled by overriding the systemd-nspawn@.service
+ # (see test/test-functions:install_systemd())
+ local root="${1:?}"
+ local container
+
+ if [[ -z "${COVERAGE_BUILD_DIR:-}" ]]; then
+ return 0
+ fi
+
+ container="$(basename "$root")"
+ mkdir -p "/run/systemd/nspawn"
+ echo -ne "[Files]\nBind=$COVERAGE_BUILD_DIR\n" >"/run/systemd/nspawn/${container:?}.nspawn"
+}
+
+create_dummy_container() {
+ local root="${1:?}"
+
+ if [[ ! -d /testsuite-13-container-template ]]; then
+ echo >&2 "Missing container template, probably not running in TEST-13-NSPAWN?"
+ exit 1
+ fi
+
+ mkdir -p "$root"
+ cp -a /testsuite-13-container-template/* "$root"
+ coverage_create_nspawn_dropin "$root"
+}
Description=Userspace Out-Of-Memory (OOM) Killer Socket
Documentation=man:systemd-oomd.service(8)
DefaultDependencies=no
-Before=sockets.target
+Before=sockets.target shutdown.target
+Conflicts=shutdown.target
+ConditionControlGroupController=v2
+ConditionControlGroupController=memory
+ConditionPathExists=/proc/pressure/cpu
+ConditionPathExists=/proc/pressure/io
+ConditionPathExists=/proc/pressure/memory
[Socket]
ListenStream=/run/systemd/oom/io.system.ManagedOOM