* rework mount.c and swap.c to follow proper state enumeration/deserialization
semantics, like we do for device.c now
+Before v240:
+
+* move portablectl into /usr/bin
+
+* portables: introduce a new unit file directory /etc/systemd/system.attached/
+ or so, where we attach portable services to
+
Features:
+* consider splitting out all temporary file creation APIs (we have so many in
+ fileio.h and elsewhere!) into a new util file of its own.
+
+* set memory.oom.group in cgroupsv2 for all leaf cgroups
+
+* whenever oom_kill memory.event event is triggered print a nice log message
+
+* Move RestrictAddressFamily= to the new cgroup create socket
+
+* support the bind/connect/sendmsg cgroup stuff for sandboxing, and possibly
+ patching around
+
* chown() tty a service is attached to after the service goes down
* optionally, if a per-partition GPT flag is set for the root/home/… partitions
5. add autodetection of hibernation images, and add "noresume" to disable
this
-* portables: introduce a new unit file directory /etc/systemd/system.attached/
- or so, where we attach portable services to
-
* cgroups: use inotify to get notified when somebody else modifies cgroups
owned by us, then log a friendly warning.
* add bpf-based implementation of devices cgroup controller logic for compat
with cgroupsv2 as supported by newest kernel
-* introduce sd_id128_get_boot_app_specific() which is like
- sd_id128_get_machine_app_specific(). After all on long-running systems both
- IDs have similar properties.
-
* sd-bus: add vtable flag, that may be used to request client creds implicitly
and asynchronously before dispatching the operation
--- /dev/null
+# The systemd Community Conduct Guidelines
+
+This document provides community guidelines for a safe, respectful, productive, and collaborative place for any person who is willing to contribute to systemd. It applies to all “collaborative spaces”, which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.).
+
+- Participants will be tolerant of opposing views.
+- Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
+- When interpreting the words and actions of others, participants should always assume good intentions.
+- Behaviour which can be reasonably considered harassment will not be tolerated.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at systemd-conduct@googlegroups.com. This team currently consists of David Strauss <<systemd-conduct@davidstrauss.net>>, Ekaterina Gerasimova (Kat) <<Kittykat3756@gmail.com>>, and Zbigniew Jędrzejewski-Szmek <<zbyszek@in.waw.pl>>. In the unfortunate event that you wish to make a complaint against one of the members, you may instead contact any of the other members individually.
+
+All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident.
* `$SYSTEMD_NSPAWN_LOCK=0` — if set, do not lock container images when running.
+* `$SYSTEMD_NSPAWN_TMPFS_TMP=0` — if set, do not overmount /tmp in the
+ container with a tmpfs, but leave the directory from the image in place.
+
systemd-logind:
* `$SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1` — if set, report that
✓ KillMode=
✓ KillSignal=
✓ FinalKillSignal=
+✓ WatchdogSignal=
```
## Service Unit Settings
-theme: jekyll-theme-slate
\ No newline at end of file
+theme: jekyll-theme-modernist
\ No newline at end of file
--- /dev/null
+# systemd Documentation
+
+* [The Boot Loader Specification](BOOT_LOADER_SPECIFICATION.md)
+
+* [Control Group APIs and Delegation](CGROUP_DELEGATION.md)
+
+* [The systemd Community Conduct Guidelines](CODE_OF_CONDUCT.md)
+
+* [Code Quality Tools](CODE_QUALITY.md)
+
+* [Contributing](CONTRIBUTING.md)
+
+* [Porting systemd To New Distributions](DISTRO_PORTING.md)
+
+* [Known Environment Variables](ENVIRONMENT.md)
+
+* [Portable Services Introduction](PORTABLE_SERVICES.md)
+
+* [Steps to a successful release](RELEASE.md)
+
+* [What settings are currently available for transient units?](TRANSIENT-SETTINGS.md)
+
+* [Notes for Translators](TRANSLATORS.md)
+
+* [Users, Groups, UIDs and GIDs on `systemd` systems](UIDS-GIDS.md)
</para></listitem>
</varlistentry>
- <varlistentry>
- <term><option>--new-id128</option></term>
-
- <listitem><para>Instead of showing journal contents, generate
- a new 128-bit ID suitable for identifying messages. This is
- intended for usage by developers who need a new identifier for
- a new message they introduce and want to make
- recognizable. This will print the new ID in four different
- formats which can be copied into source code or similar.
- </para></listitem>
- </varlistentry>
-
<varlistentry>
<term><option>--header</option></term>
<varlistentry>
<term><varname>HOME_URL=</varname></term>
+ <term><varname>DOCUMENTATION_URL=</varname></term>
<term><varname>SUPPORT_URL=</varname></term>
<term><varname>BUG_REPORT_URL=</varname></term>
<term><varname>PRIVACY_POLICY_URL=</varname></term>
<listitem><para>Links to resources on the Internet related to
- the operating system. <varname>HOME_URL=</varname> should refer
- to the homepage of the operating system, or alternatively some
- homepage of the specific version of the operating system.
+ the operating system.
+ <varname>HOME_URL=</varname> should refer to the homepage of
+ the operating system, or alternatively some homepage of the
+ specific version of the operating system.
+ <varname>DOCUMENTATION_URL=</varname> should refer to the main
+ documentation page for this operating system.
<varname>SUPPORT_URL=</varname> should refer to the main
support page for the operating system, if there is any. This
is primarily intended for operating systems which vendors
['sd_id128_get_machine',
'3',
['sd_id128_get_boot',
+ 'sd_id128_get_boot_app_specific',
'sd_id128_get_invocation',
'sd_id128_get_machine_app_specific'],
''],
'ENABLE_HIBERNATE'],
['systemd-hostnamed.service', '8', ['systemd-hostnamed'], 'ENABLE_HOSTNAMED'],
['systemd-hwdb', '8', [], 'ENABLE_HWDB'],
+ ['systemd-id128', '1', [], ''],
['systemd-importd.service', '8', ['systemd-importd'], 'ENABLE_IMPORTD'],
['systemd-inhibit', '1', [], ''],
['systemd-initctl.service',
}</programlisting>
<para>Note that new, randomized IDs may be generated with
- <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
- <option>--new-id128</option> option.</para>
+ <citerefentry><refentrytitle>systemd-id128</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
+ <command>new</command> command.</para>
</refsect1>
<xi:include href="libsystemd-pkgconfig.xml" />
<refname>sd_id128_get_machine</refname>
<refname>sd_id128_get_machine_app_specific</refname>
<refname>sd_id128_get_boot</refname>
+ <refname>sd_id128_get_boot_app_specific</refname>
<refname>sd_id128_get_invocation</refname>
<refpurpose>Retrieve 128-bit IDs</refpurpose>
</refnamediv>
<paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
</funcprototype>
+ <funcprototype>
+ <funcdef>int <function>sd_id128_get_boot_app_specific</function></funcdef>
+ <paramdef>sd_id128_t <parameter>app_id</parameter></paramdef>
+ <paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
+ </funcprototype>
+
<funcprototype>
<funcdef>int <function>sd_id128_get_invocation</function></funcdef>
<paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
<function>sd_id128_get_machine()</function>, but retrieves a machine ID that is specific to the application that is
identified by the indicated application ID. It is recommended to use this function instead of
<function>sd_id128_get_machine()</function> when passing an ID to untrusted environments, in order to make sure
- that the original machine ID may not be determined externally. The application-specific ID should be generated via
- a tool like <command>journalctl --new-id128</command>, and may be compiled into the application. This function will
- return the same application-specific ID for each combination of machine ID and application ID. Internally, this
- function calculates HMAC-SHA256 of the application ID, keyed by the machine ID.</para>
-
- <para><function>sd_id128_get_boot()</function> returns the boot ID
- of the executing kernel. This reads and parses the
- <filename>/proc/sys/kernel/random/boot_id</filename> file exposed
- by the kernel. It is randomly generated early at boot and is
- unique for every running kernel instance. See
- <citerefentry project='man-pages'><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry>
- for more information. This function also internally caches the
- returned ID to make this call a cheap operation.</para>
+ that the original machine ID may not be determined externally. This way, the ID used by the application remains
+ stable on a given machine, but cannot be easily correlated with IDs used in other applications on the same
+ machine. The application-specific ID should be generated via a tool like <command>systemd-id128 new</command>,
+ and may be compiled into the application. This function will return the same application-specific ID for each
+ combination of machine ID and application ID. Internally, this function calculates HMAC-SHA256 of the application
+ ID, keyed by the machine ID.</para>
+
+ <para><function>sd_id128_get_boot()</function> returns the boot ID of the executing kernel. This reads and parses
+ the <filename>/proc/sys/kernel/random/boot_id</filename> file exposed by the kernel. It is randomly generated early
+ at boot and is unique for every running kernel instance. See <citerefentry
+ project='man-pages'><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more
+ information. This function also internally caches the returned ID to make this call a cheap operation. It is
+ recommended to use this ID as-is only in trusted environments. In untrusted environments it is recommended to
+ derive an application specific ID using <function>sd_id128_get_machine_app_specific()</function>, see below.</para>
+
+ <para><function>sd_id128_get_boot_app_specific()</function> is analogous to
+ <function>sd_id128_get_machine_app_specific()</function> but returns an ID that changes between boots. Some
+ machines may be used for a long time without rebooting, hence the boot ID may remain constant for a long time, and
+ has properties similar to the machine ID during that time.</para>
<para><function>sd_id128_get_invocation()</function> returns the invocation ID of the currently executed
service. In its current implementation, this reads and parses the <varname>$INVOCATION_ID</varname> environment
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details. The
ID is cached internally. In future a different mechanism to determine the invocation ID may be added.</para>
- <para>Note that <function>sd_id128_get_machine_app_specific()</function>, <function>sd_id128_get_boot()</function>
- and <function>sd_id128_get_invocation()</function> always return UUID v4 compatible IDs.
- <function>sd_id128_get_machine()</function> will also return a UUID v4-compatible ID on new installations but might
- not on older. It is possible to convert the machine ID into a UUID v4-compatible one. For more information, see
+ <para>Note that <function>sd_id128_get_machine_app_specific()</function>, <function>sd_id128_get_boot()</function>,
+ <function>sd_id128_get_boot_app_specific()</function>, and <function>sd_id128_get_invocation()</function> always
+ return UUID v4 compatible IDs. <function>sd_id128_get_machine()</function> will also return a UUID v4-compatible
+ ID on new installations but might not on older. It is possible to convert the machine ID into a UUID v4-compatible
+ one. For more information, see
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<para>For more information about the <literal>sd_id128_t</literal>
<title>Return Value</title>
<para>Those calls return 0 on success (in which case <parameter>ret</parameter> is filled in),
- or a negative errno-style error code. In particular, <function>sd_id128_get_machine()</function>
- and <function>sd_id128_get_machine_app_specific()</function> return <constant>-ENOENT</constant>
- if <filename>/etc/machine-id</filename> is missing, and <constant>-ENOMEDIUM</constant> if is
- empty or all zeros.</para>
+ or a negative errno-style error code. In particular,
+ <function>sd_id128_get_machine()</function>,
+ <function>sd_id128_get_machine_app_specific()</function>, and
+ <function>sd_id128_get_boot_app_specific()</function> return <constant>-ENOENT</constant> if
+ <filename>/etc/machine-id</filename> is missing, and <constant>-ENOMEDIUM</constant> if is empty
+ or all zeros.</para>
</refsect1>
<xi:include href="libsystemd-pkgconfig.xml" />
<example>
<title>Application-specific machine ID</title>
- <para>Here's a simple example for an application specific machine ID:</para>
+ <para>First, generate the application ID:</para>
+ <programlisting>$ systemd-id128 -p new
+As string:
+c273277323db454ea63bb96e79b53e97
+
+As UUID:
+c2732773-23db-454e-a63b-b96e79b53e97
+
+As man:sd-id128(3) macro:
+#define MESSAGE_XYZ SD_ID128_MAKE(c2,73,27,73,23,db,45,4e,a6,3b,b9,6e,79,b5,3e,97)
+...
+</programlisting>
+
+ <para>Then use the new identifier in an example application:</para>
<programlisting><xi:include href="id128-app-specific.c" parse="text" /></programlisting>
</example>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-id128</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
type, see
<citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
- <para><citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
- <option>--new-id128</option> option may be used as a command line
- front-end for <function>sd_id128_randomize()</function>.</para>
+ <para><citerefentry><refentrytitle>systemd-id128</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
+ <command>new</command> command may be used as a command line front-end for
+ <function>sd_id128_randomize()</function>.</para>
</refsect1>
<refsect1>
<listitem>
<para>Just print what would be done. Currently supported by verbs
<command>halt</command>, <command>poweroff</command>, <command>reboot</command>,
- <command>kexec</command>, <command>suspend</command>,
- <command>hibernate</command>, <command>hybrid-sleep</command>,
+ <command>kexec</command>, <command>suspend</command>, <command>hibernate</command>,
+ <command>hybrid-sleep</command>, <command>suspend-then-hibernate</command>,
<command>default</command>, <command>rescue</command>,
<command>emergency</command>, and <command>exit</command>.</para>
</listitem>
sleep operation is successfully enqueued. It will not wait for the sleep/wake-up cycle to complete.</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><command>suspend-then-hibernate</command></term>
+
+ <listitem>
+ <para>Suspend the system and hibernate it after the delay specified in <filename>systemd-sleep.conf</filename>.
+ This will trigger activation of the special target unit <filename>suspend-then-hibernate.target</filename>.
+ This command is asynchronous, and will return after the hybrid sleep operation is successfully enqueued.
+ It will not wait for the sleep/wake-up or hibernate/thaw cycle to complete.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
--- /dev/null
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="systemd-id128" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <refentryinfo>
+ <title>systemd-id128</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>systemd-id128</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>systemd-id128</refname>
+ <refpurpose>Generate and print sd-128 identifiers</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>systemd-id128</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="plain">new</arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>systemd-id128</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="plain">machine-id</arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>systemd-id128</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="plain">boot-id</arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>systemd-id128</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="plain">invocation-id</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><command>id128</command> may be used to conveniently print
+ <citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ UUIDs. What identifier is printed depends on the specific verb.</para>
+
+ <para>With <command>new</command>, a new random identifier will be generated.</para>
+
+ <para>With <command>machine-id</command>, the identifier of the current machine will be
+ printed. See
+ <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
+
+ <para>With <command>boot-id</command>, the identifier of the current boot will be
+ printed.</para>
+
+ <para>Both <command>machine-id</command> and <command>boot-id</command> may be combined
+ with the <option>--app-specific=<replaceable>app-id</replaceable></option> switch to
+ generate application-specific IDs. See
+ <citerefentry><refentrytitle>sd_id128_get_machine</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ for the discussion when this is useful.</para>
+
+ <para>With <command>invocation-id</command>, the identifier of the current service invocation
+ will be printed. This is available in systemd services. See
+ <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+
+ <para>The following options are understood:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>-p</option></term>
+ <term><option>--pretty</option></term>
+
+ <listitem><para>Generate output as programming language snippets.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-a <replaceable>app-id</replaceable></option></term>
+ <term><option>--app-specific=<replaceable>app-id</replaceable></option></term>
+
+ <listitem><para>With this option, an identifier that is the result of hashing the
+ application identifier <replaceable>app-id</replaceable> and the machine identifier will be
+ printed. The <replaceable>app-id</replaceable> argument must be a valid sd-id128 string
+ identifying the application.</para>
+ </listitem>
+ </varlistentry>
+
+ <xi:include href="standard-options.xml" xpointer="help" />
+ <xi:include href="standard-options.xml" xpointer="version" />
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Exit status</title>
+
+ <para>On success, 0 is returned, a non-zero failure code otherwise.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_id128_get_machine</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
settings (see the discussion in <varname>PrivateMounts=</varname> above) will implicitly disable mount and
unmount propagation from the unit's processes towards the host by changing the propagation setting of all mount
points in the unit's file system namepace to <option>slave</option> first. Setting this option to
- <option>shared</option> does not reestablish propagation in that case. Conversely, if this option is set, but
- no other file system namespace setting is used, then new file system namespaces will be created for the unit's
- processes and this propagation flag will be applied right away to all mounts within it, without the
- intermediary application of <option>slave</option>.</para>
+ <option>shared</option> does not reestablish propagation in that case.</para>
<para>If not set – but file system namespaces are enabled through another file system namespace unit setting –
<option>shared</option> mount propagation is used, but — as mentioned — as <option>slave</option> is applied
<varlistentry>
<term><varname>MESSAGE_ID=</varname></term>
<listitem>
- <para>A 128-bit message identifier ID for recognizing
- certain message types, if this is desirable. This should
- contain a 128-bit ID formatted as a lower-case hexadecimal
- string, without any separating dashes or suchlike. This is
- recommended to be a UUID-compatible ID, but this is not
- enforced, and formatted differently. Developers can generate
- a new ID for this purpose with <command>journalctl
- <option>--new-id128</option></command>.
+ <para>A 128-bit message identifier ID for recognizing certain message types, if this is desirable. This
+ should contain a 128-bit ID formatted as a lower-case hexadecimal string, without any separating dashes or
+ suchlike. This is recommended to be a UUID-compatible ID, but this is not enforced, and formatted
+ differently. Developers can generate a new ID for this purpose with <command>systemd-id128 new</command>.
</para>
</listitem>
</varlistentry>
</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>WatchdogSignal=</varname></term>
+ <listitem><para>Specifies which signal to use to terminate the
+ service when the watchdog timeout expires (enabled through
+ <varname>WatchdogSec=</varname>). Defaults to <constant>SIGABRT</constant>.
+ </para></listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
Takes a boolean value. Unset by default, which means that the kernel default
will be used.</para>
- <para>Note that if autonegotiation is enabled, speed and duplex settings are
- read-only. If autonegotation is disabled, speed and duplex settings are writable
+ <para>Note that if autonegotiation is enabled, speed, duplex and advertise settings are
+ read-only. If autonegotation is disabled, speed, duplex and advertise settings are writable
if the driver supports multiple link modes.</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>Advertise=</varname></term>
+ <listitem>
+ <para>This sets what speeds and duplex modes of operation are advertised for auto-negotiation.
+ The supported values are:
+
+ <table>
+ <title>Supported advertise values</title>
+ <tgroup cols='3'>
+ <colspec colname='Advertise' />
+ <colspec colname='Speed' />
+ <colspec colname='Duplex Mode' />
+
+ <thead><row>
+ <entry>Advertise</entry>
+ <entry>Speed (Mbps)</entry>
+ <entry>Duplex Mode</entry>
+ </row></thead>
+ <tbody>
+
+ <row><entry><literal>10baset-half</literal></entry>
+ <entry>10</entry><entry>half</entry></row>
+
+ <row><entry><literal>10baset-full</literal></entry>
+ <entry>10</entry><entry>full</entry></row>
+
+ <row><entry><literal>100baset-half</literal></entry>
+ <entry>100</entry><entry>half</entry></row>
+
+ <row><entry><literal>100baset-full</literal></entry>
+ <entry>100</entry><entry>full</entry></row>
+
+ <row><entry><literal>1000baset-half</literal></entry>
+ <entry>1000</entry><entry>half</entry></row>
+
+ <row><entry><literal>1000baset-full</literal></entry>
+ <entry>1000</entry><entry>full</entry></row>
+
+ <row><entry><literal>10000baset-full</literal></entry>
+ <entry>10000</entry><entry>full</entry></row>
+
+ <row><entry><literal>2500basex-full</literal></entry>
+ <entry>2500</entry><entry>full</entry></row>
+
+ <row><entry><literal>1000basekx-full</literal></entry>
+ <entry>1000</entry><entry>full</entry></row>
+
+ <row><entry><literal>10000basekx4-full</literal></entry>
+ <entry>10000</entry><entry>full</entry></row>
+
+ <row><entry><literal>10000basekr-full</literal></entry>
+ <entry>10000</entry><entry>full</entry></row>
+
+ <row><entry><literal>10000baser-fec</literal></entry>
+ <entry>10000</entry><entry>full</entry></row>
+
+ <row><entry><literal>20000basemld2-full</literal></entry>
+ <entry>20000</entry><entry>full</entry></row>
+
+ <row><entry><literal>20000basekr2-full</literal></entry>
+ <entry>20000</entry><entry>full</entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ By default this is unset, i.e. all possible modes will be advertised.
+ This option may be specified more than once, in which case all specified speeds and modes are advertised.
+ If the empty string is assigned to this option, the list is reset, and all prior assignments have no effect.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><varname>TCPSegmentationOffload=</varname></term>
<listitem>
"keep-alive ping"). If the time between two such calls is
larger than the configured time, then the service is placed in
a failed state and it will be terminated with
- <constant>SIGABRT</constant>. By setting
+ <constant>SIGABRT</constant> (or the signal specified by
+ <varname>WatchdogSignal=</varname>). By setting
<varname>Restart=</varname> to <option>on-failure</option>,
<option>on-watchdog</option>, <option>on-abnormal</option> or
<option>always</option>, the service will be automatically
<title>Type</title>
<para>The type consists of a single letter and optionally an
- exclamation mark.</para>
+ exclamation mark and/or minus sign.</para>
<para>The following line types are understood:</para>
running system, and will only be executed with
<option>--boot</option>.</para>
+ <para>If the minus sign is used, this line failing to run
+ successfully during create (and only create) will not cause
+ the execution of <command>systemd-tmpfiles</command> to return
+ an error.</para>
+
+ <para>For example:
+ <programlisting># Modify sysfs but don't fail if we are in a container with a read-only /proc
+w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
+
<para>Note that for all line types that result in creation of any kind of file node
(i.e. <varname>f</varname>/<varname>F</varname>,
<varname>d</varname>/<varname>D</varname>/<varname>v</varname>/<varname>q</varname>/<varname>Q</varname>,
<refsect2>
<title>UID, GID</title>
- <para>The user and group to use for this file or directory. This
- may either be a numeric user/group ID or a user or group
- name. If omitted or when set to <literal>-</literal>, the
- default 0 (root) is used. For <varname>z</varname> and
- <varname>Z</varname> lines, when omitted or when set to
- <literal>-</literal>, the file ownership will not be
- modified. These parameters are ignored for <varname>x</varname>,
- <varname>r</varname>, <varname>R</varname>,
- <varname>L</varname>, <varname>t</varname>, and
- <varname>a</varname> lines.</para>
+ <para>The user and group to use for this file or directory. This may either be a numeric user/group ID or a user or group
+ name. If omitted or when set to <literal>-</literal>, the user/group ID of the user who invokes <command>systemd-tmpfiles</command> is used.
+ For <varname>z</varname> and <varname>Z</varname> lines, when omitted or when set to <literal>-</literal>, the file ownership will not be
+ modified. These parameters are ignored for <varname>x</varname>, <varname>r</varname>, <varname>R</varname>, <varname>L</varname>,
+ <varname>t</varname>, and <varname>a</varname> lines.</para>
</refsect2>
<refsect2>
add_project_arguments('-Werror=shadow', language : 'c')
endif
-cpp = ' '.join(cc.cmd_array()) + ' -E'
+cpp = ' '.join(cc.cmd_array() + get_option('c_args')) + ' -E'
#####################################################################
# compilation result tests
conf.set10('ENABLE_DEBUG_MMAP_CACHE', enable_debug_mmap_cache)
conf.set10('VALGRIND', get_option('valgrind'))
+conf.set10('LOG_TRACE', get_option('log-trace'))
#####################################################################
module = tuple[0]
sym = 'src/nss-@0@/nss-@0@.sym'.format(module)
- version_script_arg = join_paths(meson.current_source_dir(), sym)
+ version_script_arg = join_paths(meson.source_root(), sym)
nss = shared_library(
'nss_' + module,
public_programs += exe
if conf.get('HAVE_PAM') == 1
- version_script_arg = join_paths(meson.current_source_dir(), pam_systemd_sym)
+ version_script_arg = join_paths(meson.source_root(), pam_systemd_sym)
pam_systemd = shared_library(
'pam_systemd',
pam_systemd_c,
install : true,
install_dir : rootlibexecdir)
+exe = executable('systemd-id128',
+ 'src/id128/id128.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
+public_programs += exe
+
exe = executable('systemd-path',
'src/path/path.c',
include_directories : includes,
test('@0@:@1@:@2@'.format(b, c, sanitizer),
env,
args : [exe.full_path(),
- join_paths(meson.source_root(),
- 'test/fuzz-regressions',
- p)])
+ join_paths(meson.source_root(), p)])
endif
endforeach
endif
if git.found()
all_files = run_command(
git,
- ['--git-dir=@0@/.git'.format(meson.current_source_dir()),
+ ['--git-dir=@0@/.git'.format(meson.source_root()),
'ls-files',
':/*.[ch]'])
all_files = files(all_files.stdout().split())
custom_target(
'tags',
output : 'tags',
- command : [env, 'etags', '-o', '@0@/TAGS'.format(meson.current_source_dir())] + all_files)
+ command : [env, 'etags', '-o', '@0@/TAGS'.format(meson.source_root())] + all_files)
run_target(
'ctags',
- command : [env, 'ctags', '-o', '@0@/tags'.format(meson.current_source_dir())] + all_files)
+ command : [env, 'ctags', '-o', '@0@/tags'.format(meson.source_root())] + all_files)
endif
if git.found()
if git.found()
git_head = run_command(
git,
- ['--git-dir=@0@/.git'.format(meson.current_source_dir()),
+ ['--git-dir=@0@/.git'.format(meson.source_root()),
'rev-parse', 'HEAD']).stdout().strip()
git_head_short = run_command(
git,
- ['--git-dir=@0@/.git'.format(meson.current_source_dir()),
+ ['--git-dir=@0@/.git'.format(meson.source_root()),
'rev-parse', '--short=7', 'HEAD']).stdout().strip()
run_target(
'git-snapshot',
command : ['git', 'archive',
- '-o', '@0@/systemd-@1@.tar.gz'.format(meson.current_source_dir(),
+ '-o', '@0@/systemd-@1@.tar.gz'.format(meson.source_root(),
git_head_short),
'--prefix', 'systemd-@0@/'.format(git_head),
'HEAD'])
depends : [man, libsystemd, libudev],
command : [meson_check_api_docs_sh, libsystemd.full_path(), libudev.full_path()])
+run_target(
+ 'make-index-md',
+ command : ['sh', '@0@/tools/make-index-md.sh'.format(meson.source_root()), meson.source_root()])
+
############################################################
status = [
['blkid'],
['dbus'],
['glib'],
- ['nss-myhostname', conf.get('ENABLE_NSS_MYHOSTNAME') == 1],
- ['nss-mymachines', conf.get('ENABLE_NSS_MYMACHINES') == 1],
- ['nss-resolve', conf.get('ENABLE_NSS_RESOLVE') == 1],
- ['nss-systemd', conf.get('ENABLE_NSS_SYSTEMD') == 1],
+ ['nss-myhostname'],
+ ['nss-mymachines'],
+ ['nss-resolve'],
+ ['nss-systemd'],
['hwdb'],
['tpm'],
['man pages', want_man],
['debug hashmap'],
['debug mmap cache'],
['valgrind', conf.get('VALGRIND') == 1],
+ ['trace logging', conf.get('LOG_TRACE') == 1],
]
if tuple.length() >= 2
description : 'enable MemoryAccounting= by default')
option('valgrind', type : 'boolean', value : false,
description : 'do extra operations to avoid valgrind warnings')
+option('log-trace', type : 'boolean', value : false,
+ description : 'enable low level debug logging')
option('utmp', type : 'boolean',
description : 'support for utmp/wtmp log handling')
option('gnu-efi', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'gnu-efi support for sd-boot')
-option('efi-cc', type : 'string', value : 'gcc',
+option('efi-cc', type : 'array',
description : 'the compiler to use for EFI modules')
-option('efi-ld', type : 'string', value : 'ld',
+option('efi-ld', type : 'string',
description : 'the linker to use for EFI modules')
option('efi-libdir', type : 'string',
description : 'path to the EFI lib directory')
msgstr ""
"Project-Id-Version: systemd master\n"
"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
-"POT-Creation-Date: 2018-03-27 03:26+0000\n"
-"PO-Revision-Date: 2018-04-22 21:20+0300\n"
+"POT-Creation-Date: 2018-08-23 15:26+0000\n"
+"PO-Revision-Date: 2018-10-01 20:20+0300\n"
"Last-Translator: Muhammet Kara <muhammetk@gnome.org>\n"
"Language-Team: Turkish <gnome-turk@gnome.org>\n"
"Language: tr_TR\n"
"Sistem servislerini veya birim dosyalarını yönetmek kimlik doğrulaması "
"gerektiriyor."
-#: src/core/org.freedesktop.systemd1.policy.in:53
+#: src/core/org.freedesktop.systemd1.policy.in:54
msgid "Set or unset system and service manager environment variables"
msgstr "Sistem ve servis yöneticisi ortam değişkenlerini ayarla ya da kaldır"
-#: src/core/org.freedesktop.systemd1.policy.in:54
+#: src/core/org.freedesktop.systemd1.policy.in:55
msgid ""
"Authentication is required to set or unset system and service manager "
"environment variables."
"Sistem ve servis yöneticisi ortam değişkenlerini ayarlamak ya da kaldırmak "
"kimlik doğrulaması gerektiriyor."
-#: src/core/org.freedesktop.systemd1.policy.in:63
+#: src/core/org.freedesktop.systemd1.policy.in:64
msgid "Reload the systemd state"
msgstr "systemd durumunu yeniden yükle"
-#: src/core/org.freedesktop.systemd1.policy.in:64
+#: src/core/org.freedesktop.systemd1.policy.in:65
msgid "Authentication is required to reload the systemd state."
msgstr "systemd durumunu yeniden yüklemek kimlik doğrulaması gerektiriyor."
-#: src/hostname/org.freedesktop.hostname1.policy:22
+#: src/hostname/org.freedesktop.hostname1.policy:20
msgid "Set host name"
msgstr "Makine adını ayarla"
-#: src/hostname/org.freedesktop.hostname1.policy:23
+#: src/hostname/org.freedesktop.hostname1.policy:21
msgid "Authentication is required to set the local host name."
msgstr "Yerel makine adını ayarlamak kimlik doğrulaması gerektiriyor."
-#: src/hostname/org.freedesktop.hostname1.policy:32
+#: src/hostname/org.freedesktop.hostname1.policy:30
msgid "Set static host name"
msgstr "Statik makine adı ayarla"
-#: src/hostname/org.freedesktop.hostname1.policy:33
+#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
"Authentication is required to set the statically configured local host name, "
"as well as the pretty host name."
"Statik olarak yapılandırılmış konak makine adını ve yerel makine adını "
"ayarlamak kimlik doğrulaması gerektiriyor."
-#: src/hostname/org.freedesktop.hostname1.policy:43
+#: src/hostname/org.freedesktop.hostname1.policy:41
msgid "Set machine information"
msgstr "Makine bilgisini ayarla"
-#: src/hostname/org.freedesktop.hostname1.policy:44
+#: src/hostname/org.freedesktop.hostname1.policy:42
msgid "Authentication is required to set local machine information."
msgstr "Yerel makine bilgisini ayarlamak kimlik doğrulaması gerektiriyor."
+#: src/hostname/org.freedesktop.hostname1.policy:51
+msgid "Get product UUID"
+msgstr "Ürün UUID'ini al"
+
+#: src/hostname/org.freedesktop.hostname1.policy:52
+#| msgid "Authentication is required to reload '$(unit)'."
+msgid "Authentication is required to get product UUID."
+msgstr "Ürün UUID'ini almak için kimlik doğrulaması gereklidir."
+
#: src/import/org.freedesktop.import1.policy:22
msgid "Import a VM or container image"
msgstr "Bir SM ya da kapsayıcı kalıbını içe aktar"
"Yerel sanal makineler ve kapsayıcı kalıplarını yönetmek için kimlik "
"doğrulaması gereklidir."
+#: src/portable/org.freedesktop.portable1.policy:13
+msgid "Inspect a portable service image"
+msgstr "Bir taşınabilir hizmet kalıbını incele"
+
+#: src/portable/org.freedesktop.portable1.policy:14
+#| msgid "Authentication is required to import a VM or container image"
+msgid "Authentication is required to inspect a portable service image."
+msgstr ""
+"Bir taşınabilir hizmet kalıbını incelemek için kimlik doğrulaması gereklidir."
+
+#: src/portable/org.freedesktop.portable1.policy:23
+msgid "Attach or detach a portable service image"
+msgstr "Bir taşınabilir hizmet kalıbını tuttur ya da ayır"
+
+#: src/portable/org.freedesktop.portable1.policy:24
+#| msgid "Authentication is required for attaching a device to a seat."
+msgid ""
+"Authentication is required to attach or detach a portable service image."
+msgstr ""
+"Bir taşınabilir hizmet kalıbını tutturmak ya da ayırmak için kimlik "
+"doğrulaması gereklidir."
+
+#: src/portable/org.freedesktop.portable1.policy:34
+msgid "Delete or modify portable service image"
+msgstr "Taşınabilir hizmet kalıbını sil ya da değiştir"
+
+#: src/portable/org.freedesktop.portable1.policy:35
+#| msgid "Authentication is required to download a VM or container image"
+msgid ""
+"Authentication is required to delete or modify a portable service image."
+msgstr ""
+"Taşınabilir hizmet kalıbını silmek ya da değiştirmek için kimlik doğrulaması "
+"gereklidir."
+
#: src/resolve/org.freedesktop.resolve1.policy:22
msgid "Register a DNS-SD service"
msgstr "Bir DNS-SD hizmeti kaydet"
#: src/resolve/org.freedesktop.resolve1.policy:23
-#| msgid "Authentication is required to set a wall message"
msgid "Authentication is required to register a DNS-SD service"
msgstr "Bir DNS-SD hizmeti kaydetmek için kimlik doğrulaması gereklidir"
msgstr "Bir DNS-SD hizmetinin kaydını sil"
#: src/resolve/org.freedesktop.resolve1.policy:34
-#| msgid "Authentication is required to set a wall message"
msgid "Authentication is required to unregister a DNS-SD service"
msgstr ""
"Bir DNS-SD hizmetinin kaydını silmek için kimlik doğrulaması gereklidir"
"Gerçek zamanlı saat olarak yerel zaman dilimini veya UTC'yi ayarlamak kimlik "
"doğrulaması gerektiriyor."
-#: src/timedate/org.freedesktop.timedate1.policy:54
+#: src/timedate/org.freedesktop.timedate1.policy:53
msgid "Turn network time synchronization on or off"
msgstr "Ağ zaman eş zamanlamasını aç veya kapat"
-#: src/timedate/org.freedesktop.timedate1.policy:55
+#: src/timedate/org.freedesktop.timedate1.policy:54
msgid ""
"Authentication is required to control whether network time synchronization "
"shall be enabled."
msgstr ""
"Ağ zaman eş zamanlamasını kontrol etmek kimlik doğrulaması gerektiriyor."
-#: src/core/dbus-unit.c:496
+#: src/core/dbus-unit.c:326
msgid "Authentication is required to start '$(unit)'."
msgstr "'$(unit)' başlatmak için kimlik doğrulaması gereklidir."
-#: src/core/dbus-unit.c:497
+#: src/core/dbus-unit.c:327
msgid "Authentication is required to stop '$(unit)'."
msgstr "'$(unit)' durdurmak için kimlik doğrulaması gereklidir."
-#: src/core/dbus-unit.c:498
+#: src/core/dbus-unit.c:328
msgid "Authentication is required to reload '$(unit)'."
msgstr "'$(unit)' yeniden yüklemek için kimlik doğrulaması gereklidir."
-#: src/core/dbus-unit.c:499 src/core/dbus-unit.c:500
+#: src/core/dbus-unit.c:329 src/core/dbus-unit.c:330
msgid "Authentication is required to restart '$(unit)'."
msgstr "'$(unit)' yeniden başlatmak için kimlik doğrulaması gereklidir."
-#: src/core/dbus-unit.c:607
+#: src/core/dbus-unit.c:437
msgid "Authentication is required to kill '$(unit)'."
msgstr "'$(unit)' sonlandırmak için kimlik doğrulaması gereklidir."
-#: src/core/dbus-unit.c:638
+#: src/core/dbus-unit.c:468
msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
msgstr ""
"'$(unit)'in \"failed\" (başarısız) durumunu sıfırlamak için kimlik "
"doğrulaması gereklidir."
-#: src/core/dbus-unit.c:671
+#: src/core/dbus-unit.c:501
msgid "Authentication is required to set properties on '$(unit)'."
msgstr ""
"'$(unit)' üzerindeki özellikleri ayarlamak için kimlik doğrulaması "
if (!env_assignment_is_valid(*p))
return false;
- /* Check if there are duplicate assginments */
+ /* Check if there are duplicate assignments */
k = strcspn(*p, "=");
STRV_FOREACH(q, p + 1)
if (strneq(*p, *q, k) && (*q)[k] == '=')
assert(p);
/* Replace first occurrence of the env var or add a new one in the
- * string list. Drop other occurences. Edits in-place. Does not copy p.
+ * string list. Drop other occurrences. Edits in-place. Does not copy p.
* p must be a valid key=value assignment.
*/
r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char* const*) directories);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to enumerate executables: %m");
if (!callbacks) {
pids = hashmap_new(NULL);
alarm(DIV_ROUND_UP(timeout, USEC_PER_SEC));
STRV_FOREACH(e, envp)
- putenv(*e);
+ if (putenv(*e) < 0)
+ return log_error_errno(errno, "Failed to set environment variable: %m");
STRV_FOREACH(path, paths) {
_cleanup_free_ char *t = NULL;
}
int link_tmpfile(int fd, const char *path, const char *target) {
+ int r;
assert(fd >= 0);
assert(target);
* operation currently (renameat2() does), and there is no nice way to emulate this. */
if (path) {
- if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0)
- return -errno;
+ r = rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
+ if (r < 0)
+ return r;
} else {
char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
}
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
- struct stat buf;
- int ret;
+ int r;
- ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
- if (ret >= 0)
+ /* Try the ideal approach first */
+ if (renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE) >= 0)
return 0;
- /* renameat2() exists since Linux 3.15, btrfs added support for it later.
- * If it is not implemented, fallback to another method. */
- if (!IN_SET(errno, EINVAL, ENOSYS))
+ /* renameat2() exists since Linux 3.15, btrfs and FAT added support for it later. If it is not implemented,
+ * fall back to a different method. */
+ if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY))
return -errno;
- /* The link()/unlink() fallback does not work on directories. But
- * renameat() without RENAME_NOREPLACE gives the same semantics on
- * directories, except when newpath is an *empty* directory. This is
- * good enough. */
- ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
- if (ret >= 0 && S_ISDIR(buf.st_mode)) {
- ret = renameat(olddirfd, oldpath, newdirfd, newpath);
- return ret >= 0 ? 0 : -errno;
+ /* Let's try to use linkat()+unlinkat() as fallback. This doesn't work on directories and on some file systems
+ * that do not support hard links (such as FAT, most prominently), but for files it's pretty close to what we
+ * want — though not atomic (i.e. for a short period both the new and the old filename will exist). */
+ if (linkat(olddirfd, oldpath, newdirfd, newpath, 0) >= 0) {
+
+ if (unlinkat(olddirfd, oldpath, 0) < 0) {
+ r = -errno; /* Backup errno before the following unlinkat() alters it */
+ (void) unlinkat(newdirfd, newpath, 0);
+ return r;
+ }
+
+ return 0;
}
- /* If it is not a directory, use the link()/unlink() fallback. */
- ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
- if (ret < 0)
+ if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)) /* FAT returns EPERM on link()… */
return -errno;
- ret = unlinkat(olddirfd, oldpath, 0);
- if (ret < 0) {
- /* backup errno before the following unlinkat() alters it */
- ret = errno;
- (void) unlinkat(newdirfd, newpath, 0);
- errno = ret;
+ /* OK, neither RENAME_NOREPLACE nor linkat()+unlinkat() worked. Let's then fallback to the racy TOCTOU
+ * vulnerable accessat(F_OK) check followed by classic, replacing renameat(), we have nothing better. */
+
+ if (faccessat(newdirfd, newpath, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
+ return -EEXIST;
+ if (errno != ENOENT)
+ return -errno;
+
+ if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
return -errno;
- }
return 0;
}
* necessary to instantiate an object for each Hashmap use.
*
* If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap),
- * the implemention will:
+ * the implementation will:
* - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
* - perform extra checks for invalid use of iterators
*/
assert(l);
/* Find the next non-whitespace character, and decode it. We
- * greedily skip all preceeding and all following whitespace. */
+ * greedily skip all preceding and all following whitespace. */
for (;;) {
if (*l == 0)
_cleanup_free_ char *x = NULL;
char *t, *s;
- ssize_t slen, len, avail;
- int line, lines;
+ ssize_t len, slen, avail, line, lines;
len = base64mem(p, l, &x);
if (len <= 0)
lines = DIV_ROUND_UP(len, width);
slen = strlen_ptr(sep);
+ if (lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1))
+ return -ENOMEM;
+
t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
if (!t)
return -ENOMEM;
assert(l);
/* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
- * greedily skip all preceeding and all following whitespace. */
+ * greedily skip all preceding and all following whitespace. */
for (;;) {
if (*l == 0)
if (path_startswith(p, *i)) {
blacklisted = true;
- log_debug("Not remounting %s, because blacklisted by %s, called for %s", p, *i, cleaned);
+ log_debug("Not remounting %s blacklisted by %s, called for %s", p, *i, cleaned);
break;
}
}
s = *p;
- /* accept any number of digits, strtoull is limted to 19 */
+ /* accept any number of digits, strtoull is limited to 19 */
for (i=0; i < digits; i++,s++) {
if (*s < '0' || *s > '9') {
if (i == 0)
/* Removes redundant inner and trailing slashes. Also removes unnecessary dots
* if kill_dots is true. Modifies the passed string in-place.
*
- * ///foo//./bar/. becomes /foo/./bar/. (if kill_dots is false)
- * ///foo//./bar/. becomes /foo/bar (if kill_dots is true)
- * .//./foo//./bar/. becomes ./foo/bar (if kill_dots is false)
- * .//./foo//./bar/. becomes foo/bar (if kill_dots is true)
+ * ///foo//./bar/. becomes /foo/./bar/. (if kill_dots is false)
+ * ///foo//./bar/. becomes /foo/bar (if kill_dots is true)
+ * .//./foo//./bar/. becomes ././foo/./bar/. (if kill_dots is false)
+ * .//./foo//./bar/. becomes foo/bar (if kill_dots is true)
*/
+ if (isempty(path))
+ return path;
+
absolute = path_is_absolute(path);
f = path;
*(t++) = *f;
}
- /* Special rule, if we are talking of the root directory, a trailing slash is good */
- if (absolute && t == path)
- *(t++) = '/';
+ /* Special rule, if we stripped everything, we either need a "/" (for the root directory)
+ * or "." for the current directory */
+ if (t == path) {
+ if (absolute)
+ *(t++) = '/';
+ else
+ *(t++) = '.';
+ }
*t = 0;
return path;
assert(a);
assert(b);
- /* A relative path and an abolute path must not compare as equal.
+ /* A relative path and an absolute path must not compare as equal.
* Which one is sorted before the other does not really matter.
* Here a relative path is ordered before an absolute path. */
d = (a[0] == '/') - (b[0] == '/');
/* Now, let's tell the kernel about this new memory */
if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
- log_debug_errno(errno, "PR_SET_MM_ARG_START failed, proceeding without: %m");
- (void) munmap(nn, nn_size);
- goto use_saved_argv;
- }
+ /* HACK: prctl() API is kind of dumb on this point. The existing end address may already be
+ * below the desired start address, in which case the kernel may have kicked this back due
+ * to a range-check failure (see linux/kernel/sys.c:validate_prctl_map() to see this in
+ * action). The proper solution would be to have a prctl() API that could set both start+end
+ * simultaneously, or at least let us query the existing address to anticipate this condition
+ * and respond accordingly. For now, we can only guess at the cause of this failure and try
+ * a workaround--which will briefly expand the arg space to something potentially huge before
+ * resizing it to what we want. */
+ log_debug_errno(errno, "PR_SET_MM_ARG_START failed, attempting PR_SET_MM_ARG_END hack: %m");
+
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0) {
+ log_debug_errno(errno, "PR_SET_MM_ARG_END hack failed, proceeding without: %m");
+ (void) munmap(nn, nn_size);
+ goto use_saved_argv;
+ }
- /* And update the end pointer to the new end, too. If this fails, we don't really know what to do, it's
- * pretty unlikely that we can rollback, hence we'll just accept the failure, and continue. */
- if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0)
- log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
+ log_debug_errno(errno, "PR_SET_MM_ARG_START still failed, proceeding without: %m");
+ goto use_saved_argv;
+ }
+ } else {
+ /* And update the end pointer to the new end, too. If this fails, we don't really know what
+ * to do, it's pretty unlikely that we can rollback, hence we'll just accept the failure,
+ * and continue. */
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0)
+ log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
+ }
if (mm)
(void) munmap(mm, mm_size);
q += l;
}
- /* Skip preceeding whitespace */
+ /* Skip preceding whitespace */
l = strspn(q, WHITESPACE);
if (l < 1)
return -EINVAL;
return p > 0;
}
-static inline int sched_policy_to_string_alloc_with_check(int n, char **s) {
- if (!sched_policy_is_valid(n))
- return -EINVAL;
-
- return sched_policy_to_string_alloc(n, s);
-}
-
int ioprio_parse_priority(const char *s, int *ret);
pid_t getpid_cached(void);
}
/* Split a string into words. */
-const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
+const char* split(const char **state, size_t *l, const char *separator, SplitFlags flags) {
const char *current;
current = *state;
return NULL;
}
- if (quoted && strchr("\'\"", *current)) {
+ if (flags & SPLIT_QUOTES && strchr("\'\"", *current)) {
char quotechars[2] = {*current, '\0'};
*l = strcspn_escaped(current + 1, quotechars);
if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
(current[*l + 2] && !strchr(separator, current[*l + 2]))) {
/* right quote missing or garbage at the end */
+ if (flags & SPLIT_RELAX) {
+ *state = current + *l + 1 + (current[*l + 1] != '\0');
+ return current + 1;
+ }
*state = current;
return NULL;
}
*state = current++ + *l + 2;
- } else if (quoted) {
+ } else if (flags & SPLIT_QUOTES) {
*l = strcspn_escaped(current, separator);
- if (current[*l] && !strchr(separator, current[*l])) {
+ if (current[*l] && !strchr(separator, current[*l]) && !(flags & SPLIT_RELAX)) {
/* unfinished escape */
*state = current;
return NULL;
assert(p);
- /* Replaces a string pointer with an strdup()ed new string,
+ /* Replaces a string pointer with a strdup()ed new string,
* possibly freeing the old one. */
if (streq_ptr(*p, s))
return 1;
}
+int free_and_strndup(char **p, const char *s, size_t l) {
+ char *t;
+
+ assert(p);
+ assert(s || l == 0);
+
+ /* Replaces a string pointer with a strndup()ed new string,
+ * freeing the old one. */
+
+ if (!*p && !s)
+ return 0;
+
+ if (*p && s && strneq(*p, s, l) && (l > strlen(*p) || (*p)[l] == '\0'))
+ return 0;
+
+ if (s) {
+ t = strndup(s, l);
+ if (!t)
+ return -ENOMEM;
+ } else
+ t = NULL;
+
+ free_and_replace(*p, t);
+ return 1;
+}
+
#if !HAVE_EXPLICIT_BZERO
/*
* Pointer to memset is volatile so that compiler must de-reference
char *first_word(const char *s, const char *word) _pure_;
-const char* split(const char **state, size_t *l, const char *separator, bool quoted);
+typedef enum SplitFlags {
+ SPLIT_QUOTES = 0x01 << 0,
+ SPLIT_RELAX = 0x01 << 1,
+} SplitFlags;
+
+const char* split(const char **state, size_t *l, const char *separator, SplitFlags flags);
#define FOREACH_WORD(word, length, s, state) \
- _FOREACH_WORD(word, length, s, WHITESPACE, false, state)
+ _FOREACH_WORD(word, length, s, WHITESPACE, 0, state)
#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
- _FOREACH_WORD(word, length, s, separator, false, state)
+ _FOREACH_WORD(word, length, s, separator, 0, state)
-#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
- for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
+#define _FOREACH_WORD(word, length, s, separator, flags, state) \
+ for ((state) = (s), (word) = split(&(state), &(length), (separator), (flags)); (word); (word) = split(&(state), &(length), (separator), (flags)))
char *strappend(const char *s, const char *suffix);
char *strnappend(const char *s, const char *suffix, size_t length);
int split_pair(const char *s, const char *sep, char **l, char **r);
int free_and_strdup(char **p, const char *s);
+int free_and_strndup(char **p, const char *s, size_t l);
/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
return 0;
}
-char **strv_split(const char *s, const char *separator) {
+char **strv_split_full(const char *s, const char *separator, SplitFlags flags) {
const char *word, *state;
size_t l;
size_t n, i;
assert(s);
+ if (!separator)
+ separator = WHITESPACE;
+
s += strspn(s, separator);
if (isempty(s))
return new0(char*, 1);
n = 0;
- FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
+ _FOREACH_WORD(word, l, s, separator, flags, state)
n++;
r = new(char*, n+1);
return NULL;
i = 0;
- FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
+ _FOREACH_WORD(word, l, s, separator, flags, state) {
r[i] = strndup(word, l);
if (!r[i]) {
strv_free(r);
#include "alloc-util.h"
#include "extract-word.h"
#include "macro.h"
+#include "string-util.h"
#include "util.h"
char *strv_find(char **l, const char *name) _pure_;
return !l || !*l;
}
-char **strv_split(const char *s, const char *separator);
+char **strv_split_full(const char *s, const char *separator, SplitFlags flags);
+static inline char **strv_split(const char *s, const char *separator) {
+ return strv_split_full(s, separator, 0);
+}
char **strv_split_newlines(const char *s);
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
* Otherwise just cut it off. */
with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
- /* Cut off the timezone if we dont need it. */
+ /* Cut off the timezone if we don't need it. */
if (with_tz)
t = strndupa(t, last_space - t);
[SERVICE_EXITED] = "exited",
[SERVICE_RELOAD] = "reload",
[SERVICE_STOP] = "stop",
- [SERVICE_STOP_SIGABRT] = "stop-sigabrt",
+ [SERVICE_STOP_WATCHDOG] = "stop-watchdog",
[SERVICE_STOP_SIGTERM] = "stop-sigterm",
[SERVICE_STOP_SIGKILL] = "stop-sigkill",
[SERVICE_STOP_POST] = "stop-post",
SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
SERVICE_RELOAD,
SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
- SERVICE_STOP_SIGABRT, /* Watchdog timeout */
+ SERVICE_STOP_WATCHDOG,
SERVICE_STOP_SIGTERM,
SERVICE_STOP_SIGKILL,
SERVICE_STOP_POST,
}
/* count of characters used to encode one unicode char */
-static int utf8_encoded_expected_len(const char *str) {
- unsigned char c;
+static size_t utf8_encoded_expected_len(const char *str) {
+ uint8_t c;
assert(str);
- c = (unsigned char) str[0];
+ c = (uint8_t) str[0];
if (c < 0x80)
return 1;
if ((c & 0xe0) == 0xc0)
/* decode one unicode char */
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
char32_t unichar;
- int len, i;
+ size_t len, i;
assert(str);
for (i = 1; i < len; i++) {
if (((char32_t)str[i] & 0xc0) != 0x80)
return -EINVAL;
+
unichar <<= 6;
unichar |= (char32_t)str[i] & 0x3f;
}
return true;
}
-const char *utf8_is_valid(const char *str) {
- const uint8_t *p;
+char *utf8_is_valid(const char *str) {
+ const char *p;
assert(str);
- for (p = (const uint8_t*) str; *p; ) {
+ p = str;
+ while (*p) {
int len;
- len = utf8_encoded_valid_unichar((const char *)p);
+ len = utf8_encoded_valid_unichar(p);
if (len < 0)
return NULL;
p += len;
}
- return str;
+ return (char*) str;
}
char *utf8_escape_invalid(const char *str) {
return 0;
}
-char *utf16_to_utf8(const void *s, size_t length) {
+char *utf16_to_utf8(const char16_t *s, size_t length /* bytes! */) {
const uint8_t *f;
char *r, *t;
- r = new(char, (length * 4 + 1) / 2 + 1);
+ assert(s);
+
+ /* Input length is in bytes, i.e. the shortest possible character takes 2 bytes. Each unicode character may
+ * take up to 4 bytes in UTF-8. Let's also account for a trailing NUL byte. */
+ if (length * 2 < length)
+ return NULL; /* overflow */
+
+ r = new(char, length * 2 + 1);
if (!r)
return NULL;
- f = s;
+ f = (const uint8_t*) s;
t = r;
- while (f < (const uint8_t*) s + length) {
+ while (f + 1 < (const uint8_t*) s + length) {
char16_t w1, w2;
/* see RFC 2781 section 2.2 */
if (!utf16_is_surrogate(w1)) {
t += utf8_encode_unichar(t, w1);
-
continue;
}
if (utf16_is_trailing_surrogate(w1))
- continue;
- else if (f >= (const uint8_t*) s + length)
+ continue; /* spurious trailing surrogate, ignore */
+
+ if (f + 1 >= (const uint8_t*) s + length)
break;
w2 = f[1] << 8 | f[0];
if (!utf16_is_trailing_surrogate(w2)) {
f -= 2;
- continue;
+ continue; /* surrogate missing its trailing surrogate, ignore */
}
t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2));
return r;
}
+size_t utf16_encode_unichar(char16_t *out, char32_t c) {
+
+ /* Note that this encodes as little-endian. */
+
+ switch (c) {
+
+ case 0 ... 0xd7ffU:
+ case 0xe000U ... 0xffffU:
+ out[0] = htole16(c);
+ return 1;
+
+ case 0x10000U ... 0x10ffffU:
+ c -= 0x10000U;
+ out[0] = htole16((c >> 10) + 0xd800U);
+ out[1] = htole16((c & 0x3ffU) + 0xdc00U);
+ return 2;
+
+ default: /* A surrogate (invalid) */
+ return 0;
+ }
+}
+
+char16_t *utf8_to_utf16(const char *s, size_t length) {
+ char16_t *n, *p;
+ size_t i;
+ int r;
+
+ assert(s);
+
+ n = new(char16_t, length + 1);
+ if (!n)
+ return NULL;
+
+ p = n;
+
+ for (i = 0; i < length;) {
+ char32_t unichar;
+ size_t e;
+
+ e = utf8_encoded_expected_len(s + i);
+ if (e <= 1) /* Invalid and single byte characters are copied as they are */
+ goto copy;
+
+ if (i + e > length) /* sequence longer than input buffer, then copy as-is */
+ goto copy;
+
+ r = utf8_encoded_to_unichar(s + i, &unichar);
+ if (r < 0) /* sequence invalid, then copy as-is */
+ goto copy;
+
+ p += utf16_encode_unichar(p, unichar);
+ i += e;
+ continue;
+
+ copy:
+ *(p++) = htole16(s[i++]);
+ }
+
+ *p = 0;
+ return n;
+}
+
+size_t char16_strlen(const char16_t *s) {
+ size_t n = 0;
+
+ assert(s);
+
+ while (*s != 0)
+ n++, s++;
+
+ return n;
+}
+
/* expected size used to encode one unicode char */
static int utf8_unichar_to_encoded_len(char32_t unichar) {
/* validate one encoded unicode char and return its length */
int utf8_encoded_valid_unichar(const char *str) {
- int len, i, r;
char32_t unichar;
+ size_t len, i;
+ int r;
assert(str);
return r;
/* check if encoded length matches encoded value */
- if (utf8_unichar_to_encoded_len(unichar) != len)
+ if (utf8_unichar_to_encoded_len(unichar) != (int) len)
return -EINVAL;
/* check if value has valid range */
if (!unichar_is_valid(unichar))
return -EINVAL;
- return len;
+ return (int) len;
}
size_t utf8_n_codepoints(const char *str) {
bool unichar_is_valid(char32_t c);
-const char *utf8_is_valid(const char *s) _pure_;
+char *utf8_is_valid(const char *s) _pure_;
char *ascii_is_valid(const char *s) _pure_;
char *ascii_is_valid_n(const char *str, size_t len);
char *utf8_escape_non_printable(const char *str);
size_t utf8_encode_unichar(char *out_utf8, char32_t g);
-char *utf16_to_utf8(const void *s, size_t length);
+size_t utf16_encode_unichar(char16_t *out, char32_t c);
+
+char *utf16_to_utf8(const char16_t *s, size_t length /* bytes! */);
+char16_t *utf8_to_utf16(const char *s, size_t length);
+
+size_t char16_strlen(const char16_t *s); /* returns the number of 16bit words in the string (not bytes!) */
int utf8_encoded_valid_unichar(const char *str);
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar);
static inline bool utf16_is_surrogate(char16_t c) {
- return (0xd800 <= c && c <= 0xdfff);
+ return c >= 0xd800U && c <= 0xdfffU;
}
static inline bool utf16_is_trailing_surrogate(char16_t c) {
- return (0xdc00 <= c && c <= 0xdfff);
+ return c >= 0xdc00U && c <= 0xdfffU;
}
static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail) {
- return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000;
+ return ((((char32_t) lead - 0xd800U) << 10) + ((char32_t) trail - 0xdc00U) + 0x10000U);
}
size_t utf8_n_codepoints(const char *str);
if conf.get('ENABLE_EFI') == 1 and get_option('gnu-efi') != 'false'
efi_cc = get_option('efi-cc')
+ if efi_cc.length() == 0
+ efi_cc = cc.cmd_array()
+ endif
efi_ld = get_option('efi-ld')
+ if efi_ld == ''
+ efi_ld = find_program('ld', required: true)
+ endif
efi_incdir = get_option('efi-includedir')
gnu_efi_path_arch = ''
efi_libdir = get_option('efi-libdir')
if efi_libdir == ''
- cmd = 'cd /usr/lib/$(@0@ -print-multi-os-directory) && pwd'.format(efi_cc)
- ret = run_command('sh', '-c', cmd)
+ ret = run_command(efi_cc + ['-print-multi-os-directory'])
if ret.returncode() == 0
- efi_libdir = ret.stdout().strip()
+ path = join_paths('/usr/lib', ret.stdout().strip())
+ ret = run_command('realpath', '-e', path)
+ if ret.returncode() == 0
+ efi_libdir = ret.stdout().strip()
+ endif
endif
endif
o_file = custom_target(file + '.o',
input : file,
output : file + '.o',
- command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@']
+ command : efi_cc + ['-c', '@INPUT@', '-o', '@OUTPUT@']
+ compile_args,
depend_files : efi_headers)
if (common_sources + systemd_boot_sources).contains(file)
endif
endforeach
- libgcc_file_name = run_command(efi_cc, '-print-libgcc-file-name').stdout().strip()
+ libgcc_file_name = run_command(efi_cc + ['-print-libgcc-file-name']).stdout().strip()
systemd_boot_efi_name = 'systemd-boot@0@.efi'.format(EFI_MACHINE_TYPE_NAME)
stub_efi_name = 'linux@0@.efi.stub'.format(EFI_MACHINE_TYPE_NAME)
no_undefined_symbols = find_program('no-undefined-symbols.sh')
GraphicsOutput->Mode->Info->VerticalResolution, 0);
/* EFI buffer */
- blt_size = dib->x * dib->y * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ blt_size = sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * dib->x * dib->y;
blt = AllocatePool(blt_size);
if (!blt)
return EFI_OUT_OF_RESOURCES;
if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
return 0;
- r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
#if HAVE_SECCOMP
static BUS_DEFINE_SET_TRANSIENT_IS_VALID(errno, "i", int32_t, int, "%" PRIi32, errno_is_valid);
#endif
-static BUS_DEFINE_SET_TRANSIENT_IS_VALID(sched_priority, "i", int32_t, int, "%" PRIi32, sched_priority_is_valid);
-static BUS_DEFINE_SET_TRANSIENT_IS_VALID(nice, "i", int32_t, int, "%" PRIi32, nice_is_valid);
static BUS_DEFINE_SET_TRANSIENT_PARSE(std_input, ExecInput, exec_input_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(std_output, ExecOutput, exec_output_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(utmp_mode, ExecUtmpMode, exec_utmp_mode_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE_PTR(personality, unsigned long, parse_personality);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(secure_bits, "i", int32_t, int, "%" PRIi32, secure_bits_to_string_alloc_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(capability, "t", uint64_t, uint64_t, "%" PRIu64, capability_set_to_string_alloc);
-static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(sched_policy, "i", int32_t, int, "%" PRIi32, sched_policy_to_string_alloc_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(namespace_flag, "t", uint64_t, unsigned long, "%" PRIu64, namespace_flags_to_string);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(mount_flags, "t", uint64_t, unsigned long, "%" PRIu64, mount_propagation_flags_to_string_with_check);
if (streq(name, "LogLevelMax"))
return bus_set_transient_log_level(u, name, &c->log_level_max, message, flags, error);
- if (streq(name, "CPUSchedulingPriority"))
- return bus_set_transient_sched_priority(u, name, &c->cpu_sched_priority, message, flags, error);
-
if (streq(name, "Personality"))
return bus_set_transient_personality(u, name, &c->personality, message, flags, error);
- if (streq(name, "Nice"))
- return bus_set_transient_nice(u, name, &c->nice, message, flags, error);
-
if (streq(name, "StandardInput"))
return bus_set_transient_std_input(u, name, &c->std_input, message, flags, error);
if (streq(name, "AmbientCapabilities"))
return bus_set_transient_capability(u, name, &c->capability_ambient_set, message, flags, error);
- if (streq(name, "CPUSchedulingPolicy"))
- return bus_set_transient_sched_policy(u, name, &c->cpu_sched_policy, message, flags, error);
-
if (streq(name, "RestrictNamespaces"))
return bus_set_transient_namespace_flag(u, name, &c->restrict_namespaces, message, flags, error);
return 1;
+ } else if (streq(name, "Nice")) {
+ int32_t q;
+
+ r = sd_bus_message_read(message, "i", &q);
+ if (r < 0)
+ return r;
+
+ if (!nice_is_valid(q))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Nice value: %i", q);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ c->nice = q;
+ c->nice_set = true;
+
+ unit_write_settingf(u, flags, name, "Nice=%i", q);
+ }
+
+ return 1;
+
+ } else if (streq(name, "CPUSchedulingPolicy")) {
+ int32_t q;
+
+ r = sd_bus_message_read(message, "i", &q);
+ if (r < 0)
+ return r;
+
+ if (!sched_policy_is_valid(q))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling policy: %i", q);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ _cleanup_free_ char *s = NULL;
+
+ r = sched_policy_to_string_alloc(q, &s);
+ if (r < 0)
+ return r;
+
+ c->cpu_sched_policy = q;
+ c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(q), sched_get_priority_max(q));
+ c->cpu_sched_set = true;
+
+ unit_write_settingf(u, flags, name, "CPUSchedulingPolicy=%s", s);
+ }
+
+ return 1;
+
+ } else if (streq(name, "CPUSchedulingPriority")) {
+ int32_t p, min, max;
+
+ r = sd_bus_message_read(message, "i", &p);
+ if (r < 0)
+ return r;
+
+ min = sched_get_priority_min(c->cpu_sched_policy);
+ max = sched_get_priority_max(c->cpu_sched_policy);
+ if (p < min || p > max)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling priority: %i", p);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ c->cpu_sched_priority = p;
+ c->cpu_sched_set = true;
+
+ unit_write_settingf(u, flags, name, "CPUSchedulingPriority=%i", p);
+ }
+
+ return 1;
+
} else if (streq(name, "IOSchedulingClass")) {
int32_t q;
SD_BUS_PROPERTY("FinalKillSignal", "i", bus_property_get_int, offsetof(KillContext, final_kill_signal), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SendSIGKILL", "b", bus_property_get_bool, offsetof(KillContext, send_sigkill), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SendSIGHUP", "b", bus_property_get_bool, offsetof(KillContext, send_sighup), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("WatchdogSignal", "i", bus_property_get_int, offsetof(KillContext, watchdog_signal), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
static BUS_DEFINE_SET_TRANSIENT_PARSE(kill_mode, KillMode, kill_mode_from_string);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(final_kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
+static BUS_DEFINE_SET_TRANSIENT_TO_STRING(watchdog_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
int bus_kill_context_set_transient_property(
Unit *u,
if (streq(name, "FinalKillSignal"))
return bus_set_transient_final_kill_signal(u, name, &c->final_kill_signal, message, flags, error);
+ if (streq(name, "WatchdogSignal"))
+ return bus_set_transient_watchdog_signal(u, name, &c->watchdog_signal, message, flags, error);
+
return 0;
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
_cleanup_free_ char *label = NULL;
- r = unit_add_dependency_by_name(u, d, other, NULL, true, UNIT_DEPENDENCY_FILE);
+ r = unit_add_dependency_by_name(u, d, other, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word);
}
- r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true, UNIT_DEPENDENCY_UDEV);
+ r = unit_add_dependency_by_name(u, UNIT_WANTS, k, true, UNIT_DEPENDENCY_UDEV);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to add Wants= dependency: %m");
return r;
}
- return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_filter, action);
+ return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_filter, action, false);
}
static int apply_syscall_archs(const Unit *u, const ExecContext *c) {
if (skip_seccomp_unavailable(u, "ProtectKernelModules="))
return 0;
- return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_MODULE, SCMP_ACT_ERRNO(EPERM));
+ return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_MODULE, SCMP_ACT_ERRNO(EPERM), false);
}
static int apply_private_devices(const Unit *u, const ExecContext *c) {
if (skip_seccomp_unavailable(u, "PrivateDevices="))
return 0;
- return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO, SCMP_ACT_ERRNO(EPERM));
+ return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO, SCMP_ACT_ERRNO(EPERM), false);
}
static int apply_restrict_namespaces(const Unit *u, const ExecContext *c) {
c->final_kill_signal = SIGKILL;
c->send_sigkill = true;
c->send_sighup = false;
+ c->watchdog_signal = SIGABRT;
}
void kill_context_dump(KillContext *c, FILE *f, const char *prefix) {
int final_kill_signal;
bool send_sigkill;
bool send_sighup;
+ int watchdog_signal;
};
typedef enum KillWho {
log_unit_warning(u, "%s dependency dropin %s target %s has different name",
unit_dependency_to_string(dependency), *p, target);
- r = unit_add_dependency_by_name(u, dependency, entry, *p, true, UNIT_DEPENDENCY_FILE);
+ r = unit_add_dependency_by_name(u, dependency, entry, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_unit_warning_errno(u, r, "Cannot add %s dependency on %s, ignoring: %m",
unit_dependency_to_string(dependency), entry);
$1.SendSIGHUP, config_parse_bool, 0, offsetof($1, kill_context.send_sighup)
$1.KillMode, config_parse_kill_mode, 0, offsetof($1, kill_context.kill_mode)
$1.KillSignal, config_parse_signal, 0, offsetof($1, kill_context.kill_signal)
-$1.FinalKillSignal, config_parse_signal, 0, offsetof($1, kill_context.final_kill_signal)'
+$1.FinalKillSignal, config_parse_signal, 0, offsetof($1, kill_context.final_kill_signal)
+$1.WatchdogSignal, config_parse_signal, 0, offsetof($1, kill_context.watchdog_signal)'
)m4_dnl
m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS',
`$1.Slice, config_parse_unit_slice, 0, 0
continue;
}
- r = unit_add_dependency_by_name(u, d, k, NULL, true, UNIT_DEPENDENCY_FILE);
+ r = unit_add_dependency_by_name(u, d, k, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
return 0;
}
- r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true, UNIT_DEPENDENCY_FILE);
+ r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, true, UNIT_DEPENDENCY_FILE);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
return 0;
continue;
}
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true, UNIT_DEPENDENCY_FILE);
+ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
- r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true, UNIT_DEPENDENCY_FILE);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
m->uid_refs = hashmap_free(m->uid_refs);
m->gid_refs = hashmap_free(m->gid_refs);
- q = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
- if (q < 0 && r >= 0)
- r = q;
+ r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
q = manager_run_environment_generators(m);
if (q < 0 && r >= 0)
mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT;
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true, mask);
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, true, mask);
if (r < 0)
return r;
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true, mask);
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, true, mask);
if (r < 0)
return r;
* network.target, so that they are shut down only
* after this mount unit is stopped. */
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true, mask);
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, true, mask);
if (r < 0)
return r;
* whose purpose it is to delay this until the network
* is "up". */
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true, mask);
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, true, mask);
if (r < 0)
return r;
} else
after = SPECIAL_LOCAL_FS_PRE_TARGET;
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true, mask);
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask);
if (r < 0)
return r;
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, mask);
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, mask);
if (r < 0)
return r;
/* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */
if (streq_ptr(p->fstype, "tmpfs")) {
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, NULL, true, mask);
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, true, mask);
if (r < 0)
return r;
}
int r;
target = mount_is_network(p) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
- r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
+ r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
if (r < 0)
return r;
- r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
+ r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
if (r < 0)
return r;
}
* in the dependency "Set*" objects who created a
* dependency), we can only add deps, never lose them,
* until the next full daemon-reload. */
- unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
+ unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
load_extras = true;
}
if (!UNIT(p)->default_dependencies)
return 0;
- r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) {
- r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
- return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
}
static int path_add_trigger_dependencies(Path *p) {
r = unit_add_two_dependencies_by_name(
UNIT(s),
UNIT_BEFORE, UNIT_CONFLICTS,
- SPECIAL_SHUTDOWN_TARGET, NULL, true,
+ SPECIAL_SHUTDOWN_TARGET, true,
UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
[SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_RELOAD] = UNIT_RELOADING,
[SERVICE_STOP] = UNIT_DEACTIVATING,
- [SERVICE_STOP_SIGABRT] = UNIT_DEACTIVATING,
+ [SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
[SERVICE_STOP_POST] = UNIT_DEACTIVATING,
[SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_RELOAD] = UNIT_RELOADING,
[SERVICE_STOP] = UNIT_DEACTIVATING,
- [SERVICE_STOP_SIGABRT] = UNIT_DEACTIVATING,
+ [SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
[SERVICE_STOP_POST] = UNIT_DEACTIVATING,
* require it, so that we fail if we can't acquire
* it. */
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
} else {
/* In the --user instance there's no sysinit.target,
* in that case require basic.target instead. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
/* Second, if the rest of the base system is in the same
* transaction, order us after it, but do not pull it in or
* even require it. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
/* Third, add us in for normal shutdown. */
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
}
static void service_fix_output(Service *s) {
if (!s->bus_name)
return 0;
- r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
/* We always want to be ordered against dbus.socket if both are in the transaction. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_AUTO_RESTART))
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
if (!IN_SET(state,
SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
service_unwatch_main_pid(s);
s->main_command = NULL;
if (!IN_SET(state,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
service_unwatch_control_pid(s);
s->control_command = NULL;
if (!IN_SET(state,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
!(state == SERVICE_DEAD && UNIT(s)->job))
service_close_socket_fd(s);
return usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec);
case SERVICE_STOP:
- case SERVICE_STOP_SIGABRT:
+ case SERVICE_STOP_WATCHDOG:
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
case SERVICE_STOP_POST:
(IN_SET(s->deserialized_state,
SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
r = unit_watch_pid(UNIT(s), s->main_pid);
if (r < 0)
IN_SET(s->deserialized_state,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
r = unit_watch_pid(UNIT(s), s->control_pid);
if (r < 0)
static int state_to_kill_operation(ServiceState state) {
switch (state) {
- case SERVICE_STOP_SIGABRT:
- return KILL_ABORT;
+ case SERVICE_STOP_WATCHDOG:
+ return KILL_WATCHDOG;
case SERVICE_STOP_SIGTERM:
case SERVICE_FINAL_SIGTERM:
goto fail;
service_set_state(s, state);
- } else if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM) && s->kill_context.send_sigkill)
+ } else if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM) && s->kill_context.send_sigkill)
service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_SUCCESS);
- else if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
+ else if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
service_enter_stop_post(s, SERVICE_SUCCESS);
else if (state == SERVICE_FINAL_SIGTERM && s->kill_context.send_sigkill)
service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
fail:
log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
- if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
+ if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES);
else
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
/* We cannot fulfill this request right now, try again later
* please! */
if (IN_SET(s->state,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
return -EAGAIN;
/* Already on it */
if (IN_SET(s->state,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
return 0;
service_enter_running(s, SERVICE_SUCCESS);
break;
- case SERVICE_STOP_SIGABRT:
+ case SERVICE_STOP_WATCHDOG:
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
service_enter_running(s, f);
break;
- case SERVICE_STOP_SIGABRT:
+ case SERVICE_STOP_WATCHDOG:
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
break;
- case SERVICE_STOP_SIGABRT:
+ case SERVICE_STOP_WATCHDOG:
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
if (main_pid_good(s) <= 0)
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
- case SERVICE_STOP_SIGABRT:
- log_unit_warning(UNIT(s), "State 'stop-sigabrt' timed out. Terminating.");
+ case SERVICE_STOP_WATCHDOG:
+ log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Terminating.");
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
log_unit_error(UNIT(s), "Watchdog timeout (limit %s)!",
format_timespan(t, sizeof(t), watchdog_usec, 1));
- service_enter_signal(s, SERVICE_STOP_SIGABRT, SERVICE_FAILURE_WATCHDOG);
+ service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_WATCHDOG);
} else
log_unit_warning(UNIT(s), "Watchdog disabled! Ignoring watchdog timeout (limit %s)!",
format_timespan(t, sizeof(t), watchdog_usec, 1));
SERVICE_RUNNING,
SERVICE_RELOAD,
SERVICE_STOP,
- SERVICE_STOP_SIGABRT,
+ SERVICE_STOP_WATCHDOG,
SERVICE_STOP_SIGTERM,
SERVICE_STOP_SIGKILL,
SERVICE_STOP_POST,
r = unit_add_two_dependencies_by_name(
UNIT(s),
UNIT_BEFORE, UNIT_CONFLICTS,
- SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
if (!UNIT(s)->default_dependencies)
return 0;
- r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
}
_pure_ static bool socket_has_exec(Socket *s) {
/* File based swap devices need to be ordered after
* systemd-remount-fs.service, since they might need a
* writable file system. */
- return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true, UNIT_DEPENDENCY_FILE);
+ return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, true, UNIT_DEPENDENCY_FILE);
}
static int swap_add_default_dependencies(Swap *s) {
/* swap units generated for the swap dev links are missing the
* ordering dep against the swap target. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
}
static int swap_verify(Swap *s) {
return 0;
/* Make sure targets are unloaded on shutdown */
- return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
}
static int target_load(Unit *u) {
if (!UNIT(t)->default_dependencies)
return 0;
- r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
- r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
LIST_FOREACH(value, v, t->values) {
if (v->base == TIMER_CALENDAR) {
- r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
break;
}
}
- return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+ return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
}
static int timer_add_trigger_dependencies(Timer *t) {
return r;
}
- r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_TMPFILES_SETUP_SERVICE, NULL, true, UNIT_DEPENDENCY_FILE);
+ r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_TMPFILES_SETUP_SERVICE, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
/* If syslog or kernel logging is requested, make sure our own
* logging daemon is run first. */
- r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE);
+ r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
if (unit_has_name(u, SPECIAL_ROOT_SLICE))
return 0;
- return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, NULL, true, mask);
+ return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, true, mask);
}
static int unit_add_mount_dependencies(Unit *u) {
return unit_add_dependency(u, e, other, add_reference, mask);
}
-static int resolve_template(Unit *u, const char *name, const char*path, char **buf, const char **ret) {
+static int resolve_template(Unit *u, const char *name, char **buf, const char **ret) {
int r;
assert(u);
- assert(name || path);
+ assert(name);
assert(buf);
assert(ret);
- if (!name)
- name = basename(path);
-
if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
*buf = NULL;
*ret = name;
return 0;
}
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference, UnitDependencyMask mask) {
+int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, bool add_reference, UnitDependencyMask mask) {
_cleanup_free_ char *buf = NULL;
Unit *other;
int r;
assert(u);
- assert(name || path);
+ assert(name);
- r = resolve_template(u, name, path, &buf, &name);
+ r = resolve_template(u, name, &buf, &name);
if (r < 0)
return r;
- r = manager_load_unit(u->manager, name, path, NULL, &other);
+ r = manager_load_unit(u->manager, name, NULL, NULL, &other);
if (r < 0)
return r;
return unit_add_dependency(u, d, other, add_reference, mask);
}
-int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference, UnitDependencyMask mask) {
+int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, bool add_reference, UnitDependencyMask mask) {
_cleanup_free_ char *buf = NULL;
Unit *other;
int r;
assert(u);
- assert(name || path);
+ assert(name);
- r = resolve_template(u, name, path, &buf, &name);
+ r = resolve_template(u, name, &buf, &name);
if (r < 0)
return r;
- r = manager_load_unit(u->manager, name, path, NULL, &other);
+ r = manager_load_unit(u->manager, name, NULL, NULL, &other);
if (r < 0)
return r;
case KILL_KILL:
return c->final_kill_signal;
- case KILL_ABORT:
- return SIGABRT;
+ case KILL_WATCHDOG:
+ return c->watchdog_signal;
default:
assert_not_reached("KillOperation unknown");
KILL_TERMINATE,
KILL_TERMINATE_AND_LOG,
KILL_KILL,
- KILL_ABORT,
+ KILL_WATCHDOG,
_KILL_OPERATION_MAX,
_KILL_OPERATION_INVALID = -1
} KillOperation;
int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference, UnitDependencyMask mask);
int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference, UnitDependencyMask mask);
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference, UnitDependencyMask mask);
-int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference, UnitDependencyMask mask);
+int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, bool add_reference, UnitDependencyMask mask);
+int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, bool add_reference, UnitDependencyMask mask);
int unit_add_exec_dependencies(Unit *u, ExecContext *c);
return log_oom();
}
- if (keydev && !password)
- return log_error_errno(-EINVAL, "Keydev is specified, but path to the password file is missing: %m");
+ if (keydev && !password) {
+ log_error("Key device is specified, but path to the password file is missing.");
+ return -EINVAL;
+ }
r = generator_open_unit_file(arg_dest, NULL, n, &f);
if (r < 0)
netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
if (password) {
- if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random"))
+ if (PATH_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random"))
fputs("After=systemd-random-seed.service\n", f);
else if (!STR_IN_SET(password, "-", "none")) {
_cleanup_free_ char *uu;
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "alloc-util.h"
+#include "bus-dump.h"
+#include "bus-message.h"
+#include "env-util.h"
+#include "fd-util.h"
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ _cleanup_free_ char *out = NULL; /* out should be freed after g */
+ size_t out_size;
+ _cleanup_fclose_ FILE *g = NULL;
+ _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_free_ void *buffer = NULL;
+ int r;
+
+ /* We don't want to fill the logs with messages about parse errors.
+ * Disable most logging if not running standalone */
+ if (!getenv("SYSTEMD_LOG_LEVEL"))
+ log_set_max_level(LOG_CRIT);
+
+ r = sd_bus_new(&bus);
+ assert_se(r >= 0);
+
+ assert_se(buffer = memdup(data, size));
+
+ r = bus_message_from_malloc(bus, buffer, size, NULL, 0, NULL, &m);
+ if (r == -EBADMSG)
+ return 0;
+ assert_se(r >= 0);
+ TAKE_PTR(buffer);
+
+ if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0)
+ assert_se(g = open_memstream(&out, &out_size));
+
+ bus_message_dump(m, g ?: stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
+
+ r = sd_bus_message_rewind(m, true);
+ assert_se(r >= 0);
+
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <unistd.h>
+
+#include "sd-dhcp6-client.h"
+#include "sd-event.h"
+
+#include "dhcp6-internal.h"
+#include "dhcp6-protocol.h"
+#include "fd-util.h"
+#include "fuzz.h"
+
+static int test_dhcp_fd[2];
+
+int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
+ const void *packet, size_t len) {
+ return len;
+}
+
+int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
+ assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) >= 0);
+ return test_dhcp_fd[0];
+}
+
+static void fuzz_client(const uint8_t *data, size_t size, bool is_information_request_enabled) {
+ _cleanup_(sd_event_unrefp) sd_event *e;
+ _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
+ struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
+
+ assert_se(sd_event_new(&e) >= 0);
+ assert_se(sd_dhcp6_client_new(&client) >= 0);
+ assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
+ assert_se(sd_dhcp6_client_set_ifindex(client, 42) == 0);
+ assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
+ assert_se(sd_dhcp6_client_set_information_request(client, is_information_request_enabled) == 0);
+
+ assert_se(sd_dhcp6_client_start(client) >= 0);
+
+ if (size >= sizeof(DHCP6Message))
+ assert_se(sd_dhcp6_client_set_transaction_id(client, htobe32(0x00ffffff) & ((const DHCP6Message *) data)->transaction_id) == 0);
+
+ assert_se(write(test_dhcp_fd[1], data, size) == (ssize_t) size);
+
+ sd_event_run(e, (uint64_t) -1);
+
+ assert_se(sd_dhcp6_client_stop(client) >= 0);
+
+ test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ /* This triggers client_receive_advertise */
+ fuzz_client(data, size, false);
+
+ /* This triggers client_receive_reply */
+ fuzz_client(data, size, true);
+
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <netinet/icmp6.h>
+#include <arpa/inet.h>
+
+#include "alloc-util.h"
+#include "icmp6-util.h"
+#include "fuzz.h"
+#include "sd-ndisc.h"
+#include "socket-util.h"
+#include "ndisc-internal.h"
+
+static int test_fd[2];
+
+int icmp6_bind_router_solicitation(int index) {
+ assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) >= 0);
+ return test_fd[0];
+}
+
+int icmp6_bind_router_advertisement(int index) {
+ return -ENOSYS;
+}
+
+int icmp6_receive(int fd, void *iov_base, size_t iov_len,
+ struct in6_addr *dst, triple_timestamp *timestamp) {
+ assert_se(read(fd, iov_base, iov_len) == (ssize_t) iov_len);
+
+ if (timestamp)
+ triple_timestamp_get(timestamp);
+
+ return 0;
+}
+
+int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ struct ether_addr mac_addr = {
+ .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
+ };
+ _cleanup_(sd_event_unrefp) sd_event *e = NULL;
+ _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
+
+ assert_se(sd_event_new(&e) >= 0);
+ assert_se(sd_ndisc_new(&nd) >= 0);
+ assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
+ assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
+ assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
+ assert_se(sd_ndisc_start(nd) >= 0);
+ assert_se(write(test_fd[1], data, size) == (ssize_t) size);
+ (void) sd_event_run(e, (uint64_t) -1);
+ assert_se(sd_ndisc_stop(nd) >= 0);
+ close(test_fd[1]);
+
+ return 0;
+}
# SPDX-License-Identifier: LGPL-2.1+
fuzzers += [
+ [['src/fuzz/fuzz-bus-message.c'],
+ [libshared],
+ []],
+
[['src/fuzz/fuzz-dns-packet.c',
dns_type_headers],
[libsystemd_resolve_core,
libgpg_error,
libm]],
+ [['src/fuzz/fuzz-dhcp6-client.c',
+ 'src/libsystemd-network/dhcp-identifier.h',
+ 'src/libsystemd-network/dhcp-identifier.c',
+ 'src/libsystemd-network/dhcp6-internal.h',
+ 'src/systemd/sd-dhcp6-client.h'],
+ [libshared,
+ libsystemd_network],
+ []],
+
[['src/fuzz/fuzz-dhcp-server.c'],
[libsystemd_network,
libshared],
[]],
+ [['src/fuzz/fuzz-ndisc-rs.c',
+ 'src/libsystemd-network/dhcp-identifier.h',
+ 'src/libsystemd-network/dhcp-identifier.c',
+ 'src/libsystemd-network/icmp6-util.h',
+ 'src/systemd/sd-dhcp6-client.h',
+ 'src/systemd/sd-ndisc.h'],
+ [libshared,
+ libsystemd_network],
+ []],
+
[['src/fuzz/fuzz-unit-file.c'],
[libcore,
libshared],
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+#include <stdio.h>
+
+#include "alloc-util.h"
+#include "id128-print.h"
+#include "terminal-util.h"
+#include "util.h"
+#include "verbs.h"
+
+static bool arg_pretty = false;
+static sd_id128_t arg_app = {};
+
+static int verb_new(int argc, char **argv, void *userdata) {
+ return id128_print_new(arg_pretty);
+}
+
+static int verb_machine_id(int argc, char **argv, void *userdata) {
+ sd_id128_t id;
+ int r;
+
+ if (sd_id128_is_null(arg_app))
+ r = sd_id128_get_machine(&id);
+ else
+ r = sd_id128_get_machine_app_specific(arg_app, &id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get %smachine-ID: %m",
+ sd_id128_is_null(arg_app) ? "" : "app-specific ");
+
+ return id128_pretty_print(id, arg_pretty);
+}
+
+static int verb_boot_id(int argc, char **argv, void *userdata) {
+ sd_id128_t id;
+ int r;
+
+ if (sd_id128_is_null(arg_app))
+ r = sd_id128_get_boot(&id);
+ else
+ r = sd_id128_get_boot_app_specific(arg_app, &id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get %sboot-ID: %m",
+ sd_id128_is_null(arg_app) ? "" : "app-specific ");
+
+ return id128_pretty_print(id, arg_pretty);
+}
+
+static int verb_invocation_id(int argc, char **argv, void *userdata) {
+ sd_id128_t id;
+ int r;
+
+ if (!sd_id128_is_null(arg_app))
+ return log_error_errno(EINVAL, "Verb \"invocation-id\" cannot be combined with --app-specific=.");
+
+ r = sd_id128_get_invocation(&id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get invocation-ID: %m");
+
+ return id128_pretty_print(id, arg_pretty);
+}
+
+static int help(void) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ r = terminal_urlify_man("systemd-id128", "1", &link);
+ if (r < 0)
+ return log_oom();
+
+ printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+ "Generate and print id128 strings.\n\n"
+ " -h --help Show this help\n\n"
+ " -p --pretty Generate samples of program code\n\n"
+ " -a --app-specific=ID Generate app-specific IDs\n\n"
+ "Commands:\n"
+ " new Generate a new id128 string\n"
+ " machine-id Print the ID of current machine\n"
+ " boot-id Print the ID of current boot\n"
+ " invocation-id Print the ID of current invocation\n"
+ " help Show this help\n"
+ "\nSee the %s for details.\n"
+ , program_invocation_short_name
+ , link
+ );
+
+ return 0;
+}
+
+static int verb_help(int argc, char **argv, void *userdata) {
+ return help();
+}
+
+static int parse_argv(int argc, char *argv[]) {
+ enum {
+ ARG_VERSION = 0x100,
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "app-specific", required_argument, NULL, 'a' },
+ {},
+ };
+
+ int c, r;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "hpa:", options, NULL)) >= 0)
+ switch (c) {
+
+ case 'h':
+ return help();
+
+ case ARG_VERSION:
+ return version();
+
+ case 'p':
+ arg_pretty = true;
+ break;
+
+ case 'a':
+ r = sd_id128_from_string(optarg, &arg_app);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse \"%s\" as application-ID: %m", optarg);
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached("Unhandled option");
+ }
+
+ return 1;
+}
+
+static int id128_main(int argc, char *argv[]) {
+ static const Verb verbs[] = {
+ { "new", VERB_ANY, 1, 0, verb_new },
+ { "machine-id", VERB_ANY, 1, 0, verb_machine_id },
+ { "boot-id", VERB_ANY, 1, 0, verb_boot_id },
+ { "invocation-id", VERB_ANY, 1, 0, verb_invocation_id },
+ { "help", VERB_ANY, VERB_ANY, 0, verb_help },
+ {}
+ };
+
+ return dispatch_verb(argc, argv, verbs, NULL);
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+
+ log_parse_environment();
+ log_open();
+
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ goto finish;
+
+ r = id128_main(argc, argv);
+
+ finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
n = sparse_write(i->output_fd, p, sz, 64);
if (n < 0)
- return -errno;
+ return (int) n;
if ((size_t) n < sz)
return -EIO;
if (j->allow_sparse)
n = sparse_write(j->disk_fd, p, sz, 64);
- else
+ else {
n = write(j->disk_fd, p, sz);
+ if (n < 0)
+ n = -errno;
+ }
if (n < 0)
- return log_error_errno(errno, "Failed to write file: %m");
+ return log_error_errno((int) n, "Failed to write file: %m");
if ((size_t) n < sz) {
log_error("Short write");
return -EIO;
r = snprintf(buf + pos, size - pos,
"__CURSOR=%s\n", u->current_cursor);
- if (pos + r > size)
+ assert(r >= 0);
+ if ((size_t) r > size - pos)
/* not enough space */
return pos;
r = snprintf(buf + pos, size - pos,
"__REALTIME_TIMESTAMP="USEC_FMT"\n", realtime);
- if (r + pos > size)
+ assert(r >= 0);
+ if ((size_t) r > size - pos)
/* not enough space */
return pos;
r = snprintf(buf + pos, size - pos,
"__MONOTONIC_TIMESTAMP="USEC_FMT"\n", monotonic);
- if (r + pos > size)
+ assert(r >= 0);
+ if ((size_t) r > size - pos)
/* not enough space */
return pos;
r = snprintf(buf + pos, size - pos,
"_BOOT_ID=%s\n", sd_id128_to_string(boot_id, sid));
- if (r + pos > size)
+ assert(r >= 0);
+ if ((size_t) r > size - pos)
/* not enough space */
return pos;
ssize_t r;
assert(u);
- assert(nmemb <= SSIZE_MAX / size);
+ assert(nmemb < SSIZE_MAX / size);
if (u->input < 0)
return 0;
}
static uint64_t scale_progress(uint64_t scale, uint64_t p, uint64_t m) {
+ /* Calculates scale * p / m, but handles m == 0 safely, and saturates.
+ * Currently all callers use m >= 1, but we keep the check to be defensive.
+ */
- /* Calculates scale * p / m, but handles m == 0 safely, and saturates */
-
- if (p >= m || m == 0)
+ if (p >= m || m == 0) /* lgtm [cpp/constant-comparison] */
return scale;
return scale * p / m;
#include "fsprg.h"
#include "glob-util.h"
#include "hostname-util.h"
+#include "id128-print.h"
#include "io-util.h"
#include "journal-def.h"
#include "journal-internal.h"
" --list-catalog Show all message IDs in the catalog\n"
" --dump-catalog Show entries in the message catalog\n"
" --update-catalog Update the message catalog database\n"
- " --new-id128 Generate a new 128-bit ID\n"
" --setup-keys Generate a new FSS key pair\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
{ "no-full", no_argument, NULL, ARG_NO_FULL },
{ "lines", optional_argument, NULL, 'n' },
{ "no-tail", no_argument, NULL, ARG_NO_TAIL },
- { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
+ { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, /* deprecated */
{ "quiet", no_argument, NULL, 'q' },
{ "merge", no_argument, NULL, 'm' },
{ "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */
return 1;
}
-static int generate_new_id128(void) {
- sd_id128_t id;
- int r;
- unsigned i;
-
- r = sd_id128_randomize(&id);
- if (r < 0)
- return log_error_errno(r, "Failed to generate ID: %m");
-
- printf("As string:\n"
- SD_ID128_FORMAT_STR "\n\n"
- "As UUID:\n"
- "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
- "As man:sd-id128(3) macro:\n"
- "#define MESSAGE_XYZ SD_ID128_MAKE(",
- SD_ID128_FORMAT_VAL(id),
- SD_ID128_FORMAT_VAL(id));
- for (i = 0; i < 16; i++)
- printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
- fputs(")\n\n", stdout);
-
- printf("As Python constant:\n"
- ">>> import uuid\n"
- ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
- SD_ID128_FORMAT_VAL(id));
-
- return 0;
-}
-
static int add_matches(sd_journal *j, char **args) {
char **i;
bool have_term = false;
switch (arg_action) {
case ACTION_NEW_ID128:
- r = generate_new_id128();
+ r = id128_print_new(true);
goto finish;
case ACTION_SETUP_KEYS:
static void test_syslog_parse_priority(const char *str, int priority, int ret) {
const char *buf = str;
- int priority2, ret2;
+ int priority2 = 0, ret2;
ret2 = syslog_parse_priority(&buf, &priority2, false);
assert(len);
r = sd_id128_get_machine(&machine_id);
- if (r < 0)
+ if (r < 0) {
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10);
+#else
return r;
+#endif
+ }
unaligned_write_be16(&duid->type, DUID_TYPE_EN);
unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN);
int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
size_t *optlen, uint8_t **optvalue);
-int dhcp6_option_parse_status(DHCP6Option *option);
+int dhcp6_option_parse_status(DHCP6Option *option, size_t len);
int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia);
int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
struct in6_addr **addrs, size_t count,
return 0;
}
-int dhcp6_option_parse_status(DHCP6Option *option) {
+int dhcp6_option_parse_status(DHCP6Option *option, size_t len) {
DHCP6StatusOption *statusopt = (DHCP6StatusOption *)option;
- if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*statusopt))
+ if (len < sizeof(DHCP6StatusOption) ||
+ be16toh(option->len) + sizeof(DHCP6Option) < sizeof(DHCP6StatusOption))
return -ENOBUFS;
return be16toh(statusopt->status);
}
if (be16toh(option->len) + sizeof(DHCP6Option) > sizeof(*addr_option)) {
- r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options);
+ r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options, be16toh(option->len) + sizeof(DHCP6Option) - sizeof(*addr_option));
if (r != 0)
return r < 0 ? r: 0;
}
}
if (be16toh(option->len) + sizeof(DHCP6Option) > sizeof(*pdprefix_option)) {
- r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options);
+ r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options, be16toh(option->len) + sizeof(DHCP6Option) - sizeof(*pdprefix_option));
if (r != 0)
return r < 0 ? r: 0;
}
case SD_DHCP6_OPTION_STATUS_CODE:
- status = dhcp6_option_parse_status(option);
+ status = dhcp6_option_parse_status(option, optlen);
if (status) {
log_dhcp6_client(client, "IA status %d",
status);
/* Literal label */
label = (const char *)&optval[pos];
pos += c;
- if (pos > optlen)
+ if (pos >= optlen)
return -EMSGSIZE;
if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) {
iov.iov_len = size;
len = recvmsg(fd, &msg, MSG_DONTWAIT);
- if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
- return 0;
-
+ if (len < 0)
return -errno;
- }
if ((size_t) len != size)
return -EINVAL;
if (has_mtu) {
log_ndisc("MTU option specified twice, ignoring.");
- continue;
+ break;
}
if (length != 8) {
if (has_flag_extension) {
log_ndisc("Flags extension option specified twice, ignoring.");
- continue;
+ break;
}
if (length < 1*8) {
#define log_radv_full(level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "RADV: " fmt, ##__VA_ARGS__)
#define log_radv_errno(error, fmt, ...) log_radv_full(LOG_DEBUG, error, fmt, ##__VA_ARGS__)
-#define log_radv_warning_errno(error, fmt, ...) log_radv_full(LOG_WARNING, error, fmt, ##__VA_ARGS__)
#define log_radv(fmt, ...) log_radv_errno(0, fmt, ##__VA_ARGS__)
let the server know how large the server may make its DHCP messages.
Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
- than the defined default size unless the Maximum Messge Size option
+ than the defined default size unless the Maximum Message Size option
is explicitly set
RFC3442 "Requirements to Avoid Sizing Constraints":
free(option);
}
+ free(lease->root_path);
+ free(lease->timezone);
free(lease->hostname);
free(lease->domainname);
free(lease->dns);
if (!string)
return -ENOMEM;
- free(*ret);
- *ret = string;
+ free_and_replace(*ret, string);
}
return 0;
DHCP6IA ia_pd;
sd_event_source *timeout_t1;
sd_event_source *timeout_t2;
- int request;
+ unsigned request;
be32_t transaction_id;
usec_t transaction_start;
struct sd_dhcp6_lease *lease;
return 0;
}
+int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transaction_id) {
+ assert_return(client, -EINVAL);
+
+ client->transaction_id = transaction_id;
+
+ return 0;
+}
+
int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
assert_return(client, -EINVAL);
client->callback(client, event, client->userdata);
}
-static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
- assert(client);
-
- (void) sd_dhcp6_lease_unref(client->lease);
- client->lease = sd_dhcp6_lease_ref(lease);
-}
-
static int client_reset(sd_dhcp6_client *client) {
assert(client);
- client_set_lease(client, NULL);
+ client->lease = sd_dhcp6_lease_unref(client->lease);
client->receive_message =
sd_event_source_unref(client->receive_message);
client->timeout_resend_expire =
sd_event_source_unref(client->timeout_resend_expire);
+ client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
+ client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
+
client->state = DHCP6_STATE_STOPPED;
return 0;
uint8_t *optval;
be32_t iaid_lease;
- if (len < offsetof(DHCP6Option, data) ||
- len < offsetof(DHCP6Option, data) + be16toh(option->len))
+ if (len < pos + offsetof(DHCP6Option, data) ||
+ len < pos + offsetof(DHCP6Option, data) + be16toh(option->len))
return -ENOBUFS;
optcode = be16toh(option->code);
break;
case SD_DHCP6_OPTION_STATUS_CODE:
- status = dhcp6_option_parse_status(option);
+ status = dhcp6_option_parse_status(option, optlen);
if (status) {
log_dhcp6_client(client, "%s Status %s",
dhcp6_message_type_to_string(message->type),
break;
}
- pos += sizeof(*option) + optlen;
+ pos += offsetof(DHCP6Option, data) + optlen;
}
if (!clientid) {
return 0;
}
- client_set_lease(client, lease);
- lease = NULL;
+ sd_dhcp6_lease_unref(client->lease);
+ client->lease = TAKE_PTR(lease);
return DHCP6_STATE_BOUND;
}
r = dhcp6_lease_get_preference(client->lease, &pref_lease);
if (r < 0 || pref_advertise > pref_lease) {
- client_set_lease(client, lease);
- lease = NULL;
+ sd_dhcp6_lease_unref(client->lease);
+ client->lease = TAKE_PTR(lease);
r = 0;
}
}
if (lldp_neighbor_equal(n, old)) {
- /* Is this equal, then restart the TTL counter, but don't do anyting else. */
+ /* Is this equal, then restart the TTL counter, but don't do anything else. */
old->timestamp = n->timestamp;
lldp_start_timer(lldp, old);
lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old);
break;
case -EPFNOSUPPORT:
- log_ndisc("Received invalid source address from ICMPv6 socket.");
+ log_ndisc("Received invalid source address from ICMPv6 socket. Ignoring.");
+ break;
+
+ case -EAGAIN: /* ignore spurious wakeups */
+ break;
+
+ default:
+ log_ndisc_errno(r, "Unexpected error while reading from ICMPv6, ignoring: %m");
break;
}
log_radv("Received invalid source address from ICMPv6 socket. Ignoring.");
break;
+ case -EAGAIN: /* ignore spurious wakeups */
+ break;
+
default:
- log_radv_warning_errno(r, "Error receiving from ICMPv6 socket: %m");
+ log_radv_errno(r, "Unexpected error receiving from ICMPv6 socket: %m");
break;
}
r = radv_send(ra, &src, ra->lifetime);
if (r < 0)
- log_radv_warning_errno(r, "Unable to send solicited Router Advertisement to %s: %m", addr);
+ log_radv_errno(r, "Unable to send solicited Router Advertisement to %s: %m", addr);
else
log_radv("Sent solicited Router Advertisement to %s", addr);
r = radv_send(ra, NULL, ra->lifetime);
if (r < 0)
- log_radv_warning_errno(r, "Unable to send Router Advertisement: %m");
+ log_radv_errno(r, "Unable to send Router Advertisement: %m");
/* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
if (ra->ra_sent < SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) {
with zero lifetime */
r = radv_send(ra, NULL, 0);
if (r < 0)
- log_radv_warning_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
+ log_radv_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
radv_reset(ra);
ra->fd = safe_close(ra->fd);
} LIBSYSTEMD_238;
LIBSYSTEMD_240 {
+global:
sd_bus_message_readv;
sd_bus_set_method_call_timeout;
sd_bus_get_method_call_timeout;
+
+ sd_device_ref;
+ sd_device_unref;
+
+ sd_device_new_from_syspath;
+ sd_device_new_from_devnum;
+ sd_device_new_from_subsystem_sysname;
+ sd_device_new_from_device_id;
+
+ sd_device_get_parent;
+ sd_device_get_parent_with_subsystem_devtype;
+
+ sd_device_get_syspath;
+ sd_device_get_subsystem;
+ sd_device_get_devtype;
+ sd_device_get_devnum;
+ sd_device_get_ifindex;
+ sd_device_get_driver;
+ sd_device_get_devpath;
+ sd_device_get_devname;
+ sd_device_get_sysname;
+ sd_device_get_sysnum;
+
+ sd_device_get_is_initialized;
+ sd_device_get_usec_since_initialized;
+
+ sd_device_get_tag_first;
+ sd_device_get_tag_next;
+ sd_device_get_devlink_first;
+ sd_device_get_devlink_next;
+ sd_device_get_property_first;
+ sd_device_get_property_next;
+ sd_device_get_sysattr_first;
+ sd_device_get_sysattr_next;
+
+ sd_device_has_tag;
+ sd_device_get_property_value;
+ sd_device_get_sysattr_value;
+
+ sd_device_set_sysattr_value;
+
+ sd_device_enumerator_new;
+ sd_device_enumerator_ref;
+ sd_device_enumerator_unref;
+
+ sd_device_enumerator_get_device_first;
+ sd_device_enumerator_get_device_next;
+ sd_device_enumerator_get_subsystem_first;
+ sd_device_enumerator_get_subsystem_next;
+
+ sd_device_enumerator_add_match_subsystem;
+ sd_device_enumerator_add_match_sysattr;
+ sd_device_enumerator_add_match_property;
+ sd_device_enumerator_add_match_sysname;
+ sd_device_enumerator_add_match_tag;
+ sd_device_enumerator_add_match_parent;
+ sd_device_enumerator_allow_uninitialized;
+
+ sd_hwdb_ref;
+ sd_hwdb_unref;
+
+ sd_hwdb_new;
+
+ sd_hwdb_get;
+
+ sd_hwdb_seek;
+ sd_hwdb_enumerate;
+
+ sd_id128_get_boot_app_specific;
} LIBSYSTEMD_239;
"%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%"PRIi64,
m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
- m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", special_glyph(TRIANGULAR_BULLET), ansi_normal(),
- ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_normal(),
+ m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "",
+ special_glyph(TRIANGULAR_BULLET),
+ ansi_normal(),
+
+ ansi_highlight(),
+ bus_message_type_to_string(m->header->type) ?: "(unknown)",
+ ansi_normal(),
+
m->header->endian,
m->header->flags,
m->header->version,
m->cached_rindex_part_begin = 0;
}
-static void message_reset_containers(sd_bus_message *m) {
- unsigned i;
+static struct bus_container *message_get_last_container(sd_bus_message *m) {
+ assert(m);
+
+ if (m->n_containers == 0)
+ return &m->root_container;
+
+ assert(m->containers);
+ return m->containers + m->n_containers - 1;
+}
+
+static void message_free_last_container(sd_bus_message *m) {
+ struct bus_container *c;
+ c = message_get_last_container(m);
+
+ free(c->signature);
+ free(c->peeked_signature);
+ free(c->offsets);
+
+ /* Move to previous container, but not if we are on root container */
+ if (m->n_containers > 0)
+ m->n_containers--;
+}
+
+static void message_reset_containers(sd_bus_message *m) {
assert(m);
- for (i = 0; i < m->n_containers; i++) {
- free(m->containers[i].signature);
- free(m->containers[i].offsets);
- }
+ while (m->n_containers > 0)
+ message_free_last_container(m);
m->containers = mfree(m->containers);
-
- m->n_containers = m->containers_allocated = 0;
+ m->containers_allocated = 0;
m->root_container.index = 0;
}
free(m->iovec);
message_reset_containers(m);
- free(m->root_container.signature);
- free(m->root_container.offsets);
-
- free(m->root_container.peeked_signature);
+ assert(m->n_containers == 0);
+ message_free_last_container(m);
bus_creds_done(&m->creds);
return mfree(m);
/* dbus1 doesn't allow strings over 32bit, let's enforce this
* globally, to not risk convertability */
l = strlen(s);
- if (l > (size_t) (uint32_t) -1)
+ if (l > UINT32_MAX)
return -EINVAL;
/* Signature "(yv)" where the variant contains "s" */
return 0;
}
-static struct bus_container *message_get_container(sd_bus_message *m) {
- assert(m);
-
- if (m->n_containers == 0)
- return &m->root_container;
-
- assert(m->containers);
- return m->containers + m->n_containers - 1;
-}
-
struct bus_body_part *message_append_part(sd_bus_message *m) {
struct bus_body_part *part;
/* Add offset to current container, unless this is the first
* item in it, which will have the 0 offset, which we can
* ignore. */
- c = message_get_container(m);
+ c = message_get_last_container(m);
if (!c->need_offsets)
return 0;
assert_return(bus_type_is_basic(type), -EINVAL);
assert_return(!m->poisoned, -ESTALE);
- c = message_get_container(m);
+ c = message_get_last_container(m);
if (c->signature && c->signature[c->index]) {
/* Container signature is already set */
assert_return(!m->sealed, -EPERM);
assert_return(!m->poisoned, -ESTALE);
- c = message_get_container(m);
+ c = message_get_last_container(m);
if (c->signature && c->signature[c->index]) {
/* Container signature is already set */
char type,
const char *contents) {
- struct bus_container *c, *w;
+ struct bus_container *c;
uint32_t *array_size = NULL;
_cleanup_free_ char *signature = NULL;
size_t before, begin = 0;
return -ENOMEM;
}
- c = message_get_container(m);
+ c = message_get_last_container(m);
signature = strdup(contents);
if (!signature) {
return r;
/* OK, let's fill it in */
- w = m->containers + m->n_containers++;
- w->enclosing = type;
- w->signature = TAKE_PTR(signature);
- w->index = 0;
- w->array_size = array_size;
- w->before = before;
- w->begin = begin;
- w->n_offsets = w->offsets_allocated = 0;
- w->offsets = NULL;
- w->need_offsets = need_offsets;
+ m->containers[m->n_containers++] = (struct bus_container) {
+ .enclosing = type,
+ .signature = TAKE_PTR(signature),
+ .array_size = array_size,
+ .before = before,
+ .begin = begin,
+ .need_offsets = need_offsets,
+ };
return 0;
}
assert_return(m->n_containers > 0, -EINVAL);
assert_return(!m->poisoned, -ESTALE);
- c = message_get_container(m);
+ c = message_get_last_container(m);
if (c->enclosing != SD_BUS_TYPE_ARRAY)
if (c->signature && c->signature[c->index] != 0)
va_list ap;
int r;
- assert_return(m, -EINVAL);
- assert_return(types, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(!m->poisoned, -ESTALE);
-
va_start(ap, types);
r = sd_bus_message_appendv(m, types, ap);
va_end(ap);
if (size > (uint64_t) (uint32_t) -1)
return -EINVAL;
- c = message_get_container(m);
+ c = message_get_last_container(m);
if (c->signature && c->signature[c->index]) {
/* Container signature is already set */
assert(m);
- c = message_get_container(m);
+ c = message_get_last_container(m);
return !c->signature || c->signature[c->index] == 0;
}
assert(m);
- c = message_get_container(m);
+ c = message_get_last_container(m);
if (c->enclosing != SD_BUS_TYPE_ARRAY)
return false;
assert(alignment > 0);
*rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
+ assert(c->offsets[c->offset_index+1] >= *rindex);
c->item_size = c->offsets[c->offset_index+1] - *rindex;
} else {
assert(alignment > 0);
*rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
+ assert(c->offsets[c->offset_index+1] >= *rindex);
c->item_size = c->offsets[c->offset_index+1] - *rindex;
c->offset_index++;
if (message_end_of_array(m, m->rindex))
return 0;
- c = message_get_container(m);
+ c = message_get_last_container(m);
if (c->signature[c->index] != type)
return -ENXIO;
if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
bool ok;
+ /* D-Bus spec: The marshalling formats for the string-like types all end
+ * with a single zero (NUL) byte, but that byte is not considered to be part
+ * of the text. */
+ if (c->item_size == 0)
+ return -EBADMSG;
+
r = message_peek_body(m, &rindex, 1, c->item_size, &q);
if (r < 0)
return r;
return r;
l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+ if (l == UINT32_MAX)
+ /* avoid overflow right below */
+ return -EBADMSG;
+
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
return r;
l = *(uint8_t*) q;
+ if (l == UINT8_MAX)
+ /* avoid overflow right below */
+ return -EBADMSG;
+
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
size_t rindex;
void *q;
- int r, alignment;
+ int r;
assert(m);
assert(c);
if (!BUS_MESSAGE_IS_GVARIANT(m)) {
/* dbus1 */
+ int alignment;
r = message_peek_body(m, &rindex, 4, 4, &q);
if (r < 0)
*n_offsets = 0;
} else {
- size_t where, p = 0, framing, sz;
+ size_t where, previous = 0, framing, sz;
+ int alignment;
unsigned i;
/* gvariant: variable length array */
if (!*offsets)
return -ENOMEM;
+ alignment = bus_gvariant_get_alignment(c->signature);
+ assert(alignment > 0);
+
for (i = 0; i < *n_offsets; i++) {
- size_t x;
+ size_t x, start;
+
+ start = ALIGN_TO(previous, alignment);
x = bus_gvariant_read_word_le((uint8_t*) q + i * sz, sz);
if (x > c->item_size - sz)
return -EBADMSG;
- if (x < p)
+ if (x < start)
return -EBADMSG;
(*offsets)[i] = rindex + x;
- p = x;
+ previous = x;
}
*item_size = (*offsets)[0] - rindex;
return r;
l = *(uint8_t*) q;
+ if (l == UINT8_MAX)
+ /* avoid overflow right below */
+ return -EBADMSG;
+
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
size_t *n_offsets) {
unsigned n_variable = 0, n_total = 0, v;
- size_t previous = 0, where;
+ size_t previous, where;
const char *p;
size_t sz;
void *q;
/* Second, loop again and build an offset table */
p = signature;
+ previous = m->rindex;
while (*p != 0) {
size_t n, offset;
int k;
memcpy(t, p, n);
t[n] = 0;
+ size_t align = bus_gvariant_get_alignment(t);
+ assert(align > 0);
+
+ /* The possible start of this member after including alignment */
+ size_t start = ALIGN_TO(previous, align);
+
k = bus_gvariant_get_size(t);
if (k < 0) {
size_t x;
- /* variable size */
+ /* Variable size */
if (v > 0) {
v--;
x = bus_gvariant_read_word_le((uint8_t*) q + v*sz, sz);
if (x >= size)
return -EBADMSG;
- if (m->rindex + x < previous)
- return -EBADMSG;
} else
- /* The last item's end
- * is determined from
- * the start of the
- * offset array */
+ /* The last item's end is determined
+ * from the start of the offset array */
x = size - (n_variable * sz);
offset = m->rindex + x;
-
- } else {
- size_t align;
-
- /* fixed size */
- align = bus_gvariant_get_alignment(t);
- assert(align > 0);
-
- offset = (*n_offsets == 0 ? m->rindex : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k;
- }
+ if (offset < start) {
+ log_debug("For type %s with alignment %zu, message specifies offset %zu which is smaller than previous end %zu + alignment = %zu",
+ t, align, offset, previous, start);
+ return -EBADMSG;
+ }
+ } else
+ /* Fixed size */
+ offset = start + k;
}
previous = (*offsets)[(*n_offsets)++] = offset;
_public_ int sd_bus_message_enter_container(sd_bus_message *m,
char type,
const char *contents) {
- struct bus_container *c, *w;
+ struct bus_container *c;
uint32_t *array_size = NULL;
_cleanup_free_ char *signature = NULL;
- size_t before;
+ size_t before, end;
_cleanup_free_ size_t *offsets = NULL;
size_t n_offsets = 0, item_size = 0;
int r;
if (message_end_of_array(m, m->rindex))
return 0;
- c = message_get_container(m);
+ c = message_get_last_container(m);
signature = strdup(contents);
if (!signature)
return r;
/* OK, let's fill it in */
- w = m->containers + m->n_containers++;
- w->enclosing = type;
- w->signature = TAKE_PTR(signature);
- w->peeked_signature = NULL;
- w->index = 0;
-
- w->before = before;
- w->begin = m->rindex;
-
- /* Unary type has fixed size of 1, but virtual size of 0 */
if (BUS_MESSAGE_IS_GVARIANT(m) &&
type == SD_BUS_TYPE_STRUCT &&
isempty(signature))
- w->end = m->rindex + 0;
+ end = m->rindex + 0;
else
- w->end = m->rindex + c->item_size;
-
- w->array_size = array_size;
- w->item_size = item_size;
- w->offsets = TAKE_PTR(offsets);
- w->n_offsets = n_offsets;
- w->offset_index = 0;
+ end = m->rindex + c->item_size;
+
+ m->containers[m->n_containers++] = (struct bus_container) {
+ .enclosing = type,
+ .signature = TAKE_PTR(signature),
+
+ .before = before,
+ .begin = m->rindex,
+ /* Unary type has fixed size of 1, but virtual size of 0 */
+ .end = end,
+ .array_size = array_size,
+ .item_size = item_size,
+ .offsets = TAKE_PTR(offsets),
+ .n_offsets = n_offsets,
+ };
return 1;
}
assert_return(m->sealed, -EPERM);
assert_return(m->n_containers > 0, -ENXIO);
- c = message_get_container(m);
+ c = message_get_last_container(m);
if (c->enclosing != SD_BUS_TYPE_ARRAY) {
if (c->signature && c->signature[c->index] != 0)
return -EBUSY;
}
- free(c->signature);
- free(c->peeked_signature);
- free(c->offsets);
- m->n_containers--;
-
- c = message_get_container(m);
+ message_free_last_container(m);
+ c = message_get_last_container(m);
saved = c->index;
c->index = c->saved_index;
r = container_next_item(m, c, &m->rindex);
assert(m->sealed);
assert(m->n_containers > 0);
- c = message_get_container(m);
-
/* Undo seeks */
+ c = message_get_last_container(m);
assert(m->rindex >= c->before);
m->rindex = c->before;
/* Free container */
- free(c->signature);
- free(c->offsets);
- m->n_containers--;
+ message_free_last_container(m);
/* Correct index of new top-level container */
- c = message_get_container(m);
+ c = message_get_last_container(m);
c->index = c->saved_index;
}
if (message_end_of_array(m, m->rindex))
goto eof;
- c = message_get_container(m);
+ c = message_get_last_container(m);
if (bus_type_is_basic(c->signature[c->index])) {
if (contents)
if (contents) {
size_t l;
- char *sig;
r = signature_element_length(c->signature+c->index+1, &l);
if (r < 0)
return r;
- assert(l >= 1);
+ /* signature_element_length does verification internally */
- sig = strndup(c->signature + c->index + 1, l);
- if (!sig)
+ /* The array element must not be empty */
+ assert(l >= 1);
+ if (free_and_strndup(&c->peeked_signature,
+ c->signature + c->index + 1, l) < 0)
return -ENOMEM;
- free(c->peeked_signature);
- *contents = c->peeked_signature = sig;
+ *contents = c->peeked_signature;
}
if (type)
if (contents) {
size_t l;
- char *sig;
r = signature_element_length(c->signature+c->index, &l);
if (r < 0)
return r;
- assert(l >= 2);
- sig = strndup(c->signature + c->index + 1, l - 2);
- if (!sig)
+ assert(l >= 3);
+ if (free_and_strndup(&c->peeked_signature,
+ c->signature + c->index + 1, l - 2) < 0)
return -ENOMEM;
- free(c->peeked_signature);
- *contents = c->peeked_signature = sig;
+ *contents = c->peeked_signature;
}
if (type)
if (k > c->item_size)
return -EBADMSG;
- free(c->peeked_signature);
- c->peeked_signature = strndup((char*) q + 1, k - 1);
- if (!c->peeked_signature)
+ if (free_and_strndup(&c->peeked_signature,
+ (char*) q + 1, k - 1) < 0)
return -ENOMEM;
if (!signature_is_valid(c->peeked_signature, true))
return r;
l = *(uint8_t*) q;
+ if (l == UINT8_MAX)
+ /* avoid overflow right below */
+ return -EBADMSG;
+
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
message_reset_containers(m);
m->rindex = 0;
- c = message_get_container(m);
+ c = message_get_last_container(m);
} else {
- c = message_get_container(m);
+ c = message_get_last_container(m);
- c->offset_index = 0;
c->index = 0;
m->rindex = c->begin;
}
va_list ap;
int r;
- assert_return(m, -EINVAL);
- assert_return(m->sealed, -EPERM);
- assert_return(types, -EINVAL);
-
va_start(ap, types);
r = sd_bus_message_readv(m, types, ap);
va_end(ap);
if (message_end_of_array(m, m->rindex))
return 0;
- c = message_get_container(m);
+ c = message_get_last_container(m);
r = signature_element_length(c->signature + c->index, &l);
if (r < 0)
if (r <= 0)
return r;
- c = message_get_container(m);
+ c = message_get_last_container(m);
if (BUS_MESSAGE_IS_GVARIANT(m)) {
align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
if (r < 0)
return r;
+ if (l == UINT32_MAX)
+ /* avoid overflow right below */
+ return -EBADMSG;
+
r = message_peek_fields(m, ri, 1, l+1, &q);
if (r < 0)
return r;
return r;
l = *(uint8_t*) q;
+ if (l == UINT8_MAX)
+ /* avoid overflow right below */
+ return -EBADMSG;
+
r = message_peek_fields(m, ri, 1, l+1, &q);
if (r < 0)
return r;
} else if (t == SD_BUS_TYPE_ARRAY) {
- r = signature_element_length(*signature+1, &l);
+ r = signature_element_length(*signature + 1, &l);
if (r < 0)
return r;
assert(l >= 1);
{
- char sig[l-1], *s;
+ char sig[l + 1], *s = sig;
uint32_t nas;
int alignment;
- strncpy(sig, *signature + 1, l-1);
- s = sig;
+ strncpy(sig, *signature + 1, l);
+ sig[l] = '\0';
alignment = bus_type_get_alignment(sig[0]);
if (alignment < 0)
assert(l >= 2);
{
- char sig[l-1], *s;
- strncpy(sig, *signature + 1, l-1);
- s = sig;
+ char sig[l + 1], *s = sig;
+ strncpy(sig, *signature + 1, l);
+ sig[l] = '\0';
r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
if (r < 0)
*signature += l;
} else
- return -EINVAL;
+ return -EBADMSG;
}
}
if (*p == 0) {
size_t l;
- char *c;
/* We found the beginning of the signature
* string, yay! We require the body to be a
* structure, so verify it and then strip the
* opening/closing brackets. */
- l = ((char*) m->footer + m->footer_accessible) - p - (1 + sz);
+ l = (char*) m->footer + m->footer_accessible - p - (1 + sz);
if (l < 2 ||
p[1] != SD_BUS_TYPE_STRUCT_BEGIN ||
p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END)
return -EBADMSG;
- c = strndup(p + 1 + 1, l - 2);
- if (!c)
+ if (free_and_strndup(&m->root_container.signature,
+ p + 1 + 1, l - 2) < 0)
return -ENOMEM;
-
- free(m->root_container.signature);
- m->root_container.signature = c;
break;
}
&m->root_container.item_size,
&m->root_container.offsets,
&m->root_container.n_offsets);
+ if (r == -EINVAL)
+ return -EBADMSG;
if (r < 0)
return r;
}
assert_return(m, NULL);
- c = complete ? &m->root_container : message_get_container(m);
+ c = complete ? &m->root_container : message_get_last_container(m);
return strempty(c->signature);
}
p += t;
}
+ if (p - s < 2)
+ /* D-Bus spec: Empty structures are not allowed; there
+ * must be at least one type code between the parentheses.
+ */
+ return -EINVAL;
+
*l = p - s + 1;
return 0;
}
#include "refcnt.h"
#include "tests.h"
+static bool use_system_bus = false;
+
static void test_bus_new(void) {
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
int r;
r = sd_bus_open_user(&bus);
- if (IN_SET(r, -ECONNREFUSED, -ENOENT))
- return r;
+ if (IN_SET(r, -ECONNREFUSED, -ENOENT)) {
+ r = sd_bus_open_system(&bus);
+ if (IN_SET(r, -ECONNREFUSED, -ENOENT))
+ return r;
+ use_system_bus = true;
+ }
assert_se(r >= 0);
printf("after open: refcount %u\n", REFCNT_GET(bus->n_ref));
sd_bus *bus = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- assert_se(sd_bus_open_user(&bus) >= 0);
+ assert_se(use_system_bus ? sd_bus_open_system(&bus) >= 0 : sd_bus_open_user(&bus) >= 0);
assert_se(sd_bus_message_new_method_call(bus, &m, "a.service.name", "/an/object/path", "an.interface.name", "AMethodName") >= 0);
sd_bus *bus = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- assert_se(sd_bus_open_user(&bus) >= 0);
+ assert_se(use_system_bus ? sd_bus_open_system(&bus) >= 0 : sd_bus_open_user(&bus) >= 0);
assert_se(sd_bus_message_new_signal(bus, &m, "/an/object/path", "an.interface.name", "Name") >= 0);
#include "util.h"
static void test_bus_gvariant_is_fixed_size(void) {
+ log_info("/* %s */", __func__);
+
assert_se(bus_gvariant_is_fixed_size("") > 0);
- assert_se(bus_gvariant_is_fixed_size("()") > 0);
+ assert_se(bus_gvariant_is_fixed_size("()") == -EINVAL);
assert_se(bus_gvariant_is_fixed_size("y") > 0);
assert_se(bus_gvariant_is_fixed_size("u") > 0);
assert_se(bus_gvariant_is_fixed_size("b") > 0);
}
static void test_bus_gvariant_get_size(void) {
+ log_info("/* %s */", __func__);
+
assert_se(bus_gvariant_get_size("") == 0);
- assert_se(bus_gvariant_get_size("()") == 1);
+ assert_se(bus_gvariant_get_size("()") == -EINVAL);
assert_se(bus_gvariant_get_size("y") == 1);
assert_se(bus_gvariant_get_size("u") == 4);
assert_se(bus_gvariant_get_size("b") == 1);
}
static void test_bus_gvariant_get_alignment(void) {
+ log_info("/* %s */", __func__);
+
assert_se(bus_gvariant_get_alignment("") == 1);
- assert_se(bus_gvariant_get_alignment("()") == 1);
+ assert_se(bus_gvariant_get_alignment("()") == -EINVAL);
assert_se(bus_gvariant_get_alignment("y") == 1);
assert_se(bus_gvariant_get_alignment("b") == 1);
assert_se(bus_gvariant_get_alignment("u") == 4);
int r;
r = sd_bus_open_user(&bus);
+ if (r < 0)
+ r = sd_bus_open_system(&bus);
if (r < 0)
return log_tests_skipped_errno(r, "Failed to connect to bus");
bus->message_version = 2; /* dirty hack to enable gvariant */
- assert_se(sd_bus_message_new_method_call(bus, &m, "a.service.name", "/an/object/path/which/is/really/really/long/so/that/we/hit/the/eight/bit/boundary/by/quite/some/margin/to/test/this/stuff/that/it/really/works", "an.interface.name", "AMethodName") >= 0);
+ r = sd_bus_message_new_method_call(bus, &m, "a.service.name",
+ "/an/object/path/which/is/really/really/long/so/that/we/hit/the/eight/bit/boundary/by/quite/some/margin/to/test/this/stuff/that/it/really/works",
+ "an.interface.name", "AMethodName");
+ assert_se(r >= 0);
assert_cc(sizeof(struct bus_header) == 16);
}
int main(int argc, char *argv[]) {
- test_setup_logging(LOG_INFO);
+ test_setup_logging(LOG_DEBUG);
test_bus_gvariant_is_fixed_size();
test_bus_gvariant_get_size();
#include "bus-label.h"
#include "bus-message.h"
#include "bus-util.h"
+#include "escape.h"
#include "fd-util.h"
-#include "hexdecoct.h"
#include "log.h"
#include "tests.h"
#include "util.h"
uint8_t u, v;
void *buffer = NULL;
size_t sz;
- char *h;
+ _cleanup_free_ char *h = NULL;
const int32_t integer_array[] = { -1, -2, 0, 1, 2 }, *return_array;
char *s;
_cleanup_free_ char *first = NULL, *second = NULL, *third = NULL;
test_setup_logging(LOG_INFO);
r = sd_bus_default_user(&bus);
+ if (r < 0)
+ r = sd_bus_default_system(&bus);
if (r < 0)
return log_tests_skipped("Failed to connect to bus");
assert_se(r >= 0);
r = sd_bus_message_append(m, "()");
- assert_se(r >= 0);
+ assert_se(r == -EINVAL);
r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3");
assert_se(r >= 0);
r = bus_message_get_blob(m, &buffer, &sz);
assert_se(r >= 0);
- h = hexmem(buffer, sz);
+ h = cescape_length(buffer, sz);
assert_se(h);
-
log_info("message size = %zu, contents =\n%s", sz, h);
- free(h);
#if HAVE_GLIB
#ifndef __SANITIZE_ADDRESS__
assert_se(v == 10);
r = sd_bus_message_read(m, "()");
- assert_se(r > 0);
+ assert_se(r < 0);
r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d);
assert_se(r > 0);
assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0);
- r = sd_bus_message_skip(m, "a{yv}y(ty)y(yt)y()");
+ r = sd_bus_message_skip(m, "a{yv}y(ty)y(yt)y");
assert_se(r >= 0);
assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0);
test_setup_logging(LOG_INFO);
r = sd_bus_open_user(&bus);
+ if (r < 0)
+ r = sd_bus_open_system(&bus);
if (r < 0)
return log_tests_skipped("Failed to connect to bus");
assert_se(signature_is_single("v", false));
assert_se(signature_is_single("as", false));
assert_se(signature_is_single("(ss)", false));
- assert_se(signature_is_single("()", false));
- assert_se(signature_is_single("(()()()()())", false));
- assert_se(signature_is_single("(((())))", false));
+ assert_se(!signature_is_single("()", false));
+ assert_se(!signature_is_single("(()()()()())", false));
+ assert_se(!signature_is_single("(((())))", false));
assert_se(signature_is_single("((((s))))", false));
assert_se(signature_is_single("{ss}", true));
assert_se(signature_is_single("a{ss}", false));
assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaas", false));
assert_se(!signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaau", false));
- assert_se(signature_is_valid("(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))", false));
+ assert_se(signature_is_valid("((((((((((((((((((((((((((((((((s))))))))))))))))))))))))))))))))", false));
assert_se(!signature_is_valid("((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))", false));
assert_se(namespace_complex_pattern("", ""));
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_bus_track_unrefp) sd_bus_track *x = NULL, *y = NULL;
_cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL;
+ bool use_system_bus = false;
const char *unique;
int r;
assert_se(r >= 0);
r = sd_bus_open_user(&a);
- if (IN_SET(r, -ECONNREFUSED, -ENOENT))
- return log_tests_skipped("Failed to connect to bus");
+ if (IN_SET(r, -ECONNREFUSED, -ENOENT)) {
+ r = sd_bus_open_system(&a);
+ if (IN_SET(r, -ECONNREFUSED, -ENOENT))
+ return log_tests_skipped("Failed to connect to bus");
+ use_system_bus = true;
+ }
assert_se(r >= 0);
r = sd_bus_attach_event(a, event, SD_EVENT_PRIORITY_NORMAL);
assert_se(r >= 0);
- r = sd_bus_open_user(&b);
+ if (use_system_bus)
+ r = sd_bus_open_system(&b);
+ else
+ r = sd_bus_open_user(&b);
assert_se(r >= 0);
r = sd_bus_attach_event(b, event, SD_EVENT_PRIORITY_NORMAL);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "device-enumerator-private.h"
+#include "device-private.h"
+#include "device-util.h"
+#include "string-util.h"
+#include "tests.h"
+#include "util.h"
+
+static void test_sd_device_basic(void) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ sd_device *d;
+
+ assert_se(sd_device_enumerator_new(&e) >= 0);
+ assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0);
+ FOREACH_DEVICE(e, d) {
+ const char *syspath, *devpath, *subsystem, *val;
+ dev_t devnum;
+ usec_t usec;
+ int i, r;
+
+ assert_se(sd_device_get_syspath(d, &syspath) >= 0);
+
+ r = sd_device_get_subsystem(d, &subsystem);
+ assert_se(r >= 0 || r == -ENOENT);
+
+ r = sd_device_get_devtype(d, &val);
+ assert_se(r >= 0 || r == -ENOENT);
+
+ r = sd_device_get_devnum(d, &devnum);
+ assert_se(r >= 0 || r == -ENOENT);
+
+ r = sd_device_get_ifindex(d, &i);
+ assert_se(r >= 0 || r == -ENOENT);
+
+ r = sd_device_get_driver(d, &val);
+ assert_se(r >= 0 || r == -ENOENT);
+
+ assert_se(sd_device_get_devpath(d, &devpath) >= 0);
+
+ r = sd_device_get_devname(d, &val);
+ assert_se(r >= 0 || r == -ENOENT);
+
+ assert_se(sd_device_get_sysname(d, &val) >= 0);
+
+ r = sd_device_get_sysnum(d, &val);
+ assert_se(r >= 0 || r == -ENOENT);
+
+ i = 0;
+ assert_se(sd_device_get_is_initialized(d, &i) >= 0);
+ if (i > 0) {
+ r = sd_device_get_usec_since_initialized(d, &usec);
+ assert_se(r >= 0 || r == -ENODATA);
+ }
+
+ r = sd_device_get_sysattr_value(d, "name_assign_type", &val);
+ assert_se(r >= 0 || IN_SET(r, -ENOENT, -EINVAL));
+
+ r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val);
+ assert_se(r >= 0 || r == -ENOENT);
+
+ log_debug("syspath:%s devpath:%s subsystem:%s", syspath, devpath, strempty(subsystem));
+ }
+}
+
+int main(int argc, char **argv) {
+ test_setup_logging(LOG_INFO);
+
+ test_sd_device_basic();
+ return 0;
+}
* continued to being watched. That's because inotify doesn't really have an API for that: we
* can only change watch masks with access to the original inode either by fd or by path. But
* paths aren't stable, and keeping an O_PATH fd open all the time would mean wasting an fd
- * continously and keeping the mount busy which we can't really do. We could reconstruct the
+ * continuously and keeping the mount busy which we can't really do. We could reconstruct the
* original inode from /proc/self/fdinfo/$INOTIFY_FD (as all watch descriptors are listed
* there), but given the need for open_by_handle_at() which is privileged and not universally
* available this would be quite an incomplete solution. Hence we go the other way, leave the
free(s->description);
free(s);
}
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, source_free);
static int source_set_pending(sd_event_source *s, bool b) {
int r;
sd_event_io_handler_t callback,
void *userdata) {
- sd_event_source *s;
+ _cleanup_(source_freep) sd_event_source *s = NULL;
int r;
assert_return(e, -EINVAL);
s->enabled = SD_EVENT_ON;
r = source_io_register(s, s->enabled, events);
- if (r < 0) {
- source_free(s);
+ if (r < 0)
return r;
- }
if (ret)
*ret = s;
+ TAKE_PTR(s);
return 0;
}
sd_id128_t bootid = {};
/* When we sleep for longer, we try to realign the wakeup to
- the same time wihtin each minute/second/250ms, so that
+ the same time within each minute/second/250ms, so that
events all across the system can be coalesced into a single
CPU wakeup. However, let's take some system-specific
randomness for this value, so that in a network of systems
void *userdata) {
EventSourceType type;
- sd_event_source *s;
+ _cleanup_(source_freep) sd_event_source *s = NULL;
struct clock_data *d;
int r;
r = prioq_put(d->earliest, s, &s->time.earliest_index);
if (r < 0)
- goto fail;
+ return r;
r = prioq_put(d->latest, s, &s->time.latest_index);
if (r < 0)
- goto fail;
+ return r;
if (ret)
*ret = s;
+ TAKE_PTR(s);
return 0;
-
-fail:
- source_free(s);
- return r;
}
static int signal_exit_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
sd_event_signal_handler_t callback,
void *userdata) {
- sd_event_source *s;
+ _cleanup_(source_freep) sd_event_source *s = NULL;
struct signal_data *d;
sigset_t ss;
int r;
e->signal_sources[sig] = s;
r = event_make_signal_data(e, sig, &d);
- if (r < 0) {
- source_free(s);
+ if (r < 0)
return r;
- }
/* Use the signal name as description for the event source by default */
(void) sd_event_source_set_description(s, signal_to_string(sig));
if (ret)
*ret = s;
+ TAKE_PTR(s);
return 0;
}
sd_event_child_handler_t callback,
void *userdata) {
- sd_event_source *s;
+ _cleanup_(source_freep) sd_event_source *s = NULL;
int r;
assert_return(e, -EINVAL);
s->enabled = SD_EVENT_ONESHOT;
r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
- if (r < 0) {
- source_free(s);
+ if (r < 0)
return r;
- }
e->n_enabled_child_sources++;
r = event_make_signal_data(e, SIGCHLD, NULL);
if (r < 0) {
e->n_enabled_child_sources--;
- source_free(s);
return r;
}
if (ret)
*ret = s;
+ TAKE_PTR(s);
return 0;
}
sd_event_handler_t callback,
void *userdata) {
- sd_event_source *s;
+ _cleanup_(source_freep) sd_event_source *s = NULL;
int r;
assert_return(e, -EINVAL);
s->enabled = SD_EVENT_ONESHOT;
r = source_set_pending(s, true);
- if (r < 0) {
- source_free(s);
+ if (r < 0)
return r;
- }
if (ret)
*ret = s;
+ TAKE_PTR(s);
return 0;
}
sd_event_handler_t callback,
void *userdata) {
- sd_event_source *s;
+ _cleanup_(source_freep) sd_event_source *s = NULL;
int r;
assert_return(e, -EINVAL);
s->enabled = SD_EVENT_ON;
r = set_put(e->post_sources, s);
- if (r < 0) {
- source_free(s);
+ if (r < 0)
return r;
- }
if (ret)
*ret = s;
+ TAKE_PTR(s);
return 0;
}
sd_event_handler_t callback,
void *userdata) {
- sd_event_source *s;
+ _cleanup_(source_freep) sd_event_source *s = NULL;
int r;
assert_return(e, -EINVAL);
s->enabled = SD_EVENT_ONESHOT;
r = prioq_put(s->event->exit, s, &s->exit.prioq_index);
- if (r < 0) {
- source_free(s);
+ if (r < 0)
return r;
- }
if (ret)
*ret = s;
+ TAKE_PTR(s);
return 0;
}
*
* Note that we add all sources to the mask here, regardless whether enabled, disabled or oneshot. That's
* because we cannot change the mask anymore after the event source was created once, since the kernel has no
- * API for that. Hence we need to subscribe to the maximum mask we ever might be interested in, and supress
+ * API for that. Hence we need to subscribe to the maximum mask we ever might be interested in, and suppress
* events we don't care for client-side. */
LIST_FOREACH(inotify.by_inode_data, s, d->event_sources) {
sd_event_inotify_handler_t callback,
void *userdata) {
- bool rm_inotify = false, rm_inode = false;
struct inotify_data *inotify_data = NULL;
struct inode_data *inode_data = NULL;
_cleanup_close_ int fd = -1;
- sd_event_source *s;
+ _cleanup_(source_freep) sd_event_source *s = NULL;
struct stat st;
int r;
/* Allocate an inotify object for this priority, and an inode object within it */
r = event_make_inotify_data(e, SD_EVENT_PRIORITY_NORMAL, &inotify_data);
if (r < 0)
- goto fail;
- rm_inotify = r > 0;
+ return r;
r = event_make_inode_data(e, inotify_data, st.st_dev, st.st_ino, &inode_data);
- if (r < 0)
- goto fail;
- rm_inode = r > 0;
+ if (r < 0) {
+ event_free_inotify_data(e, inotify_data);
+ return r;
+ }
/* Keep the O_PATH fd around until the first iteration of the loop, so that we can still change the priority of
* the event source, until then, for which we need the original inode. */
LIST_PREPEND(inotify.by_inode_data, inode_data->event_sources, s);
s->inotify.inode_data = inode_data;
- rm_inode = rm_inotify = false;
-
/* Actually realize the watch now */
r = inode_data_realize_watch(e, inode_data);
if (r < 0)
- goto fail;
+ return r;
(void) sd_event_source_set_description(s, path);
if (ret)
*ret = s;
+ TAKE_PTR(s);
return 0;
-
-fail:
- source_free(s);
-
- if (rm_inode)
- event_free_inode_data(e, inode_data);
-
- if (rm_inotify)
- event_free_inotify_data(e, inotify_data);
-
- return r;
}
static sd_event_source* event_source_free(sd_event_source *s) {
return 0;
}
-_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
+static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) {
_cleanup_(khash_unrefp) khash *h = NULL;
- sd_id128_t m, result;
+ sd_id128_t result;
const void *p;
int r;
- assert_return(ret, -EINVAL);
-
- r = sd_id128_get_machine(&m);
- if (r < 0)
- return r;
+ assert(ret);
- r = khash_new_with_key(&h, "hmac(sha256)", &m, sizeof(m));
+ r = khash_new_with_key(&h, "hmac(sha256)", &base, sizeof(base));
if (r < 0)
return r;
*ret = make_v4_uuid(result);
return 0;
}
+
+_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
+ sd_id128_t id;
+ int r;
+
+ assert_return(ret, -EINVAL);
+
+ r = sd_id128_get_machine(&id);
+ if (r < 0)
+ return r;
+
+ return get_app_specific(id, app_id, ret);
+}
+
+_public_ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
+ sd_id128_t id;
+ int r;
+
+ assert_return(ret, -EINVAL);
+
+ r = sd_id128_get_boot(&id);
+ if (r < 0)
+ return r;
+
+ return get_app_specific(id, app_id, ret);
+}
}
}
- if (!had_master && d->master)
+ if (!had_master && d->master && s->started) {
+ seat_save(s);
seat_send_changed(s, "CanGraphical", NULL);
+ }
}
static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
-static bool dhcp6_verify_link(Link *link) {
- if (!link->network) {
- log_link_info(link, "Link is not managed by us");
+static bool dhcp6_get_prefix_delegation(Link *link) {
+ if (!link->network)
return false;
- }
if (!IN_SET(link->network->router_prefix_delegation,
RADV_PREFIX_DELEGATION_DHCP6,
RADV_PREFIX_DELEGATION_BOTH)) {
- log_link_debug(link, "Link does not request DHCPv6 prefix delegation");
return false;
}
if (l == dhcp6_link)
continue;
- if (!dhcp6_verify_link(l))
+ if (!dhcp6_get_prefix_delegation(l))
continue;
return true;
&lifetime_preferred,
&lifetime_valid) >= 0) {
_cleanup_free_ char *buf = NULL;
- _cleanup_free_ Route *route;
+ _cleanup_free_ Route *route = NULL;
if (pd_prefix_len > 64)
continue;
log_link_warning_errno(link, r, "Cannot delete unreachable route for DHCPv6 delegated subnet %s/%u: %m",
strnull(buf),
pd_prefix_len);
- route_free(route);
+
continue;
}
link = link_ref(link);
if (link == dhcp6_link)
continue;
- if (!dhcp6_verify_link(link))
+ if (!dhcp6_get_prefix_delegation(link))
continue;
assigned_link = manager_dhcp6_prefix_get(manager, &prefix.in6);
return 0;
}
+int dhcp6_request_prefix_delegation(Link *link) {
+ Link *l;
+ Iterator i;
+
+ assert_return(link, -EINVAL);
+ assert_return(link->manager, -EOPNOTSUPP);
+
+ if (dhcp6_get_prefix_delegation(link) <= 0)
+ return 0;
+
+ log_link_debug(link, "Requesting DHCPv6 prefixes to be delegated for new link");
+
+ HASHMAP_FOREACH(l, link->manager->links, i) {
+ int r, enabled;
+
+ if (l == link)
+ continue;
+
+ if (!l->dhcp6_client)
+ continue;
+
+ r = sd_dhcp6_client_get_prefix_delegation(l->dhcp6_client, &enabled);
+ if (r < 0) {
+ log_link_warning_errno(l, r, "Cannot get prefix delegation when adding new link");
+ continue;
+ }
+
+ if (enabled == 0) {
+ r = sd_dhcp6_client_set_prefix_delegation(l->dhcp6_client, 1);
+ if (r < 0) {
+ log_link_warning_errno(l, r, "Cannot enable prefix delegation when adding new link");
+ continue;
+ }
+ }
+
+ r = sd_dhcp6_client_is_running(l->dhcp6_client);
+ if (r <= 0)
+ continue;
+
+ if (enabled != 0) {
+ log_link_debug(l, "Requesting re-assignment of delegated prefixes after adding new link");
+ (void) dhcp6_lease_pd_prefix_acquired(l->dhcp6_client, l);
+
+ continue;
+ }
+
+ r = sd_dhcp6_client_stop(l->dhcp6_client);
+ if (r < 0) {
+ log_link_warning_errno(l, r, "Cannot stop DHCPv6 prefix delegation client after adding new link");
+ continue;
+ }
+
+ r = sd_dhcp6_client_start(l->dhcp6_client);
+ if (r < 0) {
+ log_link_warning_errno(l, r, "Cannot restart DHCPv6 prefix delegation client after adding new link");
+ continue;
+ }
+
+ log_link_debug(l, "Restarted DHCPv6 client to acquire prefix delegations after adding new link");
+ }
+
+ return 0;
+}
+
static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
void *userdata) {
_cleanup_(link_unrefp) Link *link = userdata;
assert(link);
- if (link_dhcp6_enabled(link)) {
- assert(link->dhcp6_client);
- assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
-
- /* start DHCPv6 client in stateless mode */
- r = dhcp6_request_address(link, true);
- if (r < 0 && r != -EBUSY)
- return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m");
- else
- log_link_debug(link, "Acquiring DHCPv6 lease");
- }
-
if (link_ipv6_accept_ra_enabled(link)) {
assert(link->ndisc);
return log_link_warning_errno(link, r, "Could not start IPv6 Router Advertisement: %m");
}
+ (void) dhcp6_request_prefix_delegation(link);
+
return 0;
}
int dhcp4_configure(Link *link);
int dhcp4_set_client_identifier(Link *link);
int dhcp4_set_promote_secondaries(Link *link);
+int dhcp6_request_prefix_delegation(Link *link);
int dhcp6_configure(Link *link);
int dhcp6_request_address(Link *link, int ir);
int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link);
if (r < 0)
return log_error_errno(r, "Failed to add network enumerator: %m");
- r = bus_request_name_async_may_reload_dbus(m->bus, NULL, "org.freedesktop.network1", 0, NULL);
+ r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.network1", 0, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to request name: %m");
union in_addr_union to = {}, from = {};
RoutingPolicyRule *rule = NULL;
uint32_t fwmark = 0, table = 0;
- char *iif = NULL, *oif = NULL;
+ const char *iif = NULL, *oif = NULL;
Manager *m = userdata;
uint16_t type;
int family;
return 0;
}
- r = sd_netlink_message_read_string(message, FRA_IIFNAME, (const char **) &iif);
+ r = sd_netlink_message_read_string(message, FRA_IIFNAME, &iif);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_IIFNAME attribute, ignoring: %m");
return 0;
}
- r = sd_netlink_message_read_string(message, FRA_OIFNAME, (const char **) &oif);
+ r = sd_netlink_message_read_string(message, FRA_OIFNAME, &oif);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_OIFNAME attribute, ignoring: %m");
return 0;
while ((pool = m->address_pools))
address_pool_free(pool);
- set_free(m->rules);
- set_free(m->rules_foreign);
-
+ set_free_with_destructor(m->rules, routing_policy_rule_free);
+ set_free_with_destructor(m->rules_foreign, routing_policy_rule_free);
set_free_with_destructor(m->rules_saved, routing_policy_rule_free);
sd_netlink_unref(m->rtnl);
DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
DHCP.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
-DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
+DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
IPv6AcceptRA.RouteTable, config_parse_uint32, 0, offsetof(Network, ipv6_accept_ra_route_table)
network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
/* RFC 7844 3.10:
SHOULD NOT use the Vendor Class Identifier option */
- /* NOTE: it was not initiallized to any value in network_load_one. */
- network->dhcp_vendor_class_identifier = false;
+ network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
/* RFC7844 section 3.6.:
The client intending to protect its privacy SHOULD only request a
minimal number of options in the PRL and SHOULD also randomly shuffle
network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
network->dhcp_route_table = RT_TABLE_MAIN;
network->dhcp_route_table_set = false;
- /* NOTE: the following vars were not set to any default,
- * even if they are commented in the man?
- * These vars might be overwriten by network_apply_anonymize_if_set */
- network->dhcp_vendor_class_identifier = false;
/* NOTE: from man: UseMTU=... Defaults to false*/
network->dhcp_use_mtu = false;
/* NOTE: from man: UseTimezone=... Defaults to "no".*/
int routing_policy_rule_new(RoutingPolicyRule **ret) {
RoutingPolicyRule *rule;
- rule = new0(RoutingPolicyRule, 1);
+ rule = new(RoutingPolicyRule, 1);
if (!rule)
return -ENOMEM;
- rule->family = AF_INET;
- rule->table = RT_TABLE_MAIN;
+ *rule = (RoutingPolicyRule) {
+ .family = AF_INET,
+ .table = RT_TABLE_MAIN,
+ };
*ret = rule;
return 0;
uint8_t tos,
uint32_t fwmark,
uint32_t table,
- char *iif,
- char *oif,
+ const char *iif,
+ const char *oif,
RoutingPolicyRule **ret) {
RoutingPolicyRule rule, *existing;
.tos = tos,
.fwmark = fwmark,
.table = table,
- .iif = iif,
- .oif = oif
+ .iif = (char*) iif,
+ .oif = (char*) oif
};
- if (m->rules) {
- existing = set_get(m->rules, &rule);
- if (existing) {
- if (ret)
- *ret = existing;
- return 1;
- }
+ existing = set_get(m->rules, &rule);
+ if (existing) {
+ if (ret)
+ *ret = existing;
+ return 1;
}
- if (m->rules_foreign) {
- existing = set_get(m->rules_foreign, &rule);
- if (existing) {
- if (ret)
- *ret = existing;
- return 1;
- }
+ existing = set_get(m->rules_foreign, &rule);
+ if (existing) {
+ if (ret)
+ *ret = existing;
+ return 1;
}
return -ENOENT;
uint8_t tos,
uint32_t fwmark,
uint32_t table,
- char *iif,
- char *oif,
+ const char *_iif,
+ const char *_oif,
RoutingPolicyRule **ret) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
+ _cleanup_free_ char *iif = NULL, *oif = NULL;
int r;
assert_return(rules, -EINVAL);
+ if (_iif) {
+ iif = strdup(_iif);
+ if (!iif)
+ return -ENOMEM;
+ }
+
+ if (_oif) {
+ oif = strdup(_oif);
+ if (!oif)
+ return -ENOMEM;
+ }
+
r = routing_policy_rule_new(&rule);
if (r < 0)
return r;
rule->tos = tos;
rule->fwmark = fwmark;
rule->table = table;
- rule->iif = iif;
- rule->oif = oif;
+ rule->iif = TAKE_PTR(iif);
+ rule->oif = TAKE_PTR(oif);
r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
if (r < 0)
uint8_t tos,
uint32_t fwmark,
uint32_t table,
- char *iif,
- char *oif,
+ const char *iif,
+ const char *oif,
RoutingPolicyRule **ret) {
return routing_policy_rule_add_internal(m, &m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, ret);
uint8_t tos,
uint32_t fwmark,
uint32_t table,
- char *iif,
- char *oif,
+ const char *iif,
+ const char *oif,
RoutingPolicyRule **ret) {
return routing_policy_rule_add_internal(m, &m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, ret);
}
if (r < 0)
return r;
- rule->section = n;
+ rule->section = TAKE_PTR(n);
rule->network = network;
- n = NULL;
r = hashmap_put(network->rules_by_section, rule->section, rule);
if (r < 0)
int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
int routing_policy_rule_add(Manager *m, int family, const union in_addr_union *from, uint8_t from_prefixlen, const union in_addr_union *to, uint8_t to_prefixlen,
- uint8_t tos, uint32_t fwmark, uint32_t table, char *iif, char *oif, RoutingPolicyRule **ret);
+ uint8_t tos, uint32_t fwmark, uint32_t table, const char *iif, const char *oif, RoutingPolicyRule **ret);
int routing_policy_rule_add_foreign(Manager *m, int family, const union in_addr_union *from, uint8_t from_prefixlen, const union in_addr_union *to, uint8_t to_prefixlen,
- uint8_t tos, uint32_t fwmark, uint32_t table, char *iif, char *oif, RoutingPolicyRule **ret);
+ uint8_t tos, uint32_t fwmark, uint32_t table, const char *iif, const char *oif, RoutingPolicyRule **ret);
int routing_policy_rule_get(Manager *m, int family, const union in_addr_union *from, uint8_t from_prefixlen, const union in_addr_union *to, uint8_t to_prefixlen, uint8_t tos,
- uint32_t fwmark, uint32_t table, char *iif, char *oif, RoutingPolicyRule **ret);
+ uint32_t fwmark, uint32_t table, const char *iif, const char *oif, RoutingPolicyRule **ret);
int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule);
int routing_policy_serialize_rules(Set *rules, FILE *f);
int routing_policy_load_rules(const char *state_file, Set **rules);
if (r < 0)
return log_error_errno(r, "Failed to chown() cgroup %s: %m", fs);
- if (unified_requested == CGROUP_UNIFIED_SYSTEMD) {
+ if (unified_requested == CGROUP_UNIFIED_SYSTEMD || (unified_requested == CGROUP_UNIFIED_NONE && cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0)) {
_cleanup_free_ char *lfs = NULL;
/* Always propagate access rights from unified to legacy controller */
/* Then we list outer child mounts (i.e. mounts applied *before* entering user namespacing) */
{ "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- MOUNT_FATAL },
+ MOUNT_FATAL|MOUNT_APPLY_TMPFS_TMP },
{ "tmpfs", "/sys", "tmpfs", "mode=555", MS_NOSUID|MS_NOEXEC|MS_NODEV,
MOUNT_FATAL|MOUNT_APPLY_APIVFS_NETNS },
{ "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,
bool netns = (mount_settings & MOUNT_APPLY_APIVFS_NETNS);
bool ro = (mount_settings & MOUNT_APPLY_APIVFS_RO);
bool in_userns = (mount_settings & MOUNT_IN_USERNS);
+ bool tmpfs_tmp = (mount_settings & MOUNT_APPLY_TMPFS_TMP);
size_t k;
int r;
if (!ro && (bool)(mount_table[k].mount_settings & MOUNT_APPLY_APIVFS_RO))
continue;
+ if (!tmpfs_tmp && (bool)(mount_table[k].mount_settings & MOUNT_APPLY_TMPFS_TMP))
+ continue;
+
r = chase_symlinks(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].where);
MOUNT_APPLY_APIVFS_NETNS = 1 << 4, /* if set, /proc/sys/net will be mounted read-write.
Works only if MOUNT_APPLY_APIVFS_RO is also set. */
MOUNT_INACCESSIBLE_REG = 1 << 5, /* if set, create an inaccessible regular file first and use as bind mount source */
+ MOUNT_APPLY_TMPFS_TMP = 1 << 6, /* if set, /tmp will be mounted as tmpfs */
} MountSettingsMask;
typedef enum CustomMountType {
*/
};
- int r, c = 0;
+ int r;
size_t i;
char **p;
if (whitelist[i].capability != 0 && (cap_list_retain & (1ULL << whitelist[i].capability)) == 0)
continue;
- r = seccomp_add_syscall_filter_item(ctx, whitelist[i].name, SCMP_ACT_ALLOW, syscall_blacklist);
+ r = seccomp_add_syscall_filter_item(ctx, whitelist[i].name, SCMP_ACT_ALLOW, syscall_blacklist, false);
if (r < 0)
- /* If the system call is not known on this architecture, then that's fine, let's ignore it */
- log_debug_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m", whitelist[i].name, seccomp_arch_to_string(arch));
- else
- c++;
+ return log_error_errno(r, "Failed to add syscall filter item %s: %m", whitelist[i].name);
}
STRV_FOREACH(p, syscall_whitelist) {
- r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist);
+ r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, false);
if (r < 0)
- log_debug_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m", *p, seccomp_arch_to_string(arch));
- else
- c++;
+ log_warning_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m",
+ *p, seccomp_arch_to_string(arch));
}
- return c;
+ return 0;
}
int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist) {
static bool arg_notify_ready = false;
static bool arg_use_cgns = true;
static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS;
-static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO;
+static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_TMPFS_TMP;
static void *arg_root_hash = NULL;
static size_t arg_root_hash_size = 0;
static char **arg_syscall_whitelist = NULL;
}
static void parse_mount_settings_env(void) {
- int r;
const char *e;
+ int r;
+
+ r = getenv_bool("SYSTEMD_NSPAWN_TMPFS_TMP");
+ if (r >= 0)
+ SET_FLAG(arg_mount_settings, MOUNT_APPLY_TMPFS_TMP, r > 0);
+ else if (r != -ENXIO)
+ log_warning_errno(r, "Failed to parse $SYSTEMD_NSPAWN_TMPFS_TMP, ignoring: %m");
e = getenv("SYSTEMD_NSPAWN_API_VFS_WRITABLE");
if (!e)
}
}
- if (!arg_quiet)
- log_info("Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
+ "Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
}
if (dissected_image) {
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
BTRFS_SNAPSHOT_RECURSIVE |
BTRFS_SNAPSHOT_QUOTA);
- if (r == -EEXIST) {
- if (!arg_quiet)
- log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
- } else if (r < 0) {
+ if (r == -EEXIST)
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
+ "Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
+ else if (r < 0) {
log_error_errno(r, "Couldn't create snapshot %s from %s: %m", arg_directory, arg_template);
goto finish;
- } else {
- if (!arg_quiet)
- log_info("Populated %s from template %s.", arg_directory, arg_template);
- }
+ } else
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
+ "Populated %s from template %s.", arg_directory, arg_template);
}
}
if (r < 0)
return log_error_errno(r, "Failed to register dnssd enumerator: %m");
- r = bus_request_name_async_may_reload_dbus(m->bus, NULL, "org.freedesktop.resolve1", 0, NULL);
+ r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.resolve1", 0, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to request name: %m");
return bus_log_create_error(r);
} else {
- r = in_addr_prefix_from_string_auto(eq, &family, &prefix, &prefixlen);
- if (r < 0)
- return log_error_errno(r, "Failed to parse IP address prefix: %s", eq);
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
- r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
- if (r < 0)
- return bus_log_create_error(r);
+ r = extract_first_word(&eq, &word, NULL, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s: %s", field, eq);
+
+ r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
+
+ r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
}
r = sd_bus_message_close_container(m);
return bus_append_parse_boolean(m, field, eq);
- if (STR_IN_SET(field, "KillSignal", "FinalKillSignal"))
+ if (STR_IN_SET(field, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
return bus_append_signal_from_string(m, field, eq);
return 0;
}
-struct request_name_data {
- unsigned n_ref;
-
- const char *name;
- uint64_t flags;
- void *userdata;
-};
-
-static void request_name_destroy_callback(void *userdata) {
- struct request_name_data *data = userdata;
-
- assert(data);
- assert(data->n_ref > 0);
-
- log_debug("%s n_ref=%u", __func__, data->n_ref);
-
- data->n_ref--;
- if (data->n_ref == 0)
- free(data);
-}
-
-static int reload_dbus_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- struct request_name_data *data = userdata;
- const sd_bus_error *e;
- int r;
-
- assert(data);
- assert(data->name);
- assert(data->n_ref > 0);
-
- e = sd_bus_message_get_error(m);
- if (e) {
- log_error_errno(sd_bus_error_get_errno(e), "Failed to reload DBus configuration: %s", e->message);
- return 1;
- }
-
- /* Here, use the default request name handler to avoid an infinite loop of reloading and requesting. */
- r = sd_bus_request_name_async(sd_bus_message_get_bus(m), NULL, data->name, data->flags, NULL, data->userdata);
- if (r < 0)
- log_error_errno(r, "Failed to request name: %m");
-
- return 1;
-}
-
-static int request_name_handler_may_reload_dbus(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- struct request_name_data *data = userdata;
- uint32_t ret;
- int r;
-
- assert(m);
- assert(data);
-
- if (sd_bus_message_is_method_error(m, NULL)) {
- const sd_bus_error *e = sd_bus_message_get_error(m);
- _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
-
- if (!sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED)) {
- log_debug_errno(sd_bus_error_get_errno(e),
- "Unable to request name, failing connection: %s",
- e->message);
-
- bus_enter_closing(sd_bus_message_get_bus(m));
- return 1;
- }
-
- log_debug_errno(sd_bus_error_get_errno(e),
- "Unable to request name, will retry after reloading DBus configuration: %s",
- e->message);
-
- /* If a service enables DynamicUser= and dbus.service started before the dynamic user is realized,
- * then the DBus policy about the service has not been enabled yet. So, let's try to reload DBus
- * configuration, and after that request the name again. Note that it seems that no privileges are
- * necessary to call the following method. */
-
- r = sd_bus_call_method_async(
- sd_bus_message_get_bus(m),
- &slot,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "ReloadConfig",
- reload_dbus_handler,
- data, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to reload DBus configuration: %m");
- bus_enter_closing(sd_bus_message_get_bus(m));
- return 1;
- }
-
- data->n_ref ++;
- assert_se(sd_bus_slot_set_destroy_callback(slot, request_name_destroy_callback) >= 0);
-
- r = sd_bus_slot_set_floating(slot, true);
- if (r < 0)
- return r;
-
- return 1;
- }
-
- r = sd_bus_message_read(m, "u", &ret);
- if (r < 0)
- return r;
-
- switch (ret) {
-
- case BUS_NAME_ALREADY_OWNER:
- log_debug("Already owner of requested service name, ignoring.");
- return 1;
-
- case BUS_NAME_IN_QUEUE:
- log_debug("In queue for requested service name.");
- return 1;
-
- case BUS_NAME_PRIMARY_OWNER:
- log_debug("Successfully acquired requested service name.");
- return 1;
-
- case BUS_NAME_EXISTS:
- log_debug("Requested service name already owned, failing connection.");
- bus_enter_closing(sd_bus_message_get_bus(m));
- return 1;
- }
-
- log_debug("Unexpected response from RequestName(), failing connection.");
- bus_enter_closing(sd_bus_message_get_bus(m));
- return 1;
-}
-
-int bus_request_name_async_may_reload_dbus(sd_bus *bus, sd_bus_slot **ret_slot, const char *name, uint64_t flags, void *userdata) {
- _cleanup_free_ struct request_name_data *data = NULL;
- _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
- int r;
-
- data = new(struct request_name_data, 1);
- if (!data)
- return -ENOMEM;
-
- *data = (struct request_name_data) {
- .n_ref = 1,
- .name = name,
- .flags = flags,
- .userdata = userdata,
- };
-
- r = sd_bus_request_name_async(bus, &slot, name, flags, request_name_handler_may_reload_dbus, data);
- if (r < 0)
- return r;
-
- assert_se(sd_bus_slot_set_destroy_callback(slot, request_name_destroy_callback) >= 0);
- TAKE_PTR(data);
-
- if (ret_slot)
- *ret_slot = TAKE_PTR(slot);
- else {
- r = sd_bus_slot_set_floating(slot, true);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
int bus_reply_pair_array(sd_bus_message *m, char **l) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
char **k, **v;
return bus_open_system_watch_bind_with_description(ret, NULL);
}
-int bus_request_name_async_may_reload_dbus(sd_bus *bus, sd_bus_slot **ret_slot, const char *name, uint64_t flags, void *userdata);
-
int bus_reply_pair_array(sd_bus_message *m, char **l);
log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r));
if (r == IDN2_2HYPHEN)
- /* The name has two hypens — forbidden by IDNA2008 in some cases */
+ /* The name has two hyphens — forbidden by IDNA2008 in some cases */
return 0;
if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL))
return -ENOSPC;
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <stdio.h>
+
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "id128-print.h"
+#include "log.h"
+#include "terminal-util.h"
+
+int id128_pretty_print(sd_id128_t id, bool pretty) {
+ unsigned i;
+ _cleanup_free_ char *man_link = NULL, *mod_link = NULL;
+ const char *on, *off;
+
+ if (!pretty) {
+ printf(SD_ID128_FORMAT_STR "\n",
+ SD_ID128_FORMAT_VAL(id));
+ return 0;
+ }
+
+ on = ansi_highlight();
+ off = ansi_normal();
+
+ if (terminal_urlify("man:systemd-id128(1)", "systemd-id128(1)", &man_link) < 0)
+ return log_oom();
+
+ if (terminal_urlify("https://docs.python.org/3/library/uuid.html", "uuid", &mod_link) < 0)
+ return log_oom();
+
+ printf("As string:\n"
+ "%s" SD_ID128_FORMAT_STR "%s\n\n"
+ "As UUID:\n"
+ "%s%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%s\n\n"
+ "As %s macro:\n"
+ "%s#define MESSAGE_XYZ SD_ID128_MAKE(",
+ on, SD_ID128_FORMAT_VAL(id), off,
+ on, SD_ID128_FORMAT_VAL(id), off,
+ man_link,
+ on);
+ for (i = 0; i < 16; i++)
+ printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
+ printf(")%s\n\n", off);
+
+ printf("As Python constant:\n"
+ ">>> import %s\n"
+ ">>> %sMESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')%s\n",
+ mod_link,
+ on, SD_ID128_FORMAT_VAL(id), off);
+
+ return 0;
+}
+
+int id128_print_new(bool pretty) {
+ sd_id128_t id;
+ int r;
+
+ r = sd_id128_randomize(&id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate ID: %m");
+
+ return id128_pretty_print(id, pretty);
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "sd-id128.h"
+
+int id128_pretty_print(sd_id128_t id, bool pretty);
+int id128_print_new(bool pretty);
if (q < 0)
return q;
- r = install_info_traverse(scope, c, paths, i, flags, NULL);
- if (r < 0) {
+ q = install_info_traverse(scope, c, paths, i, flags, NULL);
+ if (q < 0) {
unit_file_changes_add(changes, n_changes, r, i->name, NULL);
- return r;
+ return q;
}
/* We can attempt to process a masked unit when a different unit
generator.c
generator.h
gpt.h
+ id128-print.c
+ id128-print.h
ima-util.c
ima-util.h
import-util.c
switch-root.h
sysctl-util.c
sysctl-util.h
- tests.c
- tests.h
tomoyo-util.c
tomoyo-util.h
udev-util.h
wireguard-netlink.h
'''.split())
+if get_option('tests') != 'false'
+ shared_sources += files('tests.c', 'tests.h')
+endif
+
test_tables_h = files('test-tables.h')
shared_sources += test_tables_h
return NULL;
}
-static int seccomp_add_syscall_filter_set(scmp_filter_ctx seccomp, const SyscallFilterSet *set, uint32_t action, char **exclude);
-
-int seccomp_add_syscall_filter_item(scmp_filter_ctx *seccomp, const char *name, uint32_t action, char **exclude) {
- int r;
+static int seccomp_add_syscall_filter_set(scmp_filter_ctx seccomp, const SyscallFilterSet *set, uint32_t action, char **exclude, bool log_missing);
+int seccomp_add_syscall_filter_item(scmp_filter_ctx *seccomp, const char *name, uint32_t action, char **exclude, bool log_missing) {
assert(seccomp);
assert(name);
return -EINVAL;
}
- r = seccomp_add_syscall_filter_set(seccomp, other, action, exclude);
- if (r < 0)
- return r;
+ return seccomp_add_syscall_filter_set(seccomp, other, action, exclude, log_missing);
+
} else {
- int id;
+ int id, r;
id = seccomp_syscall_resolve_name(name);
if (id == __NR_SCMP_ERROR) {
- log_debug("System call %s is not known, ignoring.", name);
+ if (log_missing)
+ log_debug("System call %s is not known, ignoring.", name);
return 0;
}
r = seccomp_rule_add_exact(seccomp, action, id, 0);
- if (r < 0)
+ if (r < 0) {
/* If the system call is not known on this architecture, then that's fine, let's ignore it */
- log_debug_errno(r, "Failed to add rule for system call %s() / %d, ignoring: %m", name, id);
- }
+ bool ignore = r == -EDOM;
- return 0;
+ if (!ignore || log_missing)
+ log_debug_errno(r, "Failed to add rule for system call %s() / %d%s: %m",
+ name, id, ignore ? ", ignoring" : "");
+ if (!ignore)
+ return r;
+ }
+
+ return 0;
+ }
}
static int seccomp_add_syscall_filter_set(
scmp_filter_ctx seccomp,
const SyscallFilterSet *set,
uint32_t action,
- char **exclude) {
+ char **exclude,
+ bool log_missing) {
const char *sys;
int r;
assert(set);
NULSTR_FOREACH(sys, set->value) {
- r = seccomp_add_syscall_filter_item(seccomp, sys, action, exclude);
+ r = seccomp_add_syscall_filter_item(seccomp, sys, action, exclude, log_missing);
if (r < 0)
return r;
}
return 0;
}
-int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action) {
+int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action, bool log_missing) {
uint32_t arch;
int r;
if (r < 0)
return r;
- r = seccomp_add_syscall_filter_set(seccomp, set, action, NULL);
- if (r < 0) {
- log_debug_errno(r, "Failed to add filter set, ignoring: %m");
- continue;
- }
+ r = seccomp_add_syscall_filter_set(seccomp, set, action, NULL, log_missing);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to add filter set: %m");
r = seccomp_load(seccomp);
if (IN_SET(r, -EPERM, -EACCES))
return 0;
}
-int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, uint32_t action) {
+int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, uint32_t action, bool log_missing) {
uint32_t arch;
int r;
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
Iterator i;
- void *id, *val;
+ void *syscall_id, *val;
log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch));
if (r < 0)
return r;
- HASHMAP_FOREACH_KEY(val, id, set, i) {
+ HASHMAP_FOREACH_KEY(val, syscall_id, set, i) {
uint32_t a = action;
- int e = PTR_TO_INT(val);
+ int id = PTR_TO_INT(syscall_id) - 1;
+ int error = PTR_TO_INT(val);
- if (action != SCMP_ACT_ALLOW && e >= 0)
- a = SCMP_ACT_ERRNO(e);
+ if (action != SCMP_ACT_ALLOW && error >= 0)
+ a = SCMP_ACT_ERRNO(error);
- r = seccomp_rule_add_exact(seccomp, a, PTR_TO_INT(id) - 1, 0);
+ r = seccomp_rule_add_exact(seccomp, a, id, 0);
if (r < 0) {
/* If the system call is not known on this architecture, then that's fine, let's ignore it */
_cleanup_free_ char *n = NULL;
-
- n = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
- log_debug_errno(r, "Failed to add rule for system call %s() / %d, ignoring: %m", strna(n), PTR_TO_INT(id) - 1);
+ bool ignore;
+
+ n = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, id);
+ ignore = r == -EDOM;
+ if (!ignore || log_missing)
+ log_debug_errno(r, "Failed to add rule for system call %s() / %d%s: %m",
+ strna(n), id, ignore ? ", ignoring" : "");
+ if (!ignore)
+ return r;
}
}
int seccomp_filter_set_add(Hashmap *s, bool b, const SyscallFilterSet *set);
-int seccomp_add_syscall_filter_item(scmp_filter_ctx *ctx, const char *name, uint32_t action, char **exclude);
+int seccomp_add_syscall_filter_item(scmp_filter_ctx *ctx, const char *name, uint32_t action, char **exclude, bool log_missing);
-int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action);
-int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, uint32_t action);
+int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action, bool log_missing);
+int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, uint32_t action, bool log_missing);
typedef enum SeccompParseFlags {
SECCOMP_PARSE_INVERT = 1 << 0,
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include <stdbool.h>
+
char* setup_fake_runtime_dir(void);
const char* get_testdata_dir(void);
const char* get_catalog_dir(void);
sd-bus-protocol.h
sd-bus-vtable.h
sd-daemon.h
+ sd-device.h
sd-event.h
+ sd-hwdb.h
sd-id128.h
sd-journal.h
sd-login.h
# https://github.com/mesonbuild/meson/issues/1633
systemd_headers = files(_systemd_headers)
-# sd-device.h
-# sd-hwdb.h
-# sd-dhcp6-client.h
-# sd-dhcp6-lease.h
-# sd-dhcp-client.h
-# sd-dhcp-lease.h
-# sd-dhcp-server.h
-# sd-ipv4acd.h
-# sd-ipv4ll.h
-# sd-lldp.h
-# sd-ndisc.h
-# sd-netlink.h
-# sd-network.h
-# sd-path.h
-# sd-resolve.h
-# sd-utf8.h
+_not_installed_headers = '''
+ sd-dhcp6-client.h
+ sd-dhcp6-lease.h
+ sd-dhcp-client.h
+ sd-dhcp-lease.h
+ sd-dhcp-server.h
+ sd-ipv4acd.h
+ sd-ipv4ll.h
+ sd-lldp.h
+ sd-ndisc.h
+ sd-netlink.h
+ sd-network.h
+ sd-path.h
+ sd-radv.h
+ sd-resolve.h
+ sd-utf8.h
+'''.split()
install_headers(
systemd_headers,
endif
endif
-foreach header : _systemd_headers
+foreach header : _systemd_headers + _not_installed_headers
foreach opt : opts
name = ''.join([header, ':'] + opt)
if want_tests != 'false'
int *request);
int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client,
int request);
+int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transaction_id);
int sd_dhcp6_client_get_lease(
sd_dhcp6_client *client,
int sd_id128_get_machine(sd_id128_t *ret);
int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret);
+int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
int sd_id128_get_boot(sd_id128_t *ret);
int sd_id128_get_invocation(sd_id128_t *ret);
_SD_BEGIN_DECLARATIONS;
-/* Hey! If you add a new message here, you *must* also update the
- * message catalog with an appropriate explanation */
+/* Hey! If you add a new message here, you *must* also update the message catalog with an appropriate explanation */
-/* And if you add a new ID here, make sure to generate a random one
- * with journalctl --new-id128. Do not use any other IDs, and do not
- * count them up manually. */
+/* And if you add a new ID here, make sure to generate a random one with "systemd-id128 new". Do not use any other IDs,
+ * and do not count them up manually. */
#define SD_MESSAGE_JOURNAL_START SD_ID128_MAKE(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
#define SD_MESSAGE_JOURNAL_START_STR SD_ID128_MAKE_STR(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
***/
#include <inttypes.h>
+#include <linux/neighbour.h>
+#include <linux/rtnetlink.h>
+#include <net/ethernet.h>
#include <netinet/ether.h>
#include <netinet/in.h>
-#include <linux/rtnetlink.h>
-#include <linux/neighbour.h>
#include "sd-event.h"
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+/* 'struct addrinfo' needs _GNU_SOURCE */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
#include <inttypes.h>
#include <netdb.h>
#include <sys/socket.h>
libacl],
'', 'manual', '-DLOG_REALM=LOG_REALM_UDEV'],
+ [['src/test/test-udev-build-argv.c'],
+ [libudev_core,
+ libudev_static,
+ libsystemd_network,
+ libshared],
+ [threads,
+ librt,
+ libblkid,
+ libkmod,
+ libacl],
+ '', '', '-DLOG_REALM=LOG_REALM_UDEV'],
+
[['src/test/test-id128.c'],
[],
[]],
[['src/test/test-bus-util.c'],
[],
[]],
+
+ [['src/test/test-sd-hwdb.c'],
+ [],
+ []],
]
############################################################
[['src/libsystemd/sd-login/test-login.c'],
[],
[]],
+
+ [['src/libsystemd/sd-device/test-sd-device.c'],
+ [],
+ []],
]
if cxx.found()
#include "log.h"
#include "tests.h"
-static void test_name_async(unsigned n_messages) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- int r;
- unsigned i;
-
- log_info("/* %s (%u) */", __func__, n_messages);
-
- r = bus_open_system_watch_bind_with_description(&bus, "test-bus");
- if (r < 0) {
- log_error_errno(r, "Failed to connect to bus: %m");
- return;
- }
-
- r = bus_request_name_async_may_reload_dbus(bus, NULL, "org.freedesktop.systemd.test-bus-util", 0, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to request name: %m");
- return;
- }
-
- for (i = 0; i < n_messages; i++) {
- r = sd_bus_process(bus, NULL);
- log_debug("stage %u: sd_bus_process returned %d", i, r);
- if (r < 0) {
- log_notice_errno(r, "Processing failed: %m");
- return;
- }
-
- if (r > 0 && i + 1 < n_messages)
- (void) sd_bus_wait(bus, USEC_PER_SEC / 3);
- }
-}
-
static int callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
return 1;
}
int main(int argc, char **argv) {
test_setup_logging(LOG_DEBUG);
- test_name_async(0);
- test_name_async(20);
test_destroy_callback();
return 0;
#include "util.h"
#include "virt.h"
+static bool can_unshare = true;
+
typedef void (*test_function_t)(Manager *m);
static void check(Manager *m, Unit *unit, int status_expected, int code_expected) {
assert_se(mkdir_p("/tmp/test-exec-bindpaths", 0755) >= 0);
assert_se(mkdir_p("/tmp/test-exec-bindreadonlypaths", 0755) >= 0);
- test(m, "exec-bindpaths.service", 0, CLD_EXITED);
+ test(m, "exec-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
(void) rm_rf("/tmp/test-exec-bindpaths", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/tmp/test-exec-bindreadonlypaths", REMOVE_ROOT|REMOVE_PHYSICAL);
static void test_exec_privatetmp(Manager *m) {
assert_se(touch("/tmp/test-exec_privatetmp") >= 0);
- test(m, "exec-privatetmp-yes.service", 0, CLD_EXITED);
+ test(m, "exec-privatetmp-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatetmp-no.service", 0, CLD_EXITED);
unlink("/tmp/test-exec_privatetmp");
return;
}
- test(m, "exec-privatedevices-yes.service", 0, CLD_EXITED);
+ test(m, "exec-privatedevices-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatedevices-no.service", 0, CLD_EXITED);
- test(m, "exec-privatedevices-disabled-by-prefix.service", 0, CLD_EXITED);
+ test(m, "exec-privatedevices-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
/* We use capsh to test if the capabilities are
* properly set, so be sure that it exists */
test(m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
test(m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
- test(m, "exec-protectkernelmodules-yes-mount-propagation.service", 0, CLD_EXITED);
+ test(m, "exec-protectkernelmodules-yes-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_readonlypaths(Manager *m) {
- test(m, "exec-readonlypaths-simple.service", 0, CLD_EXITED);
+ test(m, "exec-readonlypaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
if (path_is_read_only_fs("/var") > 0) {
log_notice("Directory /var is readonly, skipping remaining tests in %s", __func__);
return;
}
- test(m, "exec-readonlypaths.service", 0, CLD_EXITED);
- test(m, "exec-readonlypaths-mount-propagation.service", 0, CLD_EXITED);
- test(m, "exec-readonlypaths-with-bindpaths.service", 0, CLD_EXITED);
+ test(m, "exec-readonlypaths.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+ test(m, "exec-readonlypaths-with-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-readonlypaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_readwritepaths(Manager *m) {
return;
}
- test(m, "exec-readwritepaths-mount-propagation.service", 0, CLD_EXITED);
+ test(m, "exec-readwritepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_inaccessiblepaths(Manager *m) {
return;
}
- test(m, "exec-inaccessiblepaths-proc.service", 0, CLD_EXITED);
+ test(m, "exec-inaccessiblepaths-proc.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
if (path_is_read_only_fs("/") > 0) {
log_notice("Root directory is readonly, skipping remaining tests in %s", __func__);
return;
}
- test(m, "exec-inaccessiblepaths-mount-propagation.service", 0, CLD_EXITED);
+ test(m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_temporaryfilesystem(Manager *m) {
- test(m, "exec-temporaryfilesystem-options.service", 0, CLD_EXITED);
- test(m, "exec-temporaryfilesystem-ro.service", 0, CLD_EXITED);
- test(m, "exec-temporaryfilesystem-rw.service", 0, CLD_EXITED);
- test(m, "exec-temporaryfilesystem-usr.service", 0, CLD_EXITED);
+ test(m, "exec-temporaryfilesystem-options.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-temporaryfilesystem-ro.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-temporaryfilesystem-rw.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-temporaryfilesystem-usr.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
}
static void test_exec_systemcallfilter(Manager *m) {
#if HAVE_SECCOMP
+ int r;
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
test(m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
test(m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
test(m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
+
+ r = find_binary("python3", NULL);
+ if (r < 0) {
+ log_notice_errno(r, "Skipping remaining tests in %s, could not find python3 binary: %m", __func__);
+ return;
+ }
+
test(m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
test(m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
+ test(m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED);
#endif
}
static void test_exec_systemcallerrornumber(Manager *m) {
#if HAVE_SECCOMP
+ int r;
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
}
+ r = find_binary("python3", NULL);
+ if (r < 0) {
+ log_notice_errno(r, "Skipping %s, could not find python3 binary: %m", __func__);
+ return;
+ }
+
test(m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED);
test(m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED);
#endif
return;
}
- test(m, "exec-restrictnamespaces-no.service", 0, CLD_EXITED);
+ test(m, "exec-restrictnamespaces-no.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
- test(m, "exec-restrictnamespaces-mnt.service", 0, CLD_EXITED);
+ test(m, "exec-restrictnamespaces-mnt.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-restrictnamespaces-mnt-blacklist.service", 1, CLD_EXITED);
- test(m, "exec-restrictnamespaces-merge-and.service", 0, CLD_EXITED);
- test(m, "exec-restrictnamespaces-merge-or.service", 0, CLD_EXITED);
- test(m, "exec-restrictnamespaces-merge-all.service", 0, CLD_EXITED);
+ test(m, "exec-restrictnamespaces-merge-and.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+ test(m, "exec-restrictnamespaces-merge-or.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+ test(m, "exec-restrictnamespaces-merge-all.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
#endif
}
}
static void test_exec_dynamicuser(Manager *m) {
- test(m, "exec-dynamicuser-fixeduser.service", 0, CLD_EXITED);
+
+ test(m, "exec-dynamicuser-fixeduser.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
if (check_user_has_group_with_same_name("adm"))
- test(m, "exec-dynamicuser-fixeduser-adm.service", 0, CLD_EXITED);
+ test(m, "exec-dynamicuser-fixeduser-adm.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
if (check_user_has_group_with_same_name("games"))
- test(m, "exec-dynamicuser-fixeduser-games.service", 0, CLD_EXITED);
- test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", 0, CLD_EXITED);
- test(m, "exec-dynamicuser-supplementarygroups.service", 0, CLD_EXITED);
- test(m, "exec-dynamicuser-statedir.service", 0, CLD_EXITED);
+ test(m, "exec-dynamicuser-fixeduser-games.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+ test(m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
- test(m, "exec-dynamicuser-statedir-migrate-step2.service", 0, CLD_EXITED);
+ test(m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
return;
}
- test(m, "exec-privatenetwork-yes.service", 0, CLD_EXITED);
+ test(m, "exec-privatenetwork-yes.service", can_unshare ? 0 : EXIT_NETWORK, CLD_EXITED);
}
static void test_exec_oomscoreadjust(Manager *m) {
test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
+
+ if (detect_container() > 0) {
+ log_notice("Testing in container, skipping remaining tests in %s", __func__);
+ return;
+ }
test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
}
static void test_exec_ioschedulingclass(Manager *m) {
test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
- test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
+
+ if (detect_container() > 0) {
+ log_notice("Testing in container, skipping remaining tests in %s", __func__);
+ return;
+ }
+ test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
}
static void test_exec_unsetenvironment(Manager *m) {
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
_cleanup_free_ char *test_execute_path = NULL;
+ _cleanup_hashmap_free_ Hashmap *s = NULL;
static const test_function_t user_tests[] = {
test_exec_basic,
test_exec_ambientcapabilities,
assert_se(unsetenv("VAR2") == 0);
assert_se(unsetenv("VAR3") == 0);
+ r = run_tests(UNIT_FILE_USER, user_tests);
+ if (r != 0)
+ return r;
+
+ r = run_tests(UNIT_FILE_SYSTEM, system_tests);
+ if (r != 0)
+ return r;
+
+#if HAVE_SECCOMP
+ /* The following tests are for 1beab8b0d0ff2d7d1436b52d4a0c3d56dc908962. */
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping unshare() filtered tests.");
+ return 0;
+ }
+
+ assert_se(s = hashmap_new(NULL));
+ r = seccomp_syscall_resolve_name("unshare");
+ assert_se(r != __NR_SCMP_ERROR);
+ assert_se(hashmap_put(s, UINT32_TO_PTR(r + 1), INT_TO_PTR(-1)) >= 0);
+ assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EOPNOTSUPP), true) >= 0);
+ assert_se(unshare(CLONE_NEWNS) < 0);
+ assert_se(errno == EOPNOTSUPP);
+
+ can_unshare = false;
+
r = run_tests(UNIT_FILE_USER, user_tests);
if (r != 0)
return r;
return run_tests(UNIT_FILE_SYSTEM, system_tests);
+#else
+ return 0;
+#endif
}
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
#include "user-util.h"
#include "util.h"
+#include "virt.h"
+
+static const char *arg_test_dir = NULL;
static void test_chase_symlinks(void) {
_cleanup_free_ char *result = NULL;
- char temp[] = "/tmp/test-chase.XXXXXX";
+ char *temp;
const char *top, *p, *pslash, *q, *qslash;
struct stat st;
int r, pfd;
+ log_info("/* %s */", __func__);
+
+ temp = strjoina(arg_test_dir ?: "/tmp", "/test-chase.XXXXXX");
assert_se(mkdtemp(temp));
top = strjoina(temp, "/top");
assert_se(mkdir(top, 0700) >= 0);
p = strjoina(top, "/dot");
- assert_se(symlink(".", p) >= 0);
+ if (symlink(".", p) < 0) {
+ assert_se(IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM));
+ log_tests_skipped_errno(errno, "symlink() not possible");
+ goto cleanup;
+ };
p = strjoina(top, "/dotdot");
assert_se(symlink("..", p) >= 0);
assert_se(streq("/usr", result));
result = mfree(result);
+ cleanup:
assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
static void test_unlink_noerrno(void) {
- char name[] = "/tmp/test-close_nointr.XXXXXX";
+ char *name;
int fd;
+ log_info("/* %s */", __func__);
+
+ name = strjoina(arg_test_dir ?: "/tmp", "/test-close_nointr.XXXXXX");
fd = mkostemp_safe(name);
assert_se(fd >= 0);
assert_se(close_nointr(fd) >= 0);
}
static void test_readlink_and_make_absolute(void) {
- char tempdir[] = "/tmp/test-readlink_and_make_absolute";
- char name[] = "/tmp/test-readlink_and_make_absolute/original";
- char name2[] = "test-readlink_and_make_absolute/original";
- char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias";
- char *r = NULL;
- _cleanup_free_ char *pwd = NULL;
+ const char *tempdir, *name, *name2, *name_alias;
+ _cleanup_free_ char *r1 = NULL, *r2 = NULL, *pwd = NULL;
+
+ log_info("/* %s */", __func__);
+
+ tempdir = strjoina(arg_test_dir ?: "/tmp", "/test-readlink_and_make_absolute");
+ name = strjoina(tempdir, "/original");
+ name2 = "test-readlink_and_make_absolute/original";
+ name_alias = strjoina(arg_test_dir ?: "/tmp", "/test-readlink_and_make_absolute-alias");
assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid(), MKDIR_WARN_MODE) >= 0);
assert_se(touch(name) >= 0);
- assert_se(symlink(name, name_alias) >= 0);
- assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
- assert_se(streq(r, name));
- free(r);
- assert_se(unlink(name_alias) >= 0);
+ if (symlink(name, name_alias) < 0) {
+ assert_se(IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM));
+ log_tests_skipped_errno(errno, "symlink() not possible");
+ } else {
+ assert_se(readlink_and_make_absolute(name_alias, &r1) >= 0);
+ assert_se(streq(r1, name));
+ assert_se(unlink(name_alias) >= 0);
- assert_se(safe_getcwd(&pwd) >= 0);
+ assert_se(safe_getcwd(&pwd) >= 0);
- assert_se(chdir(tempdir) >= 0);
- assert_se(symlink(name2, name_alias) >= 0);
- assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
- assert_se(streq(r, name));
- free(r);
- assert_se(unlink(name_alias) >= 0);
+ assert_se(chdir(tempdir) >= 0);
+ assert_se(symlink(name2, name_alias) >= 0);
+ assert_se(readlink_and_make_absolute(name_alias, &r2) >= 0);
+ assert_se(streq(r2, name));
+ assert_se(unlink(name_alias) >= 0);
- assert_se(chdir(pwd) >= 0);
+ assert_se(chdir(pwd) >= 0);
+ }
assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
static void test_get_files_in_directory(void) {
_cleanup_strv_free_ char **l = NULL, **t = NULL;
- assert_se(get_files_in_directory("/tmp", &l) >= 0);
+ assert_se(get_files_in_directory(arg_test_dir ?: "/tmp", &l) >= 0);
assert_se(get_files_in_directory(".", &t) >= 0);
assert_se(get_files_in_directory(".", NULL) >= 0);
}
_cleanup_free_ char *tmpdir_backup = NULL, *temp_backup = NULL, *tmp_backup = NULL;
const char *tmp_dir = NULL, *t;
+ log_info("/* %s */", __func__);
+
t = getenv("TMPDIR");
if (t) {
tmpdir_backup = strdup(t);
}
static void test_dot_or_dot_dot(void) {
+ log_info("/* %s */", __func__);
+
assert_se(!dot_or_dot_dot(NULL));
assert_se(!dot_or_dot_dot(""));
assert_se(!dot_or_dot_dot("xxx"));
static void test_access_fd(void) {
_cleanup_(rmdir_and_freep) char *p = NULL;
_cleanup_close_ int fd = -1;
+ const char *a;
- assert_se(mkdtemp_malloc("/tmp/access-fd.XXXXXX", &p) >= 0);
+ log_info("/* %s */", __func__);
+
+ a = strjoina(arg_test_dir ?: "/tmp", "/access-fd.XXXXXX");
+ assert_se(mkdtemp_malloc(a, &p) >= 0);
fd = open(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
assert_se(fd >= 0);
struct stat st;
const char *a;
usec_t test_mtime;
+ int r;
+
+ log_info("/* %s */", __func__);
test_uid = geteuid() == 0 ? 65534 : getuid();
test_gid = geteuid() == 0 ? 65534 : getgid();
test_mtime = usec_sub_unsigned(now(CLOCK_REALTIME), USEC_PER_WEEK);
- assert_se(mkdtemp_malloc("/dev/shm/touch-file-XXXXXX", &p) >= 0);
+ a = strjoina(arg_test_dir ?: "/dev/shm", "/touch-file-XXXXXX");
+ assert_se(mkdtemp_malloc(a, &p) >= 0);
a = strjoina(p, "/regular");
- assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
+ r = touch_file(a, false, test_mtime, test_uid, test_gid, 0640);
+ if (r < 0) {
+ assert_se(IN_SET(r, -EINVAL, -ENOSYS, -ENOTTY, -EPERM));
+ log_tests_skipped_errno(errno, "touch_file() not possible");
+ return;
+ }
+
assert_se(lstat(a, &st) >= 0);
assert_se(st.st_uid == test_uid);
assert_se(st.st_gid == test_gid);
if (geteuid() == 0) {
a = strjoina(p, "/cdev");
- assert_se(mknod(a, 0775 | S_IFCHR, makedev(0, 0)) >= 0);
+ r = mknod(a, 0775 | S_IFCHR, makedev(0, 0));
+ if (r < 0 && errno == EPERM && detect_container() > 0) {
+ log_notice("Running in unprivileged container? Skipping remaining tests in %s", __func__);
+ return;
+ }
+ assert_se(r >= 0);
assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
assert_se(lstat(a, &st) >= 0);
assert_se(st.st_uid == test_uid);
_cleanup_close_ int fd = -1;
struct stat st;
- assert_se(tempfn_random_child(NULL, "unlink-deallocation", &p) >= 0);
+ log_info("/* %s */", __func__);
+
+ assert_se(tempfn_random_child(arg_test_dir, "unlink-deallocation", &p) >= 0);
fd = open(p, O_WRONLY|O_CLOEXEC|O_CREAT|O_EXCL, 0600);
assert_se(fd >= 0);
assert_se(unlinkat_deallocate(AT_FDCWD, p, 0) >= 0);
assert_se(fstat(fd, &st) >= 0);
- assert_se(IN_SET(st.st_size, 0, 6)); /* depending on whether hole punching worked the size will be 6 (it worked) or 0 (we had to resort to truncation) */
+ assert_se(IN_SET(st.st_size, 0, 6)); /* depending on whether hole punching worked the size will be 6
+ (it worked) or 0 (we had to resort to truncation) */
assert_se(st.st_blocks == 0);
assert_se(st.st_nlink == 0);
}
static void test_fsync_directory_of_file(void) {
_cleanup_close_ int fd = -1;
- fd = open_tmpfile_unlinkable(NULL, O_RDWR);
+ log_info("/* %s */", __func__);
+
+ fd = open_tmpfile_unlinkable(arg_test_dir, O_RDWR);
assert_se(fd >= 0);
assert_se(fsync_directory_of_file(fd) >= 0);
}
+static void test_rename_noreplace(void) {
+ static const char* const table[] = {
+ "/reg",
+ "/dir",
+ "/fifo",
+ "/socket",
+ "/symlink",
+ NULL
+ };
+
+ _cleanup_(rm_rf_physical_and_freep) char *z = NULL;
+ const char *j = NULL;
+ char **a, **b;
+
+ log_info("/* %s */", __func__);
+
+ if (arg_test_dir)
+ j = strjoina(arg_test_dir, "/testXXXXXX");
+ assert_se(mkdtemp_malloc(j, &z) >= 0);
+
+ j = strjoina(z, table[0]);
+ assert_se(touch(j) >= 0);
+
+ j = strjoina(z, table[1]);
+ assert_se(mkdir(j, 0777) >= 0);
+
+ j = strjoina(z, table[2]);
+ (void) mkfifo(j, 0777);
+
+ j = strjoina(z, table[3]);
+ (void) mknod(j, S_IFSOCK | 0777, 0);
+
+ j = strjoina(z, table[4]);
+ (void) symlink("foobar", j);
+
+ STRV_FOREACH(a, (char**) table) {
+ _cleanup_free_ char *x = NULL, *y = NULL;
+
+ x = strjoin(z, *a);
+ assert_se(x);
+
+ if (access(x, F_OK) < 0) {
+ assert_se(errno == ENOENT);
+ continue;
+ }
+
+ STRV_FOREACH(b, (char**) table) {
+ _cleanup_free_ char *w = NULL;
+
+ w = strjoin(w, *b);
+ assert_se(w);
+
+ if (access(w, F_OK) < 0) {
+ assert_se(errno == ENOENT);
+ continue;
+ }
+
+ assert_se(rename_noreplace(AT_FDCWD, w, AT_FDCWD, y) == -EEXIST);
+ }
+
+ y = strjoin(z, "/somethingelse");
+ assert_se(y);
+
+ assert_se(rename_noreplace(AT_FDCWD, x, AT_FDCWD, y) >= 0);
+ assert_se(rename_noreplace(AT_FDCWD, y, AT_FDCWD, x) >= 0);
+ }
+}
+
int main(int argc, char *argv[]) {
+ test_setup_logging(LOG_INFO);
+
+ arg_test_dir = argv[1];
+
test_unlink_noerrno();
test_get_files_in_directory();
test_readlink_and_make_absolute();
test_touch_file();
test_unlinkat_deallocate();
test_fsync_directory_of_file();
+ test_rename_noreplace();
return 0;
}
unit_file_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-4a.service"), &changes, &n_changes) == 1);
+ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-4a.service"), &changes, &n_changes) == 2);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
assert_se(n_changes == 2);
assert_se(changes[0].type == UNIT_FILE_SYMLINK);
test_path_simplify("///.//", "/.", "/");
test_path_simplify("///.//.///", "/./.", "/");
test_path_simplify("////.././///../.", "/.././../.", "/../..");
- test_path_simplify(".", ".", "");
- test_path_simplify("./", ".", "");
- test_path_simplify(".///.//./.", "./././.", "");
- test_path_simplify(".///.//././/", "./././.", "");
+ test_path_simplify(".", ".", ".");
+ test_path_simplify("./", ".", ".");
+ test_path_simplify(".///.//./.", "./././.", ".");
+ test_path_simplify(".///.//././/", "./././.", ".");
test_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.",
"/./aaa/././.bbb/../c./d.dd/..eeee/.",
"/aaa/.bbb/../c./d.dd/..eeee");
log_info("comm = <%s>", comm);
assert_se(strneq(comm, p, TASK_COMM_LEN-1));
- assert_se(get_process_cmdline(0, 0, false, &cmdline) >= 0);
+ r = get_process_cmdline(0, 0, false, &cmdline);
+ assert_se(r >= 0);
/* we cannot expect cmdline to be renamed properly without privileges */
if (geteuid() == 0) {
- log_info("cmdline = <%s>", cmdline);
- assert_se(strneq(p, cmdline, STRLEN("test-process-util")));
- assert_se(startswith(p, cmdline));
+ if (r == 0 && detect_container() > 0)
+ log_info("cmdline = <%s> (not verified, Running in unprivileged container?)", cmdline);
+ else {
+ log_info("cmdline = <%s>", cmdline);
+ assert_se(strneq(p, cmdline, STRLEN("test-process-util")));
+ assert_se(startswith(p, cmdline));
+ }
} else
log_info("cmdline = <%s> (not verified)", cmdline);
}
--- /dev/null
+#include "sd-hwdb.h"
+
+#include "alloc-util.h"
+#include "errno.h"
+#include "tests.h"
+
+static int test_failed_enumerate(void) {
+ _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb;
+ const char *key, *value;
+ int r;
+
+ log_info("/* %s */", __func__);
+
+ r = sd_hwdb_new(&hwdb);
+ if (r == -ENOENT)
+ return r;
+ assert_se(r == 0);
+
+ assert_se(sd_hwdb_seek(hwdb, "no-such-modalias-should-exist") == 0);
+
+ assert_se(sd_hwdb_enumerate(hwdb, &key, &value) == 0);
+ assert_se(sd_hwdb_enumerate(hwdb, &key, NULL) == -EINVAL);
+ assert_se(sd_hwdb_enumerate(hwdb, NULL, &value) == -EINVAL);
+
+ return 0;
+}
+
+#define DELL_MODALIAS \
+ "evdev:atkbd:dmi:bvnXXX:bvrYYY:bdZZZ:svnDellXXX:pnYYY"
+
+static void test_basic_enumerate(void) {
+ _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb;
+ const char *key, *value;
+ size_t len1 = 0, len2 = 0;
+ int r;
+
+ log_info("/* %s */", __func__);
+
+ assert_se(sd_hwdb_new(&hwdb) == 0);
+
+ assert_se(sd_hwdb_seek(hwdb, DELL_MODALIAS) == 0);
+
+ for (;;) {
+ r = sd_hwdb_enumerate(hwdb, &key, &value);
+ assert(IN_SET(r, 0, 1));
+ if (r == 0)
+ break;
+ assert(key);
+ assert(value);
+ log_debug("A: \"%s\" → \"%s\"", key, value);
+ len1 += strlen(key) + strlen(value);
+ }
+
+ SD_HWDB_FOREACH_PROPERTY(hwdb, DELL_MODALIAS, key, value) {
+ log_debug("B: \"%s\" → \"%s\"", key, value);
+ len2 += strlen(key) + strlen(value);
+ }
+
+ assert_se(len1 == len2);
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+
+ test_setup_logging(LOG_DEBUG);
+
+ r = test_failed_enumerate();
+ if (r < 0)
+ return log_tests_skipped_errno(r, "cannot open hwdb");
+
+ test_basic_enumerate();
+
+ return 0;
+}
uint32_t a, b;
const char *name;
+ log_info("/* %s */", __func__);
+
a = seccomp_arch_native();
assert_se(a > 0);
name = seccomp_arch_to_string(a);
static void test_architecture_table(void) {
const char *n, *n2;
+ log_info("/* %s */", __func__);
+
NULSTR_FOREACH(n,
"native\0"
"x86\0"
}
static void test_syscall_filter_set_find(void) {
+ log_info("/* %s */", __func__);
+
assert_se(!syscall_filter_set_find(NULL));
assert_se(!syscall_filter_set_find(""));
assert_se(!syscall_filter_set_find("quux"));
unsigned i;
int r;
+ log_info("/* %s */", __func__);
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
if (pid == 0) { /* Child? */
int fd;
- /* if we look at the default set (or one that includes it), whitelist instead of blacklist */
+ /* If we look at the default set (or one that includes it), whitelist instead of blacklist */
if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_SYSTEM_SERVICE))
- r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW);
+ r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW, true);
else
- r = seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EUCLEAN));
+ r = seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EUCLEAN), true);
if (r < 0)
_exit(EXIT_FAILURE);
}
}
+static void test_filter_sets_ordered(void) {
+ size_t i;
+
+ log_info("/* %s */", __func__);
+
+ /* Ensure "@default" always remains at the beginning of the list */
+ assert_se(SYSCALL_FILTER_SET_DEFAULT == 0);
+ assert_se(streq(syscall_filter_sets[0].name, "@default"));
+
+ for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
+ const char *k, *p = NULL;
+
+ /* Make sure each group has a description */
+ assert_se(!isempty(syscall_filter_sets[0].help));
+
+ /* Make sure the groups are ordered alphabetically, except for the first entry */
+ assert_se(i < 2 || strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0);
+
+ NULSTR_FOREACH(k, syscall_filter_sets[i].value) {
+
+ /* Ensure each syscall list is in itself ordered, but groups before names */
+ assert_se(!p ||
+ (*p == '@' && *k != '@') ||
+ (((*p == '@' && *k == '@') ||
+ (*p != '@' && *k != '@')) &&
+ strcmp(p, k) < 0));
+
+ p = k;
+ }
+ }
+}
+
static void test_restrict_namespace(void) {
char *s = NULL;
unsigned long ul;
pid_t pid;
+ log_info("/* %s */", __func__);
+
assert_se(namespace_flags_to_string(0, &s) == 0 && streq(s, ""));
s = mfree(s);
assert_se(namespace_flags_to_string(CLONE_NEWNS, &s) == 0 && streq(s, "mnt"));
static void test_protect_sysctl(void) {
pid_t pid;
+ log_info("/* %s */", __func__);
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
static void test_restrict_address_families(void) {
pid_t pid;
+ log_info("/* %s */", __func__);
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
static void test_restrict_realtime(void) {
pid_t pid;
+ log_info("/* %s */", __func__);
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
static void test_memory_deny_write_execute_mmap(void) {
pid_t pid;
+ log_info("/* %s */", __func__);
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
int shmid;
pid_t pid;
+ log_info("/* %s */", __func__);
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
static void test_restrict_archs(void) {
pid_t pid;
+ log_info("/* %s */", __func__);
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
static void test_load_syscall_filter_set_raw(void) {
pid_t pid;
+ log_info("/* %s */", __func__);
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
assert_se(access("/", F_OK) >= 0);
assert_se(poll(NULL, 0, 0) == 0);
- assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, SCMP_ACT_KILL) >= 0);
+ assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, SCMP_ACT_KILL, true) >= 0);
assert_se(access("/", F_OK) >= 0);
assert_se(poll(NULL, 0, 0) == 0);
assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(-1)) >= 0);
#endif
- assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN)) >= 0);
+ assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0);
assert_se(access("/", F_OK) < 0);
assert_se(errno == EUCLEAN);
assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(EILSEQ)) >= 0);
#endif
- assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN)) >= 0);
+ assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0);
assert_se(access("/", F_OK) < 0);
assert_se(errno == EILSEQ);
assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(-1)) >= 0);
#endif
- assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH)) >= 0);
+ assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH), true) >= 0);
assert_se(access("/", F_OK) < 0);
assert_se(errno == EILSEQ);
assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(EILSEQ)) >= 0);
#endif
- assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH)) >= 0);
+ assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH), true) >= 0);
assert_se(access("/", F_OK) < 0);
assert_se(errno == EILSEQ);
unsigned long current;
pid_t pid;
+ log_info("/* %s */", __func__);
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
assert_se(wait_for_terminate_and_check("lockpersonalityseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
-static void test_filter_sets_ordered(void) {
- size_t i;
-
- /* Ensure "@default" always remains at the beginning of the list */
- assert_se(SYSCALL_FILTER_SET_DEFAULT == 0);
- assert_se(streq(syscall_filter_sets[0].name, "@default"));
-
- for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
- const char *k, *p = NULL;
-
- /* Make sure each group has a description */
- assert_se(!isempty(syscall_filter_sets[0].help));
-
- /* Make sure the groups are ordered alphabetically, except for the first entry */
- assert_se(i < 2 || strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0);
-
- NULSTR_FOREACH(k, syscall_filter_sets[i].value) {
-
- /* Ensure each syscall list is in itself ordered, but groups before names */
- assert_se(!p ||
- (*p == '@' && *k != '@') ||
- (((*p == '@' && *k == '@') ||
- (*p != '@' && *k != '@')) &&
- strcmp(p, k) < 0));
-
- p = k;
- }
- }
-}
-
int main(int argc, char *argv[]) {
-
test_setup_logging(LOG_DEBUG);
test_seccomp_arch_to_string();
test_architecture_table();
test_syscall_filter_set_find();
test_filter_sets();
+ test_filter_sets_ordered();
test_restrict_namespace();
test_protect_sysctl();
test_restrict_address_families();
test_restrict_archs();
test_load_syscall_filter_set_raw();
test_lock_personality();
- test_filter_sets_ordered();
return 0;
}
#include "macro.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
#include "utf8.h"
static void test_string_erase(void) {
assert_se(x[9] == '\0');
}
+static void test_free_and_strndup_one(char **t, const char *src, size_t l, const char *expected, bool change) {
+ int r;
+
+ log_debug("%s: \"%s\", \"%s\", %zd (expect \"%s\", %s)",
+ __func__, strnull(*t), strnull(src), l, strnull(expected), yes_no(change));
+
+ r = free_and_strndup(t, src, l);
+ assert_se(streq_ptr(*t, expected));
+ assert_se(r == change); /* check that change occurs only when necessary */
+}
+
+static void test_free_and_strndup(void) {
+ static const struct test_case {
+ const char *src;
+ size_t len;
+ const char *expected;
+ } cases[] = {
+ {"abc", 0, ""},
+ {"abc", 0, ""},
+ {"abc", 1, "a"},
+ {"abc", 2, "ab"},
+ {"abc", 3, "abc"},
+ {"abc", 4, "abc"},
+ {"abc", 5, "abc"},
+ {"abc", 5, "abc"},
+ {"abc", 4, "abc"},
+ {"abc", 3, "abc"},
+ {"abc", 2, "ab"},
+ {"abc", 1, "a"},
+ {"abc", 0, ""},
+
+ {"", 0, ""},
+ {"", 1, ""},
+ {"", 2, ""},
+ {"", 0, ""},
+ {"", 1, ""},
+ {"", 2, ""},
+ {"", 2, ""},
+ {"", 1, ""},
+ {"", 0, ""},
+
+ {NULL, 0, NULL},
+
+ {"foo", 3, "foo"},
+ {"foobar", 6, "foobar"},
+ };
+
+ _cleanup_free_ char *t = NULL;
+ const char *prev_expected = t;
+
+ for (unsigned i = 0; i < ELEMENTSOF(cases); i++) {
+ test_free_and_strndup_one(&t,
+ cases[i].src, cases[i].len, cases[i].expected,
+ !streq_ptr(cases[i].expected, prev_expected));
+ prev_expected = t;
+ }
+}
+
static void test_ascii_strcasecmp_n(void) {
assert_se(ascii_strcasecmp_n("", "", 0) == 0);
}
int main(int argc, char *argv[]) {
+ test_setup_logging(LOG_DEBUG);
+
test_string_erase();
+ test_free_and_strndup();
test_ascii_strcasecmp_n();
test_ascii_strcasecmp_nn();
test_cellescape();
NULL,
};
+static const char* const input_table_quoted[] = {
+ "one",
+ " two\t three ",
+ " four five",
+ NULL,
+};
+
static const char* const input_table_one[] = {
"one",
NULL,
}
static void test_strv_split(void) {
- char **s;
- unsigned i = 0;
_cleanup_strv_free_ char **l = NULL;
const char str[] = "one,two,three";
l = strv_split(str, ",");
assert_se(l);
- STRV_FOREACH(s, l)
- assert_se(streq(*s, input_table_multiple[i++]));
+ assert_se(strv_equal(l, (char**) input_table_multiple));
- i = 0;
strv_free(l);
l = strv_split(" one two\t three", WHITESPACE);
assert_se(l);
- STRV_FOREACH(s, l)
- assert_se(streq(*s, input_table_multiple[i++]));
+ assert_se(strv_equal(l, (char**) input_table_multiple));
+
+ strv_free(l);
+
+ /* Setting NULL for separator is equivalent to WHITESPACE */
+ l = strv_split(" one two\t three", NULL);
+ assert_se(l);
+ assert_se(strv_equal(l, (char**) input_table_multiple));
+
+ strv_free(l);
+
+ l = strv_split_full(" one two\t three", NULL, 0);
+ assert_se(l);
+ assert_se(strv_equal(l, (char**) input_table_multiple));
+
+ strv_free(l);
+
+ l = strv_split_full(" 'one' \" two\t three \" ' four five'", NULL, SPLIT_QUOTES);
+ assert_se(l);
+ assert_se(strv_equal(l, (char**) input_table_quoted));
+
+ strv_free(l);
+
+ /* missing last quote ignores the last element. */
+ l = strv_split_full(" 'one' \" two\t three \" ' four five' ' ignored element ", NULL, SPLIT_QUOTES);
+ assert_se(l);
+ assert_se(strv_equal(l, (char**) input_table_quoted));
+
+ strv_free(l);
+
+ /* missing last quote, but the last element is _not_ ignored with SPLIT_RELAX. */
+ l = strv_split_full(" 'one' \" two\t three \" ' four five", NULL, SPLIT_QUOTES | SPLIT_RELAX);
+ assert_se(l);
+ assert_se(strv_equal(l, (char**) input_table_quoted));
+
+ strv_free(l);
+
+ /* missing separator between */
+ l = strv_split_full(" 'one' \" two\t three \"' four five'", NULL, SPLIT_QUOTES | SPLIT_RELAX);
+ assert_se(l);
+ assert_se(strv_equal(l, (char**) input_table_quoted));
+
+ strv_free(l);
+
+ l = strv_split_full(" 'one' \" two\t three \"' four five", NULL, SPLIT_QUOTES | SPLIT_RELAX);
+ assert_se(l);
+ assert_se(strv_equal(l, (char**) input_table_quoted));
}
static void test_strv_split_empty(void) {
assert_se(l);
assert_se(strv_isempty(l));
+ strv_free(l);
+ l = strv_split("", NULL);
+ assert_se(l);
+ assert_se(strv_isempty(l));
+
+ strv_free(l);
+ l = strv_split_full("", NULL, 0);
+ assert_se(l);
+ assert_se(strv_isempty(l));
+
+ strv_free(l);
+ l = strv_split_full("", NULL, SPLIT_QUOTES);
+ assert_se(l);
+ assert_se(strv_isempty(l));
+
+ strv_free(l);
+ l = strv_split_full("", WHITESPACE, SPLIT_QUOTES);
+ assert_se(l);
+ assert_se(strv_isempty(l));
+
+ strv_free(l);
+ l = strv_split_full("", WHITESPACE, SPLIT_QUOTES | SPLIT_RELAX);
+ assert_se(l);
+ assert_se(strv_isempty(l));
+
strv_free(l);
l = strv_split(" ", WHITESPACE);
assert_se(l);
assert_se(strv_isempty(l));
+ strv_free(l);
+ l = strv_split(" ", NULL);
+ assert_se(l);
+ assert_se(strv_isempty(l));
+
+ strv_free(l);
+ l = strv_split_full(" ", NULL, 0);
+ assert_se(l);
+ assert_se(strv_isempty(l));
+
+ strv_free(l);
+ l = strv_split_full(" ", WHITESPACE, SPLIT_QUOTES);
+ assert_se(l);
+ assert_se(strv_isempty(l));
+
+ strv_free(l);
+ l = strv_split_full(" ", NULL, SPLIT_QUOTES);
+ assert_se(l);
+ assert_se(strv_isempty(l));
+
+ strv_free(l);
+ l = strv_split_full(" ", NULL, SPLIT_QUOTES | SPLIT_RELAX);
+ assert_se(l);
+ assert_se(strv_isempty(l));
}
static void test_strv_split_extract(void) {
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "tests.h"
+#include "udev.h"
+
+static void test_udev_build_argv_one(const char *c) {
+ _cleanup_strv_free_ char **a = NULL;
+ _cleanup_free_ char *arg = NULL;
+ char *argv[128], **p;
+ int argc;
+ size_t i;
+
+ assert_se(a = strv_split_full(c, NULL, SPLIT_QUOTES | SPLIT_RELAX));
+
+ assert_se(arg = strdup(c));
+ assert_se(udev_build_argv(arg, &argc, argv) >= 0);
+
+ log_info("command: %s", c);
+
+ i = 0;
+ log_info("strv_split:");
+ STRV_FOREACH(p, a)
+ log_info("argv[%zu] = '%s'", i++, *p);
+
+ i = 0;
+ log_info("udev_build_argv:");
+ STRV_FOREACH(p, argv)
+ log_info("argv[%zu] = '%s'", i++, *p);
+
+ assert_se(strv_equal(argv, a));
+ assert_se(argc == (int) strv_length(a));
+
+}
+
+static void test_udev_build_argv(void) {
+ test_udev_build_argv_one("one two three");
+ test_udev_build_argv_one("one 'two three ' \" four five \" 'aaa bbb ");
+ test_udev_build_argv_one("/bin/echo -e \\101");
+ test_udev_build_argv_one("/bin/echo -n special-device");
+ test_udev_build_argv_one("/bin/echo -n special-device");
+ test_udev_build_argv_one("/bin/echo test");
+ test_udev_build_argv_one("/bin/echo -n test-%b");
+ test_udev_build_argv_one("/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9");
+ test_udev_build_argv_one("/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed s/foo9/bar9/'");
+ test_udev_build_argv_one("/bin/echo -n 'foo3 foo4' 'foo5 foo6 foo7 foo8'");
+ test_udev_build_argv_one("/bin/sh -c 'printf %%s \\\"foo1 foo2\\\" | grep \\\"foo1 foo2\\\"'");
+ test_udev_build_argv_one("/bin/sh -c \\\"printf %%s 'foo1 foo2' | grep 'foo1 foo2'\\\"");
+ test_udev_build_argv_one("/bin/sh -c 'printf \\\"%%s %%s\\\" \\\"foo1 foo2\\\" \\\"foo3\\\"| grep \\\"foo1 foo2\\\"'");
+ test_udev_build_argv_one("/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9");
+ test_udev_build_argv_one("/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9");
+ test_udev_build_argv_one("/bin/echo -n foo");
+ test_udev_build_argv_one("/bin/echo -n usb-%b");
+ test_udev_build_argv_one("/bin/echo -n scsi-%b");
+ test_udev_build_argv_one("/bin/echo -n foo-%b");
+ test_udev_build_argv_one("/bin/echo test");
+ test_udev_build_argv_one("/bin/echo symlink test this");
+ test_udev_build_argv_one("/bin/echo symlink test this");
+ test_udev_build_argv_one("/bin/echo link test this");
+ test_udev_build_argv_one("/bin/echo -n node link1 link2");
+ test_udev_build_argv_one("/bin/echo -n node link1 link2 link3 link4");
+ test_udev_build_argv_one("/usr/bin/test -b %N");
+ test_udev_build_argv_one("/bin/echo -e name; (/usr/bin/badprogram)");
+ test_udev_build_argv_one("/bin/echo -e \\xc3\\xbcber");
+ test_udev_build_argv_one("/bin/echo -e \\xef\\xe8garbage");
+ test_udev_build_argv_one("/bin/echo 1 1 0400");
+ test_udev_build_argv_one("/bin/echo 0 0 0400letsdoabuffferoverflow0123456789012345789012345678901234567890");
+}
+
+int main(int argc, char *argv[]) {
+ test_setup_logging(LOG_DEBUG);
+
+ test_udev_build_argv();
+
+ return 0;
+}
#include "selinux-util.h"
#include "signal-util.h"
#include "string-util.h"
+#include "tests.h"
#include "udev.h"
static int fake_filesystems(void) {
const char *error;
bool ignore_mount_error;
} fakefss[] = {
- { "test/tmpfs/sys", "/sys", "failed to mount test /sys", false },
- { "test/tmpfs/dev", "/dev", "failed to mount test /dev", false },
- { "test/run", "/run", "failed to mount test /run", false },
- { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d", true },
- { "test/run", UDEVLIBEXECDIR "/rules.d", "failed to mount empty " UDEVLIBEXECDIR "/rules.d", true },
+ { "test/tmpfs/sys", "/sys", "Failed to mount test /sys", false },
+ { "test/tmpfs/dev", "/dev", "Failed to mount test /dev", false },
+ { "test/run", "/run", "Failed to mount test /run", false },
+ { "test/run", "/etc/udev/rules.d", "Failed to mount empty /etc/udev/rules.d", true },
+ { "test/run", UDEVLIBEXECDIR "/rules.d", "Failed to mount empty " UDEVLIBEXECDIR "/rules.d", true },
};
- unsigned int i;
+ unsigned i;
if (unshare(CLONE_NEWNS) < 0)
- return log_error_errno(errno, "failed to call unshare(): %m");
+ return log_error_errno(errno, "Failed to call unshare(): %m");
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
- return log_error_errno(errno, "failed to mount / as private: %m");
+ return log_error_errno(errno, "Failed to mount / as private: %m");
- for (i = 0; i < ELEMENTSOF(fakefss); i++) {
+ for (i = 0; i < ELEMENTSOF(fakefss); i++)
if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) {
log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error);
if (!fakefss[i].ignore_mount_error)
return -errno;
}
- }
return 0;
}
_cleanup_(udev_event_unrefp) struct udev_event *event = NULL;
_cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
_cleanup_(udev_rules_unrefp) struct udev_rules *rules = NULL;
- char syspath[UTIL_PATH_SIZE];
- const char *devpath;
- const char *action;
- int err;
+ const char *devpath, *action;
+ int r;
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_INFO);
- err = fake_filesystems();
- if (err < 0)
+ r = fake_filesystems();
+ if (r < 0)
return EXIT_FAILURE;
log_debug("version %s", PACKAGE_VERSION);
mac_selinux_init();
action = argv[1];
- if (action == NULL) {
+ if (!action) {
log_error("action missing");
goto out;
}
devpath = argv[2];
- if (devpath == NULL) {
+ if (!devpath) {
log_error("devpath missing");
goto out;
}
rules = udev_rules_new(1);
- strscpyl(syspath, sizeof(syspath), "/sys", devpath, NULL);
+ const char *syspath = strjoina("/sys", devpath);
dev = udev_device_new_from_synthetic_event(NULL, syspath, action);
- if (dev == NULL) {
+ if (!dev) {
log_debug("unknown device '%s'", devpath);
goto out;
}
event = udev_event_new(dev);
+ assert_se(event);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0);
/* do what devtmpfs usually provides us */
- if (udev_device_get_devnode(dev) != NULL) {
+ if (udev_device_get_devnode(dev)) {
mode_t mode = 0600;
if (streq(udev_device_get_subsystem(dev), "block"))
out:
mac_selinux_finish();
- return err ? EXIT_FAILURE : EXIT_SUCCESS;
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
#include "alloc-util.h"
#include "string-util.h"
+#include "strv.h"
#include "utf8.h"
#include "util.h"
}
static void test_utf16_to_utf8(void) {
- char *a = NULL;
- const uint16_t utf16[] = { htole16('a'), htole16(0xd800), htole16('b'), htole16(0xdc00), htole16('c'), htole16(0xd801), htole16(0xdc37) };
- const char utf8[] = { 'a', 'b', 'c', 0xf0, 0x90, 0x90, 0xb7, 0 };
+ const char16_t utf16[] = { htole16('a'), htole16(0xd800), htole16('b'), htole16(0xdc00), htole16('c'), htole16(0xd801), htole16(0xdc37) };
+ static const char utf8[] = { 'a', 'b', 'c', 0xf0, 0x90, 0x90, 0xb7 };
+ _cleanup_free_ char16_t *b = NULL;
+ _cleanup_free_ char *a = NULL;
- a = utf16_to_utf8(utf16, 14);
+ /* Convert UTF-16 to UTF-8, filtering embedded bad chars */
+ a = utf16_to_utf8(utf16, sizeof(utf16));
assert_se(a);
- assert_se(streq(a, utf8));
+ assert_se(memcmp(a, utf8, sizeof(utf8)) == 0);
+
+ /* Convert UTF-8 to UTF-16, and back */
+ b = utf8_to_utf16(utf8, sizeof(utf8));
+ assert_se(b);
free(a);
+ a = utf16_to_utf8(b, char16_strlen(b) * 2);
+ assert_se(a);
+ assert_se(strlen(a) == sizeof(utf8));
+ assert_se(memcmp(a, utf8, sizeof(utf8)) == 0);
}
static void test_utf8_n_codepoints(void) {
assert_se(utf8_console_width("\xF1") == (size_t) -1);
}
+static void test_utf8_to_utf16(void) {
+ const char *p;
+
+ FOREACH_STRING(p,
+ "abc",
+ "zażółcić gęślą jaźń",
+ "串",
+ "",
+ "…👊🔪💐…") {
+
+ _cleanup_free_ char16_t *a = NULL;
+ _cleanup_free_ char *b = NULL;
+
+ a = utf8_to_utf16(p, strlen(p));
+ assert_se(a);
+
+ b = utf16_to_utf8(a, char16_strlen(a) * 2);
+ assert_se(b);
+ assert_se(streq(p, b));
+ }
+}
+
int main(int argc, char *argv[]) {
test_utf8_is_valid();
test_utf8_is_printable();
test_utf16_to_utf8();
test_utf8_n_codepoints();
test_utf8_console_width();
+ test_utf8_to_utf16();
return 0;
}
if (r < 0)
return log_error_errno(r, "Failed to add manager object vtable: %m");
- r = bus_request_name_async_may_reload_dbus(m->bus, NULL, "org.freedesktop.timesync1", 0, NULL);
+ r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.timesync1", 0, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to request name: %m");
bool force:1;
+ bool allow_failure:1;
+
bool done:1;
} Item;
r = arg_create ? create_item(i) : 0;
q = arg_remove ? remove_item(i) : 0;
p = arg_clean ? clean_item(i) : 0;
+ /* Failure can only be tolerated for create */
+ if (i->allow_failure)
+ r = 0;
return t < 0 ? t :
r < 0 ? r :
ItemArray *existing;
OrderedHashmap *h;
int r, pos;
- bool force = false, boot = false;
+ bool force = false, boot = false, allow_failure = false;
assert(fname);
assert(line >= 1);
boot = true;
else if (action[pos] == '+' && !force)
force = true;
+ else if (action[pos] == '-' && !allow_failure)
+ allow_failure = true;
else {
*invalid_config = true;
log_error("[%s:%u] Unknown modifiers in command '%s'",
i.type = action[0];
i.force = force;
+ i.allow_failure = allow_failure;
r = specifier_printf(path, specifier_table, NULL, &i.path);
if (r == -ENXIO)
[NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation",
};
+static const char* const advertise_table[_NET_DEV_ADVERTISE_MAX] = {
+ [NET_DEV_ADVERTISE_10BASET_HALF] = "10baset-half",
+ [NET_DEV_ADVERTISE_10BASET_FULL] = "10baset-full",
+ [NET_DEV_ADVERTISE_100BASET_HALF] = "100baset-half",
+ [NET_DEV_ADVERTISE_100BASET_FULL] = "100baset-full",
+ [NET_DEV_ADVERTISE_1000BASET_HALF] = "1000baset-half",
+ [NET_DEV_ADVERTISE_1000BASET_FULL] = "1000baset-full",
+ [NET_DEV_ADVERTISE_10000BASET_FULL] = "10000baset-full",
+ [NET_DEV_ADVERTISE_2500BASEX_FULL] = "2500basex-full",
+ [NET_DEV_ADVERTISE_1000BASEKX_FULL] = "1000basekx-full",
+ [NET_DEV_ADVERTISE_10000BASEKX4_FULL] = "10000basekx4-full",
+ [NET_DEV_ADVERTISE_10000BASEKR_FULL] = "10000basekr-full",
+ [NET_DEV_ADVERTISE_10000BASER_FEC] = "10000baser-fec",
+ [NET_DEV_ADVERTISE_20000BASEMLD2_Full] = "20000basemld2-full",
+ [NET_DEV_ADVERTISE_20000BASEKR2_Full] = "20000basekr2-full",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(advertise, NetDevAdvertise);
+
int ethtool_connect(int *ret) {
int fd;
ecmd.phy_address = u->base.phy_address;
ecmd.autoneg = u->base.autoneg;
ecmd.mdio_support = u->base.mdio_support;
+ ecmd.eth_tp_mdix = u->base.eth_tp_mdix;
+ ecmd.eth_tp_mdix_ctrl = u->base.eth_tp_mdix_ctrl;
ifr->ifr_data = (void *) &ecmd;
* link mode; if the link is down, the speed is 0, %SPEED_UNKNOWN or the highest
* enabled speed and @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
*/
-
int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *link) {
_cleanup_free_ struct ethtool_link_usettings *u = NULL;
struct ifreq ifr = {};
u->base.autoneg = link->autonegotiation;
+ if (link->advertise) {
+ uint32_t advertise[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32] = {};
+
+ advertise[0] = link->advertise;
+ memcpy(&u->link_modes.advertising, advertise, ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES);
+ }
+
if (u->base.cmd == ETHTOOL_GLINKSETTINGS)
r = set_slinksettings(*fd, &ifr, u);
else
return 0;
}
+
+int config_parse_advertise(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ link_config *config = data;
+ NetDevAdvertise mode, a = 0;
+ const char *p;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ /* Empty string resets the value. */
+ config->advertise = 0;
+ return 0;
+ }
+
+ for (p = rvalue;;) {
+ _cleanup_free_ char *w = NULL;
+
+ r = extract_first_word(&p, &w, NULL, 0);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split advertise modes '%s', ignoring: %m", rvalue);
+ break;
+ }
+ if (r == 0)
+ break;
+
+ mode = advertise_from_string(w);
+ if (mode == _NET_DEV_ADVERTISE_INVALID) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse advertise mode, ignoring: %s", w);
+ continue;
+ }
+ a |= mode;
+ }
+
+ config->advertise |= a;
+
+ return 0;
+}
_NET_DEV_PORT_INVALID = -1
} NetDevPort;
+typedef enum NetDevAdvertise {
+ NET_DEV_ADVERTISE_10BASET_HALF = 1 << ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+ NET_DEV_ADVERTISE_10BASET_FULL = 1 << ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+ NET_DEV_ADVERTISE_100BASET_HALF = 1 << ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+ NET_DEV_ADVERTISE_100BASET_FULL = 1 << ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+ NET_DEV_ADVERTISE_1000BASET_HALF = 1 << ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+ NET_DEV_ADVERTISE_1000BASET_FULL = 1 << ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ NET_DEV_ADVERTISE_10000BASET_FULL = 1 << ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+ NET_DEV_ADVERTISE_2500BASEX_FULL = 1 << ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+ NET_DEV_ADVERTISE_1000BASEKX_FULL = 1 << ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+ NET_DEV_ADVERTISE_10000BASEKX4_FULL = 1 << ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+ NET_DEV_ADVERTISE_10000BASEKR_FULL = 1 << ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+ NET_DEV_ADVERTISE_10000BASER_FEC = 1 << ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
+ NET_DEV_ADVERTISE_20000BASEMLD2_Full = 1 << ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
+ NET_DEV_ADVERTISE_20000BASEKR2_Full = 1 << ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
+ _NET_DEV_ADVERTISE_MAX,
+ _NET_DEV_ADVERTISE_INVALID = -1,
+} NetDevAdvertise;
+
#define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32 (SCHAR_MAX)
+#define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES (4 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32)
/* layout of the struct passed from/to userland */
struct ethtool_link_usettings {
const char *port_to_string(NetDevPort port) _const_;
NetDevPort port_from_string(const char *port) _pure_;
+const char *advertise_to_string(NetDevAdvertise advertise) _const_;
+NetDevAdvertise advertise_from_string(const char *advertise) _pure_;
+
int config_parse_duplex(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_wol(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_port(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_channel(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_advertise(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
Link.TxChannels, config_parse_channel, 0, 0
Link.OtherChannels, config_parse_channel, 0, 0
Link.CombinedChannels, config_parse_channel, 0, 0
+Link.Advertise, config_parse_advertise, 0, 0
if (config->port != _NET_DEV_PORT_INVALID)
log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
- speed = DIV_ROUND_UP(config->speed, 1000000);
- if (r == -EOPNOTSUPP)
- r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
+ if (config->advertise)
+ log_warning_errno(r, "Could not set advertise mode to 0x%X: %m", config->advertise);
- if (r < 0)
- log_warning_errno(r, "Could not set speed or duplex of %s to %u Mbps (%s): %m",
- old_name, speed, duplex_to_string(config->duplex));
+ if (config->speed) {
+
+ speed = DIV_ROUND_UP(config->speed, 1000000);
+ if (r == -EOPNOTSUPP) {
+ r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
+ if (r < 0)
+ log_warning_errno(r, "Could not set speed of %s to %u Mbps: %m", old_name, speed);
+ }
+ }
+
+ if (config->duplex !=_DUP_INVALID)
+ log_warning_errno(r, "Could not set duplex of %s to (%s): %m", old_name, duplex_to_string(config->duplex));
}
r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
size_t speed;
Duplex duplex;
int autonegotiation;
+ uint32_t advertise;
WakeOnLan wol;
NetDevPort port;
int features[_NET_DEV_FEAT_MAX];
const char *attr, *port_name;
size_t l;
char *s;
+ int r;
/* ACPI _DSM — device specific method for naming a PCI or PCI Express device */
attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
if (!attr)
return -ENOENT;
- idx = strtoul(attr, NULL, 0);
- if (idx <= 0)
- return -EINVAL;
+ r = safe_atolu(attr, &idx);
+ if (r < 0)
+ return r;
/* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for
* example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary
* provide the port number in the 'dev_id' sysfs attribute instead of 'dev_port',
* which thus stays initialized as 0. */
if (dev_port == 0) {
- unsigned long type;
-
attr = udev_device_get_sysattr_value(dev, "type");
- /* The 'type' attribute always exists. */
- type = strtoul(attr, NULL, 10);
- if (type == ARPHRD_INFINIBAND) {
- attr = udev_device_get_sysattr_value(dev, "dev_id");
- if (attr)
- dev_port = strtoul(attr, NULL, 16);
+ if (attr) {
+ unsigned long type = strtoul(attr, NULL, 10);
+ if (type == ARPHRD_INFINIBAND) {
+ attr = udev_device_get_sysattr_value(dev, "dev_id");
+ if (attr)
+ dev_port = strtoul(attr, NULL, 16);
+ }
}
}
}
}
int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test) {
- char arg[UTIL_PATH_SIZE];
- int argc;
- char *argv[128];
+ _cleanup_strv_free_ char **argv = NULL;
if (!builtins[cmd])
return -EOPNOTSUPP;
+ argv = strv_split_full(command, NULL, SPLIT_QUOTES | SPLIT_RELAX);
+ if (!argv)
+ return -ENOMEM;
+
/* we need '0' here to reset the internal state */
optind = 0;
- strscpy(arg, sizeof(arg), command);
- udev_build_argv(arg, &argc, argv);
- return builtins[cmd]->cmd(dev, argc, argv, test);
+ return builtins[cmd]->cmd(dev, strv_length(argv), argv, test);
}
int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val) {
#include "fd-util.h"
#include "format-util.h"
#include "netlink-util.h"
+#include "path-util.h"
#include "process-util.h"
#include "signal-util.h"
#include "string-util.h"
bool accept_failure,
const char *cmd,
char *result, size_t ressize) {
- int outpipe[2] = {-1, -1};
- int errpipe[2] = {-1, -1};
+ _cleanup_close_pair_ int outpipe[2] = {-1, -1}, errpipe[2] = {-1, -1};
+ _cleanup_strv_free_ char **argv = NULL;
pid_t pid;
- int err = 0;
+ int r;
/* pipes from child to parent */
- if (result != NULL || log_get_max_level() >= LOG_INFO) {
- if (pipe2(outpipe, O_NONBLOCK) != 0) {
- err = log_error_errno(errno, "pipe failed: %m");
- goto out;
- }
- }
- if (log_get_max_level() >= LOG_INFO) {
- if (pipe2(errpipe, O_NONBLOCK) != 0) {
- err = log_error_errno(errno, "pipe failed: %m");
- goto out;
- }
- }
+ if (!result || log_get_max_level() >= LOG_INFO)
+ if (pipe2(outpipe, O_NONBLOCK) != 0)
+ return log_error_errno(errno, "Failed to create pipe for command '%s': %m", cmd);
- err = safe_fork("(spawn)", FORK_RESET_SIGNALS|FORK_LOG, &pid);
- if (err < 0)
- goto out;
- if (err == 0) {
- char arg[UTIL_PATH_SIZE];
- char *argv[128];
- char program[UTIL_PATH_SIZE];
+ if (log_get_max_level() >= LOG_INFO)
+ if (pipe2(errpipe, O_NONBLOCK) != 0)
+ return log_error_errno(errno, "Failed to create pipe for command '%s': %m", cmd);
+
+ argv = strv_split_full(cmd, NULL, SPLIT_QUOTES|SPLIT_RELAX);
+ if (!argv)
+ return log_oom();
+
+ /* allow programs in /usr/lib/udev/ to be called without the path */
+ if (!path_is_absolute(argv[0])) {
+ char *program;
+
+ program = path_join(NULL, UDEVLIBEXECDIR, argv[0]);
+ if (!program)
+ return log_oom();
+ free_and_replace(argv[0], program);
+ }
+
+ r = safe_fork("(spawn)", FORK_RESET_SIGNALS|FORK_LOG, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork() to execute command '%s': %m", cmd);
+ if (r == 0) {
/* child closes parent's ends of pipes */
outpipe[READ_END] = safe_close(outpipe[READ_END]);
errpipe[READ_END] = safe_close(errpipe[READ_END]);
- strscpy(arg, sizeof(arg), cmd);
- udev_build_argv(arg, NULL, argv);
-
- /* allow programs in /usr/lib/udev/ to be called without the path */
- if (argv[0][0] != '/') {
- strscpyl(program, sizeof(program), UDEVLIBEXECDIR "/", argv[0], NULL);
- argv[0] = program;
- }
-
- log_debug("starting '%s'", cmd);
+ log_debug("Starting '%s'", cmd);
spawn_exec(event, cmd, argv, udev_device_get_properties_envp(event->dev),
outpipe[WRITE_END], errpipe[WRITE_END]);
outpipe[READ_END], errpipe[READ_END],
result, ressize);
- err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid, accept_failure);
+ r = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid, accept_failure);
+ if (r < 0)
+ return log_error_errno(r, "Failed to wait spawned command '%s': %m", cmd);
-out:
- if (outpipe[READ_END] >= 0)
- close(outpipe[READ_END]);
- if (outpipe[WRITE_END] >= 0)
- close(outpipe[WRITE_END]);
- if (errpipe[READ_END] >= 0)
- close(errpipe[READ_END]);
- if (errpipe[WRITE_END] >= 0)
- close(errpipe[WRITE_END]);
- return err;
+ return r;
}
static int rename_netif(struct udev_event *event) {
#include "udev.h"
static int node_symlink(struct udev_device *dev, const char *node, const char *slink) {
- struct stat stats;
- char target[UTIL_PATH_SIZE];
- char *s;
- size_t l;
+ _cleanup_free_ char *slink_dirname = NULL, *target = NULL;
char slink_tmp[UTIL_PATH_SIZE + 32];
- int i = 0;
- int tail = 0;
- int err = 0;
+ struct stat stats;
+ int r, err = 0;
+
+ slink_dirname = dirname_malloc(slink);
+ if (!slink_dirname)
+ return log_oom();
/* use relative link */
- target[0] = '\0';
- while (node[i] && (node[i] == slink[i])) {
- if (node[i] == '/')
- tail = i+1;
- i++;
- }
- s = target;
- l = sizeof(target);
- while (slink[i] != '\0') {
- if (slink[i] == '/')
- l = strpcpy(&s, l, "../");
- i++;
- }
- l = strscpy(s, l, &node[tail]);
- if (l == 0) {
- err = -EINVAL;
- goto exit;
- }
+ r = path_make_relative(slink_dirname, node, &target);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get relative path from '%s' to '%s': %m", slink, node);
/* preserve link with correct target, do not replace node of other device */
if (lstat(slink, &stats) == 0) {
+++ /dev/null
-/*/* -whitespace
+++ /dev/null
-# SPDX-License-Identifier: LGPL-2.1+
-
-sanitize_address = custom_target(
- 'sanitize-address-fuzzers',
- output : 'sanitize-address-fuzzers',
- command : [meson_build_sh,
- meson.source_root(),
- '@OUTPUT@',
- 'fuzzers',
- '-Db_lundef=false -Db_sanitize=address'])
-
-sanitizers = [['address', sanitize_address]]
-
-fuzz_regression_tests = '''
- fuzz-dns-packet/issue-7888
- fuzz-dns-packet/oss-fuzz-5465
- fuzz-journal-remote/crash-5a8f03d4c3a46fcded39527084f437e8e4b54b76
- fuzz-journal-remote/crash-96dee870ea66d03e89ac321eee28ea63a9b9aa45
- fuzz-journal-remote/oss-fuzz-8659
- fuzz-journal-remote/oss-fuzz-8686
- fuzz-journald-syslog/github-9795
- fuzz-journald-syslog/github-9820
- fuzz-journald-syslog/github-9827
- fuzz-journald-syslog/github-9829
- fuzz-unit-file/oss-fuzz-6884
- fuzz-unit-file/oss-fuzz-6885
- fuzz-unit-file/oss-fuzz-6886
- fuzz-unit-file/oss-fuzz-6892
- fuzz-unit-file/oss-fuzz-6897
- fuzz-unit-file/oss-fuzz-6897-evverx
- fuzz-unit-file/oss-fuzz-6908
- fuzz-unit-file/oss-fuzz-6917
- fuzz-unit-file/oss-fuzz-6977
- fuzz-unit-file/oss-fuzz-6977-unminimized
- fuzz-unit-file/oss-fuzz-7004
- fuzz-unit-file/oss-fuzz-8064
- fuzz-unit-file/oss-fuzz-8827
- fuzz-unit-file/oss-fuzz-10007
-'''.split()
KillExcludeUsers=
KillOnlyUsers=
KillSignal=
+WatchdogSignal=
KillUserProcesses=
LOCATION=
LidSwitchIgnoreInhibited=
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1+
+
+sanitize_address = custom_target(
+ 'sanitize-address-fuzzers',
+ output : 'sanitize-address-fuzzers',
+ command : [meson_build_sh,
+ meson.source_root(),
+ '@OUTPUT@',
+ 'fuzzers',
+ '-Db_lundef=false -Db_sanitize=address'])
+
+sanitizers = [['address', sanitize_address]]
+
+if git.found()
+ out = run_command(
+ git,
+ '--git-dir=@0@/.git'.format(meson.source_root()),
+ 'ls-files', ':/test/fuzz/*/*')
+else
+ out = run_command(
+ 'sh', '-c', 'ls @0@/*/*'.format(meson.current_source_dir()))
+endif
+
+fuzz_regression_tests = []
+foreach p : out.stdout().split()
+ # Remove the last entry which is ''.
+ #
+ # Also, backslashes get mangled, so skip test. See
+ # https://github.com/mesonbuild/meson/issues/1564.
+ if not p.contains('\\')
+ fuzz_regression_tests += p
+ endif
+endforeach
test-execute/exec-systemcallfilter-system-user-nfsnobody.service
test-execute/exec-systemcallfilter-system-user-nobody.service
test-execute/exec-systemcallfilter-system-user.service
+ test-execute/exec-systemcallfilter-with-errno-multi.service
test-execute/exec-systemcallfilter-with-errno-name.service
test-execute/exec-systemcallfilter-with-errno-number.service
test-execute/exec-temporaryfilesystem-options.service
############################################################
+if install_tests
+ install_data('run-unit-tests.py',
+ install_mode : 'rwxr-xr-x',
+ install_dir : testsdir)
+endif
+
+############################################################
+
# prepare test/sys tree
sys_script_py = find_program('sys-script.py')
custom_target(
endif
endif
-subdir('fuzz-regressions')
+subdir('fuzz')
tmpmounts.append(d)
if os.path.isdir('/run/systemd/resolve'):
os.chmod('/run/systemd/resolve', 0o755)
+ shutil.chown('/run/systemd/resolve', 'systemd-resolve', 'systemd-resolve')
# Avoid "Failed to open /dev/tty" errors in containers.
os.environ['SYSTEMD_LOG_TARGET'] = 'journal'
--- /dev/null
+#!/usr/bin/env python3
+
+import argparse
+import dataclasses
+import glob
+import os
+import subprocess
+import sys
+try:
+ import colorama as c
+ GREEN = c.Fore.GREEN
+ YELLOW = c.Fore.YELLOW
+ RED = c.Fore.RED
+ RESET_ALL = c.Style.RESET_ALL
+ BRIGHT = c.Style.BRIGHT
+except ImportError:
+ GREEN = YELLOW = RED = RESET_ALL = BRIGHT = ''
+
+@dataclasses.dataclass
+class Total:
+ total:int
+ good:int = 0
+ skip:int = 0
+ fail:int = 0
+
+def argument_parser():
+ p = argparse.ArgumentParser()
+ p.add_argument('-u', '--unsafe', action='store_true',
+ help='run "unsafe" tests too')
+ return p
+
+opts = argument_parser().parse_args()
+
+tests = glob.glob('/usr/lib/systemd/tests/test-*')
+if opts.unsafe:
+ tests += glob.glob('/usr/lib/systemd/tests/unsafe/test-*')
+
+total = Total(total=len(tests))
+for test in tests:
+ name = os.path.basename(test)
+
+ ex = subprocess.run(test, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ if ex.returncode == 0:
+ print(f'{GREEN}PASS: {name}{RESET_ALL}')
+ total.good += 1
+ elif ex.returncode == 77:
+ print(f'{YELLOW}SKIP: {name}{RESET_ALL}')
+ total.skip += 1
+ else:
+ print(f'{RED}FAIL: {name}{RESET_ALL}')
+ total.fail += 1
+
+ # stdout/stderr might not be valid unicode, let's just dump it to the terminal.
+ # Also let's reset the style afterwards, in case our output sets something.
+ sys.stdout.buffer.write(ex.stdout)
+ print(f'{RESET_ALL}{BRIGHT}')
+ sys.stdout.buffer.write(ex.stderr)
+ print(f'{RESET_ALL}')
+
+print(f'{BRIGHT}OK: {total.good} SKIP: {total.skip} FAIL: {total.fail}{RESET_ALL}')
+sys.exit(total.fail > 0)
Description=Test DynamicUser with User= and SupplementaryGroups=
[Service]
-ExecStart=/bin/sh -x -c 'test "$$(id -G)" = "1" && test "$$(id -g)" = "1" && test "$$(id -u)" = "1"'
+ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'test "$$(id -g)" = "1" && test "$$(id -u)" = "1"'
Type=oneshot
User=1
DynamicUser=yes
Description=Test DynamicUser with User=
[Service]
-ExecStart=/bin/sh -x -c 'test "$$(id -G)" = "1" && test "$$(id -g)" = "1" && test "$$(id -u)" = "1"'
+ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'test "$$(id -g)" = "1" && test "$$(id -u)" = "1"'
Type=oneshot
User=1
DynamicUser=yes
Description=Test DynamicUser with SupplementaryGroups=
[Service]
-ExecStart=/bin/sh -x -c 'test "$$(id -G | cut -d " " --complement -f 1)" = "1 2 3"'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "2" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "3" && HAVE=1; done; test "$$HAVE" -eq 1'
Type=oneshot
DynamicUser=yes
SupplementaryGroups=1 2 3
Description=Test for Supplementary Group with multiple groups without Group and User
[Service]
-ExecStart=/bin/sh -x -c 'test "$$(id -G)" = "0 1 2 3" && test "$$(id -g)" = "0" && test "$$(id -u)" = "0"'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "0" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "2" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "3" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'test "$$(id -g)" = "0" && test "$$(id -u)" = "0"'
Type=oneshot
SupplementaryGroups=1 2 3
Description=Test for Supplementary Group with multiple groups and Group=1
[Service]
-ExecStart=/bin/sh -x -c 'test "$$(id -G)" = "1 2 3" && test "$$(id -g)" = "1" && test "$$(id -u)" = "0"'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "2" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "3" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'test "$$(id -g)" = "1" && test "$$(id -u)" = "0"'
Type=oneshot
Group=1
SupplementaryGroups=1 2 3
Description=Test for Supplementary Group with multiple groups and Uid=1
[Service]
-ExecStart=/bin/sh -x -c 'test "$$(id -G)" = "1 2 3" && test "$$(id -g)" = "1" && test "$$(id -u)" = "1"'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "2" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "3" && HAVE=1; done; test "$$HAVE" -eq 1'
Type=oneshot
User=1
SupplementaryGroups=1 2 3
Description=Test for Supplementary Group with only one group and uid 1
[Service]
-ExecStart=/bin/sh -x -c 'test "$$(id -G)" = "1" && test "$$(id -g)" = "1" && test "$$(id -u)" = "1"'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'test "$$(id -g)" = "1" && test "$$(id -u)" = "1"'
Type=oneshot
User=1
Group=1
Description=Test for Supplementary Group with only one group
[Service]
-ExecStart=/bin/sh -x -c 'test "$$(id -G)" = "1" && test "$$(id -g)" = "1" && test "$$(id -u)" = "0"'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'test "$$(id -g)" = "1" && test "$$(id -u)" = "0"'
Type=oneshot
Group=1
SupplementaryGroups=1
Description=Test for Supplementary Group
[Service]
-ExecStart=/bin/sh -x -c 'test "$$(id -G)" = "0 1"'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "0" && HAVE=1; done; test "$$HAVE" -eq 1'
+ExecStart=/bin/sh -x -c 'HAVE=; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1'
Type=oneshot
SupplementaryGroups=1
--- /dev/null
+[Unit]
+Description=Test for SystemCallFilter updating errno
+# test for issue #9939 which is fixed by a5404992cc7724ebf7572a0aa89d9fdb26ce0b62 (#9942)
+
+[Service]
+ExecStart=/usr/bin/python3 -c 'import os\ntry: os.uname()\nexcept Exception as e: exit(e.errno)'
+Type=oneshot
+SystemCallFilter=~uname:ENOENT uname:EILSEQ
+SystemCallErrorNumber=EACCES
Description=Test for UMask
[Service]
-ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "600"'
+ExecStart=/bin/sh -x -c 'rm /tmp/test-exec-umask; touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "600"'
Type=oneshot
UMask=0177
PrivateTmp=yes
Description=Test for UMask default
[Service]
-ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "644"'
+ExecStart=/bin/sh -x -c 'rm /tmp/test-exec-umask; touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "644"'
Type=oneshot
PrivateTmp=yes
--- /dev/null
+[NetDev]
+Name=test1
+Kind=dummy
--- /dev/null
+[NetDev]
+Name=dummy98
+Kind=dummy
--- /dev/null
+[NetDev]
+Name=macvlan99
+Kind=macvlan
--- /dev/null
+[NetDev]
+Name=macvtap99
+Kind=macvtap
--- /dev/null
+[NetDev]
+Name=vlan99
+Kind=vlan
+
+[VLAN]
+Id=99
+GVRP=true
+MVRP=true
+LooseBinding=true
+ReorderHeader=true
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+VLAN=vlan99
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Bond=bond199
+ActiveSlave=true
--- /dev/null
+[Match]
+Name=bond199
--- /dev/null
+[Match]
+Name=veth-peer
+
+[Network]
+EmitLLDP=yes
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Bond=bond199
+PrimarySlave=true
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+Bond=bond199
+PrimarySlave=true
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+LLDP=yes
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Address=192.168.42.100
+DNS=192.168.42.1
+Domains= one two three four five six seven eight nine ten
--- /dev/null
+[Match]
+Name=dummy98
+
+[Link]
+MACAddress=00:01:02:aa:bb:cc
--- /dev/null
+[Match]
+Name=dummy98
+
+[Address]
+Address=10.2.3.4/16
+PreferredLifetime=0
+Scope=link
+
+[Address]
+Address=2001:0db8:0:f101::1/64
--- /dev/null
+[Match]
+Name=dummy98
+
+[Address]
+Address=10.2.3.4/16
+Peer=10.2.3.5/16
+Label=32
+
+[Address]
+Address=10.6.7.8/16
+Label=33
--- /dev/null
+[NetDev]
+Name=bond199
+Kind=bond
+
+[Bond]
+Mode=active-backup
--- /dev/null
+[NetDev]
+Name=bond99
+Kind=bond
+
+[Bond]
+Mode=802.3ad
+TransmitHashPolicy=layer3+4
+MIIMonitorSec=1s
+LACPTransmitRate=fast
+UpDelaySec=2s
+DownDelaySec=2s
+ResendIGMP=4
+MinLinks=1
--- /dev/null
+[NetDev]
+Name=bridge99
+Kind=bridge
+
+[Bridge]
+HelloTimeSec=9
+MaxAgeSec=9
+ForwardDelaySec=9
+AgeingTimeSec=9
+Priority=9
+MulticastQuerier= true
+MulticastSnooping=true
+STP=true
--- /dev/null
+[NetDev]
+Name=geneve99
+Kind=geneve
+
+[GENEVE]
+Id=99
+Remote=192.168.22.1
+TTL=1
+UDPChecksum=true
+UDP6ZeroChecksumTx=true
+UDP6ZeroChecksumRx=true
+DestinationPort=6082
--- /dev/null
+[NetDev]
+Name=gretun99
+Kind=gre
+
+[Tunnel]
+Local=10.65.223.238
+Remote=10.65.223.239
--- /dev/null
+[NetDev]
+Name=gretap99
+Kind=gretap
+
+[Tunnel]
+Local=10.65.223.238
+Remote=10.65.223.239
--- /dev/null
+[NetDev]
+Name=ip6gretap99
+Kind=ip6gretap
+
+[Tunnel]
+Local=2a00:ffde:4567:edde::4987
+Remote=2001:473:fece:cafe::5179
--- /dev/null
+[NetDev]
+Name=ip6tnl99
+Kind=ip6tnl
+
+[Tunnel]
+Mode=ip6ip6
+Local=2a00:ffde:4567:edde::4987
+Remote=2001:473:fece:cafe::5179
--- /dev/null
+[NetDev]
+Name=ipiptun99
+Kind=ipip
+MTUBytes=1480
+
+[Tunnel]
+Local=192.168.223.238
+Remote=192.169.224.239
+Independent=true
--- /dev/null
+[NetDev]
+Name=ipiptun99
+Kind=ipip
+MTUBytes=1480
+
+[Tunnel]
+Local=192.168.223.238
+Remote=192.169.224.239
--- /dev/null
+[Match]
+Name=dummy98
+
+[IPv6AddressLabel]
+Label=4444
+Prefix=2004:da8:1:0::/64
--- /dev/null
+[NetDev]
+Name=ipvlan99
+Kind=ipvlan
+
+[IPVLAN]
+Mode=L2
--- /dev/null
+[Match]
+Name=dummy98
+
+[Link]
+MACAddress=00:01:02:aa:bb:cc
+Unmanaged=true
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Address=192.168.0.15/24
+
+[Route]
+Gateway=192.168.0.1
--- /dev/null
+[Match]
+Name=test1
+
+[Route]
+Destination=192.168.1.1
+InitialCongestionWindow=20
+
+[Route]
+Destination=192.168.1.2
+InitialAdvertisedReceiveWindow=30
--- /dev/null
+[Match]
+Name=dummy98
+
+[Route]
+Type=blackhole
+Destination=202.54.1.2
+
+[Route]
+Type=unreachable
+Destination=202.54.1.3
+
+[Route]
+Type=prohibit
+Destination=202.54.1.4
--- /dev/null
+[NetDev]
+Name=sittun99
+Kind=sit
+
+[Tunnel]
+Local=10.65.223.238
+Remote=10.65.223.239
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+IPForward=true
+IPv6PrivacyExtensions=true
+IPv6DuplicateAddressDetection=3
+IPv6HopLimit=5
+IPv4ProxyARP=true
+IPv6ProxyNDP=true
--- /dev/null
+[NetDev]
+Name=tap99
+Kind=tap
+
+[Tap]
+MultiQueue=true
+PacketInfo=true
--- /dev/null
+[NetDev]
+Name=tun99
+Kind=tun
+
+[Tun]
+MultiQueue=true
+PacketInfo=true
--- /dev/null
+[NetDev]
+Name=vcan99
+Kind=vcan
--- /dev/null
+[NetDev]
+Name=veth99
+Kind=veth
+MACAddress=12:34:56:78:9a:bc
+
+[Peer]
+Name=veth-peer
+MACAddress=12:34:56:78:9a:bd
--- /dev/null
+[NetDev]
+Name=vrf99
+Kind=vrf
+
+[VRF]
+TableId=42
--- /dev/null
+[NetDev]
+Name=vtitun99
+Kind=vti
+
+[Tunnel]
+Local=10.65.223.238
+Remote=10.65.223.239
--- /dev/null
+[NetDev]
+Name=vti6tun99
+Kind=vti6
+
+[Tunnel]
+Local=2a00:ffde:4567:edde::4987
+Remote=2001:473:fece:cafe::5179
--- /dev/null
+[NetDev]
+Name=vxlan99
+Kind=vxlan
+
+[VXLAN]
+Id=999
+L2MissNotification=true
+L3MissNotification=true
+RouteShortCircuit=true
+UDPChecksum=true
+UDP6ZeroChecksumTx=true
+UDP6ZeroChecksumRx=true
+RemoteChecksumTx=true
+RemoteChecksumRx=true
+GroupPolicyExtension=true
+DestinationPort=5555
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Bridge=bridge99
+
+[Bridge]
+Cost=400
+HairPin = true
+FastLeave = true
+UnicastFlood = true
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+Bridge=bridge99
--- /dev/null
+[NetDev]
+Name=bridge99
+Kind=bridge
--- /dev/null
+[Match]
+Name=bridge99
+
+[Network]
+Address=192.168.0.15/24
+Gateway=192.168.0.1
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+Address=192.168.0.15/24
+Gateway=192.168.0.1
+ConfigureWithoutCarrier=true
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv4
+IPv6AcceptRA=false
+
+[DHCP]
+Anonymize=true
+UseMTU=true
+UseRoutes=true
+SendHostname=true
+UseHostname=true
+Hostname=test-hostname
+ClientIdentifier=mac
+VendorClassIdentifier=SusantVendorTest
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv4
+IPv6AcceptRA=false
+
+[DHCP]
+CriticalConnection=true
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv4
+IPv6AcceptRA=false
+
+[DHCP]
+UseMTU=true
+UseRoutes=true
+SendHostname=true
+UseHostname=true
+Hostname=test-hostname
+ClientIdentifier=mac
+VendorClassIdentifier=SusantVendorTest
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv4
+IPv6AcceptRA=false
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv4
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv6
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv6
+
+[DHCP]
+RapidCommit=false
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=yes
+
+[DHCP]
+ListenPort=5555
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv4
+IPv6AcceptRA=false
+
+[DHCP]
+UseRoutes=true
+RouteMetric=24
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv4
+IPv6AcceptRA=false
+
+[DHCP]
+UseRoutes=true
+RouteTable=12
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+IPv6AcceptRA=false
+DHCP=ipv4
+UseRoutes=true
+UseTimezone=true
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=yes
--- /dev/null
+[Match]
+Name=veth-peer
+
+[Network]
+IPv6AcceptRA=false
+Address=192.168.5.1/24
+DHCPServer=yes
+
+[DHCPServer]
+PoolOffset=10
+PoolSize=50
+EmitRouter=yes
+Timezone=Europe/Berlin
--- /dev/null
+[Match]
+Name=veth-peer
+
+[Network]
+Address=2600::1
+Address=192.168.5.1/24
--- /dev/null
+[Match]
+Name=veth-peer
+
+[Network]
+Address=192.168.5.1/24
+DHCPServer=yes
+
+[DHCPServer]
+PoolOffset=10
+PoolSize=50
+DNS=192.168.5.1
+NTP=192.168.5.1
--- /dev/null
+[Match]
+Name=veth-peer
+
+[Network]
+Address=192.168.0.1
+Address=192.168.5.1
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=gretap99
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=gretun99
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=ip6gretap99
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=ip6tnl99
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=ipiptun99
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+IPv6AcceptRA=true
--- /dev/null
+[Match]
+Name=veth-peer
+
+[Network]
+IPv6PrefixDelegation=yes
+
+[IPv6Prefix]
+Prefix=2002:da8:1:0::/64
+PreferredLifetimeSec=1000s
+ValidLifetimeSec=2100s
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+IPVLAN=ipvlan99
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+MACVLAN=macvlan99
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+MACVTAP=macvtap99
--- /dev/null
+[Match]
+Name=test1
+
+[RoutingPolicyRule]
+TypeOfService=0x08
+Table=7
+From= 192.168.100.18
+Priority=111
+IncomingInterface=test1
+OutgoingInterface=test1
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=sittun99
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Address=192.168.0.15/24
+Gateway=192.168.0.1
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=vtitun99
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=vti6tun99
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+VXLAN=vxlan99
--- /dev/null
+#!/usr/bin/env python3
+# SPDX-License-Identifier: LGPL-2.1+
+# systemd-networkd tests
+
+import os
+import sys
+import unittest
+import subprocess
+import time
+import shutil
+import signal
+import socket
+import threading
+from shutil import copytree
+
+network_unit_file_path='/var/run/systemd/network'
+networkd_ci_path='/var/run/networkd-ci'
+network_sysctl_ipv6_path='/proc/sys/net/ipv6/conf'
+network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf'
+
+dnsmasq_config_file='/var/run/networkd-ci/test-dnsmasq.conf'
+dnsmasq_pid_file='/var/run/networkd-ci/test-test-dnsmasq.pid'
+dnsmasq_log_file='/var/run/networkd-ci/test-dnsmasq-log-file'
+
+def setUpModule():
+
+ os.makedirs(network_unit_file_path, exist_ok=True)
+ os.makedirs(networkd_ci_path, exist_ok=True)
+
+ shutil.rmtree(networkd_ci_path)
+ copytree(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'), networkd_ci_path)
+
+def tearDownModule():
+ shutil.rmtree(networkd_ci_path)
+
+class Utilities():
+ dhcp_server_data = []
+
+ def read_link_attr(self, link, dev, attribute):
+ with open(os.path.join(os.path.join(os.path.join('/sys/class/net/', link), dev), attribute)) as f:
+ return f.readline().strip()
+
+ def link_exits(self, link):
+ return os.path.exists(os.path.join('/sys/class/net', link))
+
+ def link_remove(self, links):
+ for link in links:
+ if os.path.exists(os.path.join('/sys/class/net', link)):
+ subprocess.call(['ip', 'link', 'del', 'dev', link])
+
+ def read_ipv6_sysctl_attr(self, link, attribute):
+ with open(os.path.join(os.path.join(network_sysctl_ipv6_path, link), attribute)) as f:
+ return f.readline().strip()
+
+ def read_ipv4_sysctl_attr(self, link, attribute):
+ with open(os.path.join(os.path.join(network_sysctl_ipv4_path, link), attribute)) as f:
+ return f.readline().strip()
+
+ def copy_unit_to_networkd_unit_path(self, *units):
+ for unit in units:
+ shutil.copy(os.path.join(networkd_ci_path, unit), network_unit_file_path)
+
+ def remove_unit_from_networkd_path(self, units):
+ for unit in units:
+ if (os.path.exists(os.path.join(network_unit_file_path, unit))):
+ os.remove(os.path.join(network_unit_file_path, unit))
+
+ def start_dnsmasq(self):
+ subprocess.check_call('dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range=2600::10,2600::20 --dhcp-range=192.168.5.10,192.168.5.200 -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --dhcp-option=33,192.168.5.4,192.168.5.5', shell=True)
+
+ time.sleep(10)
+
+ def stop_dnsmasq(self, pid_file):
+ if os.path.exists(pid_file):
+ with open(pid_file, 'r') as f:
+ pid = f.read().rstrip(' \t\r\n\0')
+ os.kill(int(pid), signal.SIGTERM)
+
+ os.remove(pid_file)
+
+ def search_words_in_file(self, word):
+ if os.path.exists(dnsmasq_log_file):
+ with open (dnsmasq_log_file) as in_file:
+ contents = in_file.read()
+ print(contents)
+ for part in contents.split():
+ if word in part:
+ in_file.close()
+ print("%s, %s" % (word, part))
+ return True
+ return False
+
+ def remove_lease_file(self):
+ if os.path.exists(os.path.join(networkd_ci_path, 'lease')):
+ os.remove(os.path.join(networkd_ci_path, 'lease'))
+
+ def remove_log_file(self):
+ if os.path.exists(dnsmasq_log_file):
+ os.remove(dnsmasq_log_file)
+
+ def start_networkd(self):
+ subprocess.check_call('systemctl restart systemd-networkd', shell=True)
+ time.sleep(5)
+
+global ip
+global port
+
+class DHCPServer(threading.Thread):
+ def __init__(self, name):
+ threading.Thread.__init__(self)
+ self.name = name
+
+ def run(self):
+ self.start_dhcp_server()
+
+ def start_dhcp_server(self):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+ server_address = ('0.0.0.0', 67)
+ sock.bind(server_address)
+
+ print('Starting DHCP Server ...\n')
+ data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
+
+ global ip
+ ip = addr[0]
+
+ global port
+ port = addr[1]
+ sock.close()
+
+class NetworkdNetDevTests(unittest.TestCase, Utilities):
+
+ links =['bridge99', 'bond99', 'bond99', 'vlan99', 'test1', 'macvtap99',
+ 'macvlan99', 'ipvlan99', 'vxlan99', 'veth99', 'vrf99', 'tun99',
+ 'tap99', 'vcan99', 'geneve99', 'dummy98', 'ipiptun99', 'sittun99',
+ 'gretap99', 'vtitun99', 'vti6tun99','ip6tnl99', 'gretun99', 'ip6gretap99']
+
+ units = ['25-bridge.netdev', '25-bond.netdev', '21-vlan.netdev', '11-dummy.netdev', '21-vlan.network',
+ '21-macvtap.netdev', 'macvtap.network', '21-macvlan.netdev', 'macvlan.network', 'vxlan.network',
+ '25-vxlan.netdev', '25-ipvlan.netdev', 'ipvlan.network', '25-veth.netdev', '25-vrf.netdev',
+ '25-tun.netdev', '25-tun.netdev', '25-vcan.netdev', '25-geneve.netdev', '25-ipip-tunnel.netdev',
+ '25-ip6tnl-tunnel.netdev', '25-ip6gre-tunnel.netdev','25-sit-tunnel.netdev', '25-gre-tunnel.netdev',
+ '25-gretap-tunnel.netdev', '25-vti-tunnel.netdev', '25-vti6-tunnel.netdev', '12-dummy.netdev',
+ 'gre.network', 'ipip.network', 'ip6gretap.network', 'gretun.network', 'ip6tnl.network', '25-tap.netdev',
+ 'vti6.network', 'vti.network', 'gretap.network', 'sit.network', '25-ipip-tunnel-independent.netdev']
+
+ def setUp(self):
+ self.link_remove(self.links)
+
+ def tearDown(self):
+ self.link_remove(self.links)
+ self.remove_unit_from_networkd_path(self.units)
+
+ def test_bridge(self):
+ self.copy_unit_to_networkd_unit_path('25-bridge.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('bridge99'))
+
+ self.assertEqual('900', self.read_link_attr('bridge99', 'bridge', 'hello_time'))
+ self.assertEqual('900', self.read_link_attr('bridge99', 'bridge', 'max_age'))
+ self.assertEqual('900', self.read_link_attr('bridge99', 'bridge','forward_delay'))
+ self.assertEqual('900', self.read_link_attr('bridge99', 'bridge','ageing_time'))
+ self.assertEqual('9', self.read_link_attr('bridge99', 'bridge','priority'))
+ self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','multicast_querier'))
+ self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','multicast_snooping'))
+ self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','stp_state'))
+
+ def test_bond(self):
+ self.copy_unit_to_networkd_unit_path('25-bond.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('bond99'))
+
+ self.assertEqual('802.3ad 4', self.read_link_attr('bond99', 'bonding', 'mode'))
+ self.assertEqual('layer3+4 1', self.read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
+ self.assertEqual('1000', self.read_link_attr('bond99', 'bonding', 'miimon'))
+ self.assertEqual('fast 1', self.read_link_attr('bond99', 'bonding', 'lacp_rate'))
+ self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'updelay'))
+ self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'downdelay'))
+ self.assertEqual('4', self.read_link_attr('bond99', 'bonding', 'resend_igmp'))
+ self.assertEqual('1', self.read_link_attr('bond99', 'bonding', 'min_links'))
+
+ def test_vlan(self):
+ self.copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev', '21-vlan.network')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('vlan99'))
+
+ output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vlan99']).rstrip().decode('utf-8')
+ self.assertTrue(output, 'REORDER_HDR')
+ self.assertTrue(output, 'LOOSE_BINDING')
+ self.assertTrue(output, 'GVRP')
+ self.assertTrue(output, 'MVRP')
+ self.assertTrue(output, '99')
+
+ def test_macvtap(self):
+ self.copy_unit_to_networkd_unit_path('21-macvtap.netdev', '11-dummy.netdev', 'macvtap.network')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('macvtap99'))
+
+ def test_macvlan(self):
+ self.copy_unit_to_networkd_unit_path('21-macvlan.netdev', '11-dummy.netdev', 'macvlan.network')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('macvlan99'))
+
+ def test_ipvlan(self):
+ self.copy_unit_to_networkd_unit_path('25-ipvlan.netdev', '11-dummy.netdev', 'ipvlan.network')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('ipvlan99'))
+
+ def test_veth(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ def test_dummy(self):
+ self.copy_unit_to_networkd_unit_path('11-dummy.netdev')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('test1'))
+
+ def test_tun(self):
+ self.copy_unit_to_networkd_unit_path('25-tun.netdev')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('tun99'))
+
+ def test_tap(self):
+ self.copy_unit_to_networkd_unit_path('25-tap.netdev')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('tap99'))
+
+ def test_vrf(self):
+ self.copy_unit_to_networkd_unit_path('25-vrf.netdev')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('vrf99'))
+
+ def test_vcan(self):
+ self.copy_unit_to_networkd_unit_path('25-vcan.netdev')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('vcan99'))
+
+ def test_geneve(self):
+ self.copy_unit_to_networkd_unit_path('25-geneve.netdev')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('geneve99'))
+
+ output = subprocess.check_output(['ip', '-d', 'link', 'show', 'geneve99']).rstrip().decode('utf-8')
+ self.assertTrue(output, '192.168.22.1')
+ self.assertTrue(output, '6082')
+ self.assertTrue(output, 'udpcsum')
+ self.assertTrue(output, 'udp6zerocsumrx')
+
+ def test_ipip_tunnel(self):
+ self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ipip-tunnel.netdev', 'ipip.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ self.assertTrue(self.link_exits('ipiptun99'))
+
+ def test_gre_tunnel(self):
+ self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gre-tunnel.netdev', 'gretun.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ self.assertTrue(self.link_exits('gretun99'))
+
+ def test_gretap_tunnel(self):
+ self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gretap-tunnel.netdev', 'gretap.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ self.assertTrue(self.link_exits('gretap99'))
+
+ def test_ip6gretap_tunnel(self):
+ self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6gre-tunnel.netdev', 'ip6gretap.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ self.assertTrue(self.link_exits('ip6gretap99'))
+
+ def test_vti_tunnel(self):
+ self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti-tunnel.netdev', 'vti.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ self.assertTrue(self.link_exits('vtitun99'))
+
+ def test_vti6_tunnel(self):
+ self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti6-tunnel.netdev', 'vti6.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ self.assertTrue(self.link_exits('vti6tun99'))
+
+ def test_ip6tnl_tunnel(self):
+ self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6tnl-tunnel.netdev', 'ip6tnl.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ self.assertTrue(self.link_exits('ip6tnl99'))
+
+ def test_sit_tunnel(self):
+ self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-sit-tunnel.netdev', 'sit.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ self.assertTrue(self.link_exits('sittun99'))
+
+ def test_tunnel_independent(self):
+ self.copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev')
+
+ self.start_networkd()
+ self.assertTrue(self.link_exits('ipiptun99'))
+
+ def test_vxlan(self):
+ self.copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network','11-dummy.netdev')
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('vxlan99'))
+
+ output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vxlan99']).rstrip().decode('utf-8')
+ self.assertRegex(output, "999")
+ self.assertRegex(output, '5555')
+ self.assertRegex(output, 'l2miss')
+ self.assertRegex(output, 'l3miss')
+ self.assertRegex(output, 'udpcsum')
+ self.assertRegex(output, 'udp6zerocsumtx')
+ self.assertRegex(output, 'udp6zerocsumrx')
+ self.assertRegex(output, 'remcsumtx')
+ self.assertRegex(output, 'remcsumrx')
+ self.assertRegex(output, 'gbp')
+
+class NetworkdNetWorkTests(unittest.TestCase, Utilities):
+ links = ['dummy98', 'test1', 'bond199']
+
+ units = ['12-dummy.netdev', 'test-static.network', 'configure-without-carrier.network', '11-dummy.netdev',
+ '23-primary-slave.network', '23-test1-bond199.network', '11-dummy.netdev', '23-bond199.network',
+ '25-bond-active-backup-slave.netdev', '12-dummy.netdev', '23-active-slave.network',
+ 'routing-policy-rule.network', '25-address-section.network', '25-address-section-miscellaneous.network',
+ '25-route-section.network', '25-route-type.network', '25-route-tcp-window-settings.network',
+ '25-address-link-section.network', '25-ipv6-address-label-section.network', '25-link-section-unmanaged.network',
+ '25-sysctl.network']
+
+ def setUp(self):
+ self.link_remove(self.links)
+
+ def tearDown(self):
+ self.link_remove(self.links)
+ self.remove_unit_from_networkd_path(self.units)
+
+ def test_static_address(self):
+ self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'test-static.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '192.168.0.15')
+ self.assertRegex(output, '192.168.0.1')
+ self.assertRegex(output, 'routable')
+
+ def test_configure_without_carrier(self):
+ self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('test1'))
+ output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '192.168.0.15')
+ self.assertRegex(output, '192.168.0.1')
+ self.assertRegex(output, 'routable')
+
+ def test_bond_active_slave(self):
+ self.copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ self.assertTrue(self.link_exits('bond199'))
+ output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'active_slave dummy98')
+
+ def test_bond_primary_slave(self):
+ self.copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('test1'))
+ self.assertTrue(self.link_exits('bond199'))
+ output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'primary test1')
+
+ def test_routing_policy_rule(self):
+ self.copy_unit_to_networkd_unit_path('routing-policy-rule.network', '11-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('test1'))
+ output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '111')
+ self.assertRegex(output, 'from 192.168.100.18')
+ self.assertRegex(output, 'tos 0x08')
+ self.assertRegex(output, 'iif test1')
+ self.assertRegex(output, 'oif test1')
+ self.assertRegex(output, 'lookup 7')
+
+ def test_address_preferred_lifetime_zero_ipv6(self):
+ self.copy_unit_to_networkd_unit_path('25-address-section-miscellaneous.network', '12-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+
+ output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
+ self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
+
+ def test_ip_route(self):
+ self.copy_unit_to_networkd_unit_path('25-route-section.network', '12-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+
+ output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '192.168.0.1')
+ self.assertRegex(output, 'static')
+ self.assertRegex(output, '192.168.0.0/24')
+
+ def test_ip_route_blackhole_unreachable_prohibit(self):
+ self.copy_unit_to_networkd_unit_path('25-route-type.network', '12-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+
+ output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'blackhole')
+ self.assertRegex(output, 'unreachable')
+ self.assertRegex(output, 'prohibit')
+
+ subprocess.call(['ip', 'route', 'del', 'blackhole', '202.54.1.2'])
+ subprocess.call(['ip', 'route', 'del', 'unreachable', '202.54.1.3'])
+ subprocess.call(['ip', 'route', 'del', 'prohibit', '202.54.1.4'])
+
+ def test_ip_route_tcp_window(self):
+ self.copy_unit_to_networkd_unit_path('25-route-tcp-window-settings.network', '11-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('test1'))
+
+ output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'initcwnd 20')
+ self.assertRegex(output, 'initrwnd 30')
+
+ def test_ip_link_mac_address(self):
+ self.copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+
+ output = subprocess.check_output(['ip', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '00:01:02:aa:bb:cc')
+
+ def test_ip_link_unmanaged(self):
+ self.copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+
+ output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'unmanaged')
+
+ def test_ipv6_address_label(self):
+ self.copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+
+ output = subprocess.check_output(['ip', 'addrlabel', 'list']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '2004:da8:1::/64')
+
+ def test_sysctl(self):
+ self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+
+ self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
+ self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
+ self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
+ self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
+ self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
+ self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
+ self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
+
+class NetworkdNetWorkBrideTests(unittest.TestCase, Utilities):
+ links = ['dummy98', 'test1', 'bridge99']
+
+ units = ['11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev', '26-bridge-slave-interface-1.network',
+ '26-bridge-slave-interface-2.network', 'bridge99.network']
+
+ def setUp(self):
+ self.link_remove(self.links)
+
+ def tearDown(self):
+ self.link_remove(self.links)
+ self.remove_unit_from_networkd_path(self.units)
+
+ def test_bridge_property(self):
+ self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
+ '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
+ 'bridge99.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+ self.assertTrue(self.link_exits('test1'))
+ self.assertTrue(self.link_exits('bridge99'))
+
+ output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'master')
+ self.assertRegex(output, 'bridge')
+
+ output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'master')
+ self.assertRegex(output, 'bridge')
+
+ output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '192.168.0.15')
+ self.assertRegex(output, '192.168.0.1')
+
+ output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'cost 400')
+ self.assertRegex(output, 'hairpin on')
+ self.assertRegex(output, 'flood on')
+ self.assertRegex(output, 'fastleave on')
+
+class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
+ links = ['veth99']
+
+ units = ['23-emit-lldp.network', '24-lldp.network', '25-veth.netdev']
+
+ def setUp(self):
+ self.link_remove(self.links)
+
+ def tearDown(self):
+ self.link_remove(self.links)
+ self.remove_unit_from_networkd_path(self.units)
+
+ def test_lldp(self):
+ self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ output = subprocess.check_output(['networkctl', 'lldp']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'veth-peer')
+ self.assertRegex(output, 'veth99')
+
+class NetworkdNetworkRATests(unittest.TestCase, Utilities):
+ links = ['veth99']
+
+ units = ['25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network']
+
+ def setUp(self):
+ self.link_remove(self.links)
+
+ def tearDown(self):
+ self.link_remove(self.links)
+ self.remove_unit_from_networkd_path(self.units)
+
+ def test_ipv6_prefix_delegation(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '2002:da8:1:0')
+
+class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
+ links = ['veth99', 'dummy98']
+
+ units = ['25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network', '12-dummy.netdev', '24-search-domain.network',
+ 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network']
+
+ def setUp(self):
+ self.link_remove(self.links)
+
+ def tearDown(self):
+ self.link_remove(self.links)
+ self.remove_unit_from_networkd_path(self.units)
+
+ def test_dhcp_server(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ time.sleep(5)
+
+ output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '192.168.5.*')
+ self.assertRegex(output, 'Gateway: 192.168.5.1')
+ self.assertRegex(output, 'DNS: 192.168.5.1')
+ self.assertRegex(output, 'NTP: 192.168.5.1')
+
+ def test_domain(self):
+ self.copy_unit_to_networkd_unit_path( '12-dummy.netdev', '24-search-domain.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('dummy98'))
+
+ output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'Address: 192.168.42.100')
+ self.assertRegex(output, 'DNS: 192.168.42.1')
+ self.assertRegex(output, 'Search Domains: one')
+
+ def test_emit_router_timezone(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'Gateway: 192.168.5.*')
+ self.assertRegex(output, '192.168.5.*')
+ self.assertRegex(output, 'Europe/Berlin')
+
+class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
+ links = ['veth99', 'dummy98']
+
+ units = ['25-veth.netdev', 'dhcp-server-veth-peer.network','dhcp-client-ipv6-only.network',
+ 'dhcp-client-ipv4-only-ipv6-disabled.network', 'dhcp-client-ipv4-only.network',
+ 'dhcp-client-ipv4-dhcp-settings.network', 'dhcp-client-anonymize.network',
+ 'dhcp-client-ipv6-rapid-commit.network', 'dhcp-client-route-table.network',
+ 'dhcp-v4-server-veth-peer.network', 'dhcp-client-listen-port.network',
+ 'dhcp-client-route-metric.network', 'dhcp-client-critical-connection.network']
+
+ def setUp(self):
+ self.link_remove(self.links)
+ self.stop_dnsmasq(dnsmasq_pid_file)
+
+ def tearDown(self):
+ self.link_remove(self.links)
+ self.remove_unit_from_networkd_path(self.units)
+ self.stop_dnsmasq(dnsmasq_pid_file)
+ self.remove_lease_file()
+ self.remove_log_file()
+
+ def test_dhcp_client_ipv6_only(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network','dhcp-client-ipv6-only.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ self.start_dnsmasq()
+
+ output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '2600::')
+ self.assertNotRegex(output, '192.168.5')
+
+ def test_dhcp_client_ipv4_only(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network','dhcp-client-ipv4-only-ipv6-disabled.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ self.start_dnsmasq()
+
+ output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertNotRegex(output, '2600::')
+ self.assertRegex(output, '192.168.5')
+
+ def test_dhcp_client_ipv4_ipv6(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
+ 'dhcp-client-ipv4-only.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ self.start_dnsmasq()
+
+ output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '2600::')
+ self.assertRegex(output, '192.168.5')
+
+ def test_dhcp_client_settings(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ self.start_dnsmasq()
+
+ output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '12:34:56:78:9a:bc')
+ self.assertRegex(output, '192.168.5')
+ self.assertRegex(output, '1492')
+
+ output = subprocess.check_output(['ip', 'route']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, 'default.*dev veth99 proto dhcp')
+
+ self.search_words_in_file('vendor class: SusantVendorTest')
+ self.search_words_in_file('client MAC address: 12:34:56:78:9a:bc')
+ self.search_words_in_file('client provides name: test-hostname')
+ self.search_words_in_file('26:mtu')
+
+ def test_dhcp6_client_settings_rapidcommit_true(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ self.start_dnsmasq()
+
+ output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '12:34:56:78:9a:bc')
+
+ self.assertTrue(self.search_words_in_file('14:rapid-commit'))
+
+ def test_dhcp6_client_settings_rapidcommit_false(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ self.start_dnsmasq()
+
+ output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '12:34:56:78:9a:bc')
+
+ self.assertFalse(self.search_words_in_file('14:rapid-commit'))
+
+ def test_dhcp_client_settings_anonymize(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ self.start_dnsmasq()
+ self.assertFalse(self.search_words_in_file('VendorClassIdentifier=SusantVendorTest'))
+ self.assertFalse(self.search_words_in_file('test-hostname'))
+ self.assertFalse(self.search_words_in_file('26:mtu'))
+
+ def test_dhcp_client_listen_port(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
+ dh_server = DHCPServer("dhcp_server")
+ dh_server.start()
+
+ self.start_networkd()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ global port
+ global ip
+
+ self.assertRegex(str(port), '5555')
+ self.assertRegex(str(ip), '0.0.0.0')
+
+ dh_server.join()
+
+ def test_dhcp_route_table_id(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
+ self.start_networkd()
+ self.start_dnsmasq()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ output = subprocess.check_output(['ip', 'route', 'show', 'table', '12']).rstrip().decode('utf-8')
+ print(output)
+
+ self.assertRegex(output, 'veth99 proto dhcp')
+ self.assertRegex(output, '192.168.5.1')
+
+ def test_dhcp_route_metric(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
+ self.start_networkd()
+ self.start_dnsmasq()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+
+ self.assertRegex(output, 'metric 24')
+
+ def test_dhcp_route_criticalconnection_true(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
+ self.start_networkd()
+ self.start_dnsmasq()
+
+ self.assertTrue(self.link_exits('veth99'))
+
+ output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+
+ self.assertRegex(output, '192.168.5.*')
+ # Stoping dnsmasq as networkd won't be allowed to renew the DHCP lease.
+ self.stop_dnsmasq(dnsmasq_pid_file)
+
+ # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
+ time.sleep(125)
+
+ output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+ self.assertRegex(output, '192.168.5.*')
+
+if __name__ == '__main__':
+ unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
+ verbosity=3))
--- /dev/null
+#!/bin/sh
+
+set -eu
+
+cd "$@"/docs/
+(
+ echo "# systemd Documentation"
+
+ for f in *.md ; do
+ if [ "x$f" != "xindex.md" ] ; then
+ t=`grep "^# " "$f" | head -n 1 | sed -e 's/^#\s*//'`
+ echo -e "\n* [$t]($f)"
+ fi
+ done
+) > index.md
meson $build -D$fuzzflag -Db_lundef=false
ninja -C $build fuzzers
-for d in "$(dirname "$0")/../test/fuzz-corpus/"*; do
- zip -jqr $OUT/fuzz-$(basename "$d")_seed_corpus.zip "$d"
+# The seed corpus is a separate flat archive for each fuzzer,
+# with a fixed name ${fuzzer}_seed_corpus.zip.
+for d in "$(dirname "$0")/../test/fuzz/fuzz-"*; do
+ zip -jqr $OUT/$(basename "$d")_seed_corpus.zip "$d"
done
# get fuzz-dns-packet corpus
Description=Dispatch Password Requests to Console Directory Watch
Documentation=man:systemd-ask-password-console.service(8)
DefaultDependencies=no
-Conflicts=shutdown.target
+Conflicts=shutdown.target emergency.service
After=plymouth-start.service
Before=paths.target shutdown.target cryptsetup.target
ConditionPathExists=!/run/plymouth/pid
Description=Dispatch Password Requests to Console
Documentation=man:systemd-ask-password-console.service(8)
DefaultDependencies=no
-Conflicts=shutdown.target
+Conflicts=shutdown.target emergency.service
After=plymouth-start.service systemd-vconsole-setup.service
Before=shutdown.target
ConditionPathExists=!/run/plymouth/pid
Description=Forward Password Requests to Wall Directory Watch
Documentation=man:systemd-ask-password-console.service(8)
DefaultDependencies=no
-Conflicts=shutdown.target
+Conflicts=shutdown.target emergency.service
Before=paths.target shutdown.target cryptsetup.target
[Path]
ConditionCapability=CAP_NET_ADMIN
DefaultDependencies=no
# systemd-udevd.service can be dropped once tuntap is moved to netlink
-After=systemd-udevd.service network-pre.target systemd-sysctl.service
+After=systemd-udevd.service network-pre.target systemd-sysusers.service systemd-sysctl.service
Before=network.target multi-user.target shutdown.target
Conflicts=shutdown.target
Wants=network.target
ExecStart=!!@rootlibexecdir@/systemd-networkd
WatchdogSec=3min
User=systemd-network
-DynamicUser=yes
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW
+ProtectSystem=strict
ProtectHome=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
Documentation=https://www.freedesktop.org/wiki/Software/systemd/writing-network-configuration-managers
Documentation=https://www.freedesktop.org/wiki/Software/systemd/writing-resolver-clients
DefaultDependencies=no
-After=systemd-networkd.service
+After=systemd-sysusers.service systemd-networkd.service
Before=network.target nss-lookup.target shutdown.target
Conflicts=shutdown.target
Wants=nss-lookup.target
ExecStart=!!@rootlibexecdir@/systemd-resolved
WatchdogSec=3min
User=systemd-resolve
-DynamicUser=yes
CapabilityBoundingSet=CAP_SETPCAP CAP_NET_RAW CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_SETPCAP CAP_NET_RAW CAP_NET_BIND_SERVICE
+PrivateTmp=yes
PrivateDevices=yes
+ProtectSystem=strict
ProtectHome=yes
ProtectControlGroups=yes
ProtectKernelTunables=yes
ConditionCapability=CAP_SYS_TIME
ConditionVirtualization=!container
DefaultDependencies=no
-After=systemd-remount-fs.service
+After=systemd-remount-fs.service systemd-sysusers.service
Before=time-sync.target sysinit.target shutdown.target
Conflicts=shutdown.target
Wants=time-sync.target
ExecStart=!!@rootlibexecdir@/systemd-timesyncd
WatchdogSec=3min
User=systemd-timesync
-DynamicUser=yes
CapabilityBoundingSet=CAP_SYS_TIME
AmbientCapabilities=CAP_SYS_TIME
+PrivateTmp=yes
PrivateDevices=yes
+ProtectSystem=strict
ProtectHome=yes
ProtectControlGroups=yes
ProtectKernelTunables=yes