]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #13709 from zachsmith/systemd-tmpfiles-allow-append-to-file
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 4 Oct 2019 09:59:06 +0000 (11:59 +0200)
committerGitHub <noreply@github.com>
Fri, 4 Oct 2019 09:59:06 +0000 (11:59 +0200)
systemd-tmpfiles: allow appending content to file

144 files changed:
TODO
docs/ENVIRONMENT.md
hwdb/60-keyboard.hwdb
hwdb/60-sensor.hwdb
hwdb/70-pointingstick.hwdb
man/bootctl.xml
man/kernel-command-line.xml
man/sd_journal_print.xml
man/systemd.exec.xml
man/systemd.kill.xml
man/systemd.network.xml
man/systemd.resource-control.xml
man/systemd.service.xml
man/systemd.xml
meson.build
po/pl.po
rules/60-sensor.rules
rules/61-autosuspend-manual.rules [new file with mode: 0644]
rules/meson.build
shell-completion/bash/systemd-run
shell-completion/zsh/_systemd-run
src/backlight/backlight.c
src/basic/cgroup-util.c
src/basic/cgroup-util.h
src/basic/efivars.c [new file with mode: 0644]
src/basic/efivars.h [new file with mode: 0644]
src/basic/macro.h
src/basic/memory-util.h
src/basic/meson.build
src/basic/mountpoint-util.c
src/basic/path-util.c
src/basic/proc-cmdline.c
src/basic/proc-cmdline.h
src/basic/string-util.h
src/basic/util.c
src/basic/util.h
src/boot/bless-boot-generator.c
src/boot/bless-boot.c
src/boot/bootctl.c
src/core/automount.c
src/core/cgroup.c
src/core/cgroup.h
src/core/dbus-cgroup.c
src/core/dbus-job.h
src/core/dbus-kill.c
src/core/dbus-unit.h
src/core/execute.c
src/core/kill.c
src/core/kill.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/main.c
src/core/mount-setup.c
src/core/mount.c
src/core/scope.c
src/core/service.c
src/core/slice.c
src/core/smack-setup.c
src/core/socket.c
src/core/swap.c
src/core/unit.c
src/core/unit.h
src/cryptsetup/cryptsetup.c
src/debug-generator/debug-generator.c
src/gpt-auto-generator/gpt-auto-generator.c
src/libsystemd-network/dhcp-internal.h
src/libsystemd-network/dhcp-network.c
src/libsystemd-network/dhcp-packet.c
src/libsystemd-network/dhcp6-internal.h
src/libsystemd-network/dhcp6-option.c
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/test-dhcp-client.c
src/libsystemd/sd-bus/test-bus-creds.c
src/libsystemd/sd-event/sd-event.c
src/login/logind-dbus.c
src/login/logind.c
src/login/pam_systemd.c
src/network/networkd-conf.c
src/network/networkd-conf.h
src/network/networkd-dhcp-common.c
src/network/networkd-dhcp-common.h
src/network/networkd-dhcp4.c
src/network/networkd-dhcp6.c
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/nspawn/nspawn-cgroup.c
src/nspawn/nspawn-stub-pid1.c
src/nspawn/nspawn.c
src/nspawn/test-patch-uid.c
src/rfkill/rfkill.c
src/shared/boot-timestamps.c
src/shared/bootspec.c
src/shared/bus-unit-util.c
src/shared/cgroup-setup.c [new file with mode: 0644]
src/shared/cgroup-setup.h [new file with mode: 0644]
src/shared/condition.c
src/shared/crypt-util.h
src/shared/efi-loader.c [moved from src/shared/efivars.c with 79% similarity]
src/shared/efi-loader.h [moved from src/shared/efivars.h with 61% similarity]
src/shared/ethtool-util.c
src/shared/meson.build
src/shared/reboot-util.c
src/shared/reboot-util.h
src/shared/serialize.h
src/shared/unit-file.c
src/shared/unit-file.h
src/shutdown/shutdown.c
src/system-update-generator/system-update-generator.c
src/systemctl/systemctl.c
src/systemd/sd-dhcp-client.h
src/systemd/sd-dhcp6-client.h
src/test/meson.build
src/test/test-boot-timestamps.c
src/test/test-capability.c
src/test/test-cgroup-setup.c [new file with mode: 0644]
src/test/test-cgroup-util.c
src/test/test-cgroup.c
src/test/test-condition.c
src/test/test-engine.c
src/test/test-helper.c
src/test/test-job-type.c
src/test/test-proc-cmdline.c
src/test/test-unit-file.c
src/udev/udev-builtin-blkid.c
src/udev/udevadm-trigger.c
test/README.testsuite
test/TEST-13-NSPAWN-SMOKE/test.sh
test/TEST-23-TYPE-EXEC/testsuite.sh
test/fuzz/fuzz-network-parser/directives.network
test/fuzz/fuzz-unit-file/directives.service
test/test-execute/exec-dynamicuser-statedir.service
test/test-functions
test/test-network/systemd-networkd-tests.py
tools/chromeos/gen_autosuspend_rules.py [new file with mode: 0755]
tools/make-autosuspend-rules.py [new file with mode: 0755]
units/systemd-networkd.service.in

diff --git a/TODO b/TODO
index 4679be1e6515d3a35559e131cf006260afc96e42..03d38da9a0eec2d346f21b691449e8f452489b86 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1109,7 +1109,6 @@ External:
 
 * systemctl status foo.service should say that it is trigger by foo.timer
 * systemctl status should know about 'systemd-analyze calendar ... --iterations='
-* systemctl list-timers foo should use .timer suffix by default
 * If timer has just OnInactiveSec=..., it should fire after a specified time
   after being started.
 
index 838cc7e4cf88eaa7666187c1cf491615abfd3411..83c2d251340f04ed813852782cbe086fc1c200fc 100644 (file)
@@ -36,10 +36,13 @@ All tools:
 * `$SD_EVENT_PROFILE_DELAYS=1` â€” if set, the sd-event event loop implementation
   will print latency information at runtime.
 
-* `$SYSTEMD_PROC_CMDLINE` â€” if set, may contain a string that is used as kernel
-  command line instead of the actual one readable from /proc/cmdline. This is
-  useful for debugging, in order to test generators and other code against
-  specific kernel command lines.
+* `$SYSTEMD_PROC_CMDLINE` â€” if set, the contents are used as the kernel command
+  line instead of the actual one in /proc/cmdline. This is useful for
+  debugging, in order to test generators and other code against specific kernel
+  command lines.
+
+* `$SYSTEMD_EFI_OPTIONS` â€” if set, used instead of the string in SystemdOptions
+  EFI variable. Analogous to `$SYSTEMD_PROC_CMDLINE`.
 
 * `$SYSTEMD_IN_INITRD` â€” takes a boolean. If set, overrides initrd detection.
   This is useful for debugging and testing initrd-only programs in the main
@@ -70,8 +73,8 @@ systemctl:
 
 systemd-nspawn:
 
-* `$UNIFIED_CGROUP_HIERARCHY=1` â€” if set, force nspawn into unified cgroup
-  hierarchy mode.
+* `$SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=1` â€” if set, force nspawn into unified
+  cgroup hierarchy mode.
 
 * `$SYSTEMD_NSPAWN_API_VFS_WRITABLE=1` â€” if set, make /sys and /proc/sys and
   friends writable in the container. If set to "network", leave only
index ee40e12692a1e0a36590aae7ba58079c91033bc0..15f0a970b6c751ab6abfa946f08594e72cca4cf1 100644 (file)
@@ -23,7 +23,7 @@
 #      evdev:input:bZZZZvYYYYpXXXXeWWWW-VVVV
 #    This matches on the kernel modalias of the input-device, mainly:
 #    ZZZZ is the bus-id (see /usr/include/linux/input.h BUS_*), YYYY, XXXX and
-#    WWW are the 4-digit hex uppercase vendor, product and version ID and VVVV
+#    WWWW are the 4-digit hex uppercase vendor, product and version ID and VVVV
 #    is an arbitrary length input-modalias describing the device capabilities.
 #    The vendor, product and version ID for a device node "eventX" is listed
 #    in /sys/class/input/eventX/device/id.
@@ -1135,6 +1135,12 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMEDIONNB:pnA555*:pvr*
  KEYBOARD_KEY_67=email                                  # envelope button
  KEYBOARD_KEY_69=prog2                                  # link 2 button
 
+# Erazer
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMedion*:pnErazer*:pvr*
+ KEYBOARD_KEY_a0=!mute
+ KEYBOARD_KEY_ae=!volumedown
+ KEYBOARD_KEY_b0=!volumeup
+
 ###########################################################
 # Microsoft
 ###########################################################
index 97e8dc8aa7e6bf041a5a580bbc0efee6226b8eb1..ab07a4846a6167acd1dd108fb6d80b0adc411f5c 100644 (file)
@@ -252,6 +252,12 @@ sensor:modalias:acpi:ACCE0001*:dmi:*svnEndless*:*pnELT-NL3*
 sensor:modalias:acpi:KIOX000A*:dmi:*:svnEVE*:pnEveV:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
 
+#########################################
+# Google Chromebooks
+#########################################
+sensor:modalias:platform:cros-ec-accel:dmi:*:svnGOOGLE*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
+
 #########################################
 # GP-electronic
 #########################################
index 92d079f22f9b85a825723ed4519858898019bf1f..c5c7dd9725747a8da92a7a937f07f21dfb6638a3 100644 (file)
@@ -127,6 +127,15 @@ evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??50
 # Lenovo Thinkpad *60 series
 evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??60:*
 evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??60?:*
+# Lenovo Thinkpad *70 series
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??70:*
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??70?:*
+# Lenovo Thinkpad *80 series
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??80:*
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??80?:*
+# Lenovo Thinkpad *90 series
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??90:*
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??90?:*
 # Lenovo Thinkpad X1 Carbon 3rd gen
 evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX1Carbon3rd:*
 # Lenovo Thinkpad X1 Carbon 4th gen
index 822d07a606b8e325d83435bfae1fe8c4e8113ed0..7ce41b70f99e043a0877543400881f270175adf2 100644 (file)
         and the firmware's boot loader list.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>is-installed</option></term>
+
+        <listitem><para>Checks whether <command>systemd-boot</command> is installed in the ESP. Note that a
+        single ESP might host multiple boot loaders; this hence checks whether
+        <command>systemd-boot</command> is one (of possibly many) installed boot loaders â€” and neither
+        whether it is the default nor whether it is registered in any EFI variables.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>random-seed</option></term>
 
       </varlistentry>
 
       <varlistentry>
-        <term><option>is-installed</option></term>
+        <term><option>system-options</option> <optional><replaceable>VALUE</replaceable></optional></term>
 
-        <listitem><para>Checks whether <command>systemd-boot</command> is installed in the ESP. Note that a
-        single ESP might host multiple boot loaders; this hence checks whether
-        <command>systemd-boot</command> is one (of possibly many) installed boot loaders â€” and neither
-        whether it is the default nor whether it is registered in any EFI variables.</para></listitem>
+        <listitem><para>When called without the optional argument, prints the current value of the
+        <literal>SystemdOptions</literal> EFI variable. When called with an argument, sets the
+        variable to that value. See
+        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+        for the meaning of that variable.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index f9408a028d348bb632ce21d775282f1f35685b9b..848f5ec4435e36c68e2797335b728081bd13cb4b 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <para>The kernel, the initial RAM disk (initrd) and
-    basic userspace functionality may be configured at boot via
-    kernel command line arguments.</para>
+    <para>The kernel, the initial RAM disk (initrd) and basic userspace functionality may be configured at
+    boot via kernel command line arguments. In addition, various systemd tools look at the EFI variable
+    <literal>SystemdOptions</literal> (if available). Both sources are combined, but the kernel command line
+    has higher priority. Please note that <emphasis>the EFI variable is only used by systemd tools, and is
+    ignored by the kernel and other user space tools</emphasis>, so it is not a replacement for the kernel
+    command line.</para>
 
     <para>For command line parameters understood by the kernel, please
     see
         <citerefentry><refentrytitle>systemd-backlight@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd-rfkill.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
-        <citerefentry><refentrytitle>systemd-firstboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+        <citerefentry><refentrytitle>systemd-firstboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
       </para>
   </refsect1>
 
index ad9412ed544943c112ce669a2a68b4a583099331..85e5aa02807dbb5993a741ed65e4e248e2e18416 100644 (file)
@@ -70,6 +70,7 @@
     journal. The first argument is a priority value. This is followed by a format string and its parameters, similar to
     <citerefentry project='man-pages'><refentrytitle>printf</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
     <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+    Note that currently the resulting message will be trucated to <constant>LINE_MAX - 8</constant>.
     The priority value is one of <constant>LOG_EMERG</constant>, <constant>LOG_ALERT</constant>,
     <constant>LOG_CRIT</constant>, <constant>LOG_ERR</constant>, <constant>LOG_WARNING</constant>,
     <constant>LOG_NOTICE</constant>, <constant>LOG_INFO</constant>, <constant>LOG_DEBUG</constant>, as defined in
index 6dcccc38b4f49eb9b6ddedb5e1dac0761b0b9bd1..2f6fc0b5ba3c381381ff4f6483ef1613bb79ec59 100644 (file)
@@ -1869,6 +1869,12 @@ SystemCallErrorNumber=EPERM</programlisting>
         variable definitions. The parser strips leading and trailing whitespace from the values of assignments, unless
         you use double quotes (").</para>
 
+        <para><ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C escapes</ulink>
+        are supported, but not
+        <ulink url="https://en.wikipedia.org/wiki/Control_character#In_ASCII">most control characters</ulink>.
+        <literal>\t</literal> and <literal>\n</literal> can be used to insert tabs and newlines within
+        <varname>EnvironmentFile=</varname>.</para>
+
         <para>The argument passed should be an absolute filename or wildcard expression, optionally prefixed with
         <literal>-</literal>, which indicates that if the file does not exist, it will not be read and no error or
         warning message is logged. This option may be specified more than once in which case all specified files are
@@ -1899,6 +1905,12 @@ SystemCallErrorNumber=EPERM</programlisting>
         <para>Variables set for invoked processes due to this setting are subject to being overridden by those
         configured with <varname>Environment=</varname> or <varname>EnvironmentFile=</varname>.</para>
 
+        <para><ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C escapes</ulink>
+        are supported, but not
+        <ulink url="https://en.wikipedia.org/wiki/Control_character#In_ASCII">most control characters</ulink>.
+        <literal>\t</literal> and <literal>\n</literal> can be used to insert tabs and newlines within
+        <varname>EnvironmentFile=</varname>.</para>
+
         <para>Example:
         <programlisting>PassEnvironment=VAR1 VAR2 VAR3</programlisting>
         passes three variables <literal>VAR1</literal>,
index 2c6fea7493973b8777a9ca28f44f40a90c6cf93c..6a1c67d4063f8451400c0877cfafcf77619673b9 100644 (file)
         unless it is empty.</para>
 
         <para>Processes will first be terminated via <constant>SIGTERM</constant> (unless the signal to send
-        is changed via <varname>KillSignal=</varname>). Optionally, this is immediately followed by a
-        <constant>SIGHUP</constant> (if enabled with <varname>SendSIGHUP=</varname>). If processes still
-        remain after the main process of a unit has exited or the delay configured via the
-        <varname>TimeoutStopSec=</varname> has passed, the termination request is repeated with the
-        <constant>SIGKILL</constant> signal or the signal specified via <varname>FinalKillSignal=</varname>
-        (unless this is disabled via the <varname>SendSIGKILL=</varname> option). See
-        <citerefentry><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry> for more
-        information.</para>
+        is changed via <varname>KillSignal=</varname> or <varname>RestartKillSignal=</varname>). Optionally,
+        this is immediately followed by a <constant>SIGHUP</constant> (if enabled with
+        <varname>SendSIGHUP=</varname>). If processes still remain after the main process of a unit has
+        exited or the delay configured via the <varname>TimeoutStopSec=</varname> has passed, the termination
+        request is repeated with the <constant>SIGKILL</constant> signal or the signal specified via
+        <varname>FinalKillSignal=</varname> (unless this is disabled via the <varname>SendSIGKILL=</varname>
+        option). See <citerefentry><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+        for more information.</para>
 
         <para>Defaults to <option>control-group</option>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>KillSignal=</varname></term>
-        <listitem><para>Specifies which signal to use when killing a
-        service. This controls the signal that is sent as first step
-        of shutting down a unit (see above), and is usually followed
-        by <constant>SIGKILL</constant> (see above and below). For a
-        list of valid signals, see
+        <listitem><para>Specifies which signal to use when stopping a service. This controls the signal that
+        is sent as first step of shutting down a unit (see above), and is usually followed by
+        <constant>SIGKILL</constant> (see above and below). For a list of valid signals, see
         <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
-        Defaults to <constant>SIGTERM</constant>. </para>
+        Defaults to <constant>SIGTERM</constant>.</para>
 
-        <para>Note that, right after sending the signal specified in
-        this setting, systemd will always send
-        <constant>SIGCONT</constant>, to ensure that even suspended
-        tasks can be terminated cleanly.</para>
+        <para>Note that, right after sending the signal specified in this setting, systemd will always send
+        <constant>SIGCONT</constant>, to ensure that even suspended tasks can be terminated cleanly.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>RestartKillSignal=</varname></term>
+        <listitem><para>Specifies which signal to use when restarting a service. The same as
+        <varname>KillSignal=</varname> described above, with the exception that this setting is used in a
+        restart job. Not set by default, and the value of <varname>KillSignal=</varname> is used.</para>
         </listitem>
       </varlistentry>
 
index 585041095d738a706a9f8f28fb8a7aed7f8c552d..657ba662455e16e35a4c3b2bb8e2e0db78f46bdd 100644 (file)
           lease expires. This is contrary to the DHCP specification, but may be the best choice if,
           e.g., the root filesystem relies on this connection. The setting <literal>dhcp</literal>
           implies <literal>dhcp-on-stop</literal>, and <literal>yes</literal> implies
-          <literal>dhcp</literal> and <literal>static</literal>. Defaults to
-          <literal>dhcp-on-stop</literal>.</para>
+          <literal>dhcp</literal> and <literal>static</literal>. Defaults to <literal>no</literal>.
+          </para>
         </listitem>
       </varlistentry>
 
           <para>Note that if IPv6 is enabled on the interface, and the MTU is chosen
           below 1280 (the minimum MTU for IPv6) it will automatically be increased to this value.</para>
         </listitem>
-      </varlistentry>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>IPServiceType=</varname></term>
+          <listitem>
+            <para>Takes string; "CS6" or "CS4". Used to set IP service type to CS6 (network control)
+            or CS4 (Realtime). IPServiceType defaults to CS6 if nothing is specified.</para>
+          </listitem>
+        </varlistentry>
       </variablelist>
   </refsect1>
 
           <term><varname>SendRelease=</varname></term>
           <listitem>
             <para>When true, the DHCPv4 client sends a DHCP release packet when it stops.
-            Defaults to false.</para>
+            Defaults to true.</para>
           </listitem>
         </varlistentry>
 
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><varname>PrefixDelegationHint=</varname></term>
+          <listitem>
+            <para>Takes an IPv6 address with prefix length as <varname>Addresss=</varname> in
+            the "[Network]" section. Specifies the DHCPv6 client for the requesting router to include
+            a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1-128. Defaults to unset.</para>
+          </listitem>
+        </varlistentry>
       </variablelist>
   </refsect1>
 
index 98a0741359ac770a54bf98ccbe794b82aaa460c7..7daaba5074a7774f411624cda7ff1256cef0f7b8 100644 (file)
           <para>Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is
           parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a
           percentage value may be specified, which is taken relative to the installed physical memory on the
-          system. This controls the <literal>memory.min</literal> control group attribute. For details about this
+          system. If assigned the special value <literal>infinity</literal>, all available memory is protected, which may be
+          useful in order to always inherit all of the protection afforded by ancestors.
+          This controls the <literal>memory.min</literal> control group attribute. For details about this
           control group attribute, see <ulink
           url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
 
           <para>Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is
           parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a
           percentage value may be specified, which is taken relative to the installed physical memory on the
-          system. This controls the <literal>memory.low</literal> control group attribute. For details about this
+          system. If assigned the special value <literal>infinity</literal>, all available memory is protected, which may be
+          useful in order to always inherit all of the protection afforded by ancestors.
+          This controls the <literal>memory.low</literal> control group attribute. For details about this
           control group attribute, see <ulink
           url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
 
         <term><varname>MemoryHigh=<replaceable>bytes</replaceable></varname></term>
 
         <listitem>
-          <para>Specify the high limit on memory usage of the executed processes in this unit. Memory usage may go
+          <para>Specify the throttling limit on memory usage of the executed processes in this unit. Memory usage may go
           above the limit if unavoidable, but the processes are heavily slowed down and memory is taken away
           aggressively in such cases. This is the main mechanism to control memory usage of a unit.</para>
 
           parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a
           percentage value may be specified, which is taken relative to the installed physical memory on the
           system. If assigned the
-          special value <literal>infinity</literal>, no memory limit is applied. This controls the
+          special value <literal>infinity</literal>, no memory throttling is applied. This controls the
           <literal>memory.high</literal> control group attribute. For details about this control group attribute, see
           <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
 
index 14840c2e16d80200039145142d82cd6d2a235378..af14eedfcc6fac2b6681da021bf3c149896bcaa7 100644 (file)
 
       <varlistentry>
         <term><varname>ExecStop=</varname></term>
-        <listitem><para>Commands to execute to stop the service
-        started via <varname>ExecStart=</varname>. This argument takes
-        multiple command lines, following the same scheme as described
-        for <varname>ExecStart=</varname> above. Use of this setting
-        is optional. After the commands configured in this option are
-        run, it is implied that the service is stopped, and any processes
-        remaining for it are terminated
-        according to the <varname>KillMode=</varname> setting (see
+        <listitem><para>Commands to execute to stop the service started via
+        <varname>ExecStart=</varname>. This argument takes multiple command lines, following the same scheme
+        as described for <varname>ExecStart=</varname> above. Use of this setting is optional. After the
+        commands configured in this option are run, it is implied that the service is stopped, and any
+        processes remaining for it are terminated according to the <varname>KillMode=</varname> setting (see
         <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
-        If this option is not specified, the process is terminated by
-        sending the signal specified in <varname>KillSignal=</varname>
-        when service stop is requested. Specifier and environment
-        variable substitution is supported (including
+        If this option is not specified, the process is terminated by sending the signal specified in
+        <varname>KillSignal=</varname> or <varname>RestartKillSignal=</varname> when service stop is
+        requested. Specifier and environment variable substitution is supported (including
         <varname>$MAINPID</varname>, see above).</para>
 
-        <para>Note that it is usually not sufficient to specify a command for this setting that only asks the service
-        to terminate (for example, by queuing some form of termination signal for it), but does not wait for it to do
-        so. Since the remaining processes of the services are killed according to <varname>KillMode=</varname> and
-        <varname>KillSignal=</varname> as described above immediately after the command exited, this may not result in
-        a clean stop. The specified command should hence be a synchronous operation, not an asynchronous one.</para>
+        <para>Note that it is usually not sufficient to specify a command for this setting that only asks the
+        service to terminate (for example, by sending some form of termination signal to it), but does not
+        wait for it to do so. Since the remaining processes of the services are killed according to
+        <varname>KillMode=</varname> and <varname>KillSignal=</varname> or
+        <varname>RestartKillSignal=</varname> as described above immediately after the command exited, this
+        may not result in a clean stop. The specified command should hence be a synchronous operation, not an
+        asynchronous one.</para>
 
         <para>Note that the commands specified in <varname>ExecStop=</varname> are only executed when the service
         started successfully first. They are not invoked if the service was never started at all, or in case its
index c01cf46e812a5202f85f06ff275312bdd647fe1a..957d37dcd935fdbfa1c87f74e73546ab4a2cb7ff 100644 (file)
   <refsect1>
     <title>Kernel Command Line</title>
 
-    <para>When run as system instance systemd parses a number of
-    kernel command line arguments<footnote><para>If run inside a Linux
-    container these arguments may be passed as command line arguments
-    to systemd itself, next to any of the command line options listed
-    in the Options section above. If run outside of Linux containers,
-    these arguments are parsed from <filename>/proc/cmdline</filename>
-    instead.</para></footnote>:</para>
+    <para>When run as the system instance systemd parses a number of options listed below. They can be
+    specified as kernel command line arguments<footnote><para>If run inside a Linux container these arguments
+    may be passed as command line arguments to systemd itself, next to any of the command line options listed
+    in the Options section above. If run outside of Linux containers, these arguments are parsed from
+    <filename>/proc/cmdline</filename> instead.</para></footnote>, or through the
+    <literal>SystemdOptions</literal> EFI variable (on EFI systems). The kernel command line has higher
+    priority. Following variables are understood:</para>
 
     <variablelist class='kernel-commandline-options'>
       <varlistentry>
index e5ceb1e169db344f49849986a81e96c48b2cf2b0..1172516454b45cfa33ba4a08a6953492934fb4a4 100644 (file)
@@ -382,6 +382,7 @@ possible_cc_flags = [
 possible_link_flags = [
         '-Wl,-z,relro',
         '-Wl,-z,now',
+        '-fstack-protector',
 ]
 
 if cc.get_id() == 'clang'
@@ -960,20 +961,14 @@ conf.set10('HAVE_MICROHTTPD', have)
 want_libcryptsetup = get_option('libcryptsetup')
 if want_libcryptsetup != 'false' and not skip_deps
         libcryptsetup = dependency('libcryptsetup',
-                                   version : '>= 1.6.0',
+                                   version : '>= 2.0.1',
                                    required : want_libcryptsetup == 'true')
         have = libcryptsetup.found()
-        have_sector = cc.has_member(
-                    'struct crypt_params_plain',
-                    'sector_size',
-                    prefix : '#include <libcryptsetup.h>')
 else
         have = false
-        have_sector = false
         libcryptsetup = []
 endif
 conf.set10('HAVE_LIBCRYPTSETUP', have)
-conf.set10('HAVE_LIBCRYPTSETUP_SECTOR_SIZE', have_sector)
 
 want_libcurl = get_option('libcurl')
 if want_libcurl != 'false' and not skip_deps
@@ -1469,6 +1464,9 @@ install_libsystemd_static = static_library(
                         libgcrypt],
         c_args : libsystemd_c_args + (static_libsystemd_pic ? [] : ['-fno-PIC']))
 
+#Generate autosuspend rules
+make_autosuspend_rules_py = find_program('tools/make-autosuspend-rules.py')
+
 ############################################################
 
 # binaries that have --help and are intended for use by humans,
index 5c1588bebe47856c9c97f88d23a0921ba1af95f1..cd27d498f8fb0727f3c424ed4587c530b1a53802 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -6,8 +6,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
 "Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
-"POT-Creation-Date: 2019-09-13 15:30+0000\n"
-"PO-Revision-Date: 2019-09-14 12:44+0200\n"
+"POT-Creation-Date: 2019-09-22 15:30+0000\n"
+"PO-Revision-Date: 2019-09-28 15:18+0200\n"
 "Last-Translator: Piotr DrÄ…g <piotrdrag@gmail.com>\n"
 "Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n"
 "Language: pl\n"
@@ -709,6 +709,14 @@ msgstr "Przywrócenie ustawieÅ„ DNS"
 msgid "Authentication is required to reset DNS settings."
 msgstr "Wymagane jest uwierzytelnienie, aby przywrócić ustawienia DNS."
 
+#: src/network/org.freedesktop.network1.policy:143
+msgid "Renew dynamic addresses"
+msgstr "Odnowienie adresów dynamicznych"
+
+#: src/network/org.freedesktop.network1.policy:144
+msgid "Authentication is required to renew dynamic addresses."
+msgstr "Wymagane jest uwierzytelnienie, aby odnowić adresy dynamiczne."
+
 #: src/portable/org.freedesktop.portable1.policy:13
 msgid "Inspect a portable service image"
 msgstr "Badanie obrazu przenoÅ›nej usÅ‚ugi"
index 7ad2c36be3d405b3725bf8990daded4ce65645b6..7b9b7d2887bb6673f873c89c1f4d47245a9d6f11 100644 (file)
@@ -3,7 +3,7 @@
 ACTION=="remove", GOTO="sensor_end"
 
 # device matching the sensor's name and the machine's DMI data for IIO devices
-SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="usb|i2c", \
+SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="usb|i2c|platform", \
   IMPORT{builtin}="hwdb 'sensor:modalias:$attr{modalias}:$attr{[dmi/id]modalias}'", \
   GOTO="sensor_end"
 
diff --git a/rules/61-autosuspend-manual.rules b/rules/61-autosuspend-manual.rules
new file mode 100644 (file)
index 0000000..dcc0405
--- /dev/null
@@ -0,0 +1,20 @@
+# This udev rule is for any devices that should enter automatic suspend
+# but are not already included in generated rules from ChromeOS via
+# tools/make-autosuspend-rules.py
+#
+
+ACTION!="add", GOTO="autosuspend_manual_end"
+SUBSYSTEM!="usb", GOTO="autosuspend_manual_end"
+
+SUBSYSTEM=="usb", GOTO="autosuspend_manual_usb"
+
+# USB rules
+LABEL="autosuspend_manual_usb"
+GOTO="autosuspend_manual_end"
+
+# Enable autosuspend
+LABEL="autosuspend_manual_enable"
+TEST=="power/control", ATTR{power/control}="auto", GOTO="autosuspend_manual_end"
+
+LABEL="autosuspend_manual_end"
+
index 79423cc2c45f7eb047f63249d36884dd6afbfebd..57896aa1a4c1a2838ec40fd2fb63b18a98a0784f 100644 (file)
@@ -14,6 +14,7 @@ rules = files('''
         60-persistent-v4l.rules
         60-sensor.rules
         60-serial.rules
+        61-autosuspend-manual.rules
         70-joystick.rules
         70-mouse.rules
         70-touchpad.rules
@@ -44,3 +45,11 @@ foreach file : rules_in
                      install_dir : udevrulesdir)
         all_rules += gen
 endforeach
+
+auto_suspend_rules = custom_target(
+        '60-autosuspend-chromeos.rules',
+        output : '60-autosuspend-chromeos.rules',
+        command : make_autosuspend_rules_py,
+        capture : true,
+        install : true,
+        install_dir: [udevrulesdir])
index 4670973032b3d9d8844acdaa3eb1c5fafc23d5e3..707b038d9a8459431fd5388a8d2f29421e0895f3 100644 (file)
@@ -80,7 +80,7 @@ _systemd_run() {
                          SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group=
                          DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth=
                          BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment=
-                         KillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA=
+                         KillSignal= RestartKillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA=
                          LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC=
                          LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE=
                          LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices=
index 6a703a075bf9510ec099019def1d0252b55580b3..ca0faa14844dd2e3fc1224992c921361a6626e81 100644 (file)
@@ -35,7 +35,7 @@ _arguments \
                 SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group= \
                 DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth= \
                 BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment= \
-                KillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA= \
+                KillSignal= RestartKillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA= \
                 LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= \
                 LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= \
                 LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= \
index dfd68053980e3fbfa304cbe854ad26098023cd07..048441429025d966b1f629fff84ed2d8ffe07121 100644 (file)
@@ -13,7 +13,7 @@
 #include "main-func.h"
 #include "mkdir.h"
 #include "parse-util.h"
-#include "proc-cmdline.h"
+#include "reboot-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "util.h"
index 2a359a606374f2399affecaeb42487a9a02eb26b..7531cca5bcd03296c414d09992f92b7c8f0ac1c5 100644 (file)
@@ -31,7 +31,6 @@
 #include "mkdir.h"
 #include "parse-util.h"
 #include "path-util.h"
-#include "proc-cmdline.h"
 #include "process-util.h"
 #include "set.h"
 #include "special.h"
@@ -408,173 +407,6 @@ int cg_kill_recursive(
         return ret;
 }
 
-int cg_migrate(
-                const char *cfrom,
-                const char *pfrom,
-                const char *cto,
-                const char *pto,
-                CGroupFlags flags) {
-
-        bool done = false;
-        _cleanup_set_free_ Set *s = NULL;
-        int r, ret = 0;
-        pid_t my_pid;
-
-        assert(cfrom);
-        assert(pfrom);
-        assert(cto);
-        assert(pto);
-
-        s = set_new(NULL);
-        if (!s)
-                return -ENOMEM;
-
-        my_pid = getpid_cached();
-
-        do {
-                _cleanup_fclose_ FILE *f = NULL;
-                pid_t pid = 0;
-                done = true;
-
-                r = cg_enumerate_processes(cfrom, pfrom, &f);
-                if (r < 0) {
-                        if (ret >= 0 && r != -ENOENT)
-                                return r;
-
-                        return ret;
-                }
-
-                while ((r = cg_read_pid(f, &pid)) > 0) {
-
-                        /* This might do weird stuff if we aren't a
-                         * single-threaded program. However, we
-                         * luckily know we are not */
-                        if ((flags & CGROUP_IGNORE_SELF) && pid == my_pid)
-                                continue;
-
-                        if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
-                                continue;
-
-                        /* Ignore kernel threads. Since they can only
-                         * exist in the root cgroup, we only check for
-                         * them there. */
-                        if (cfrom &&
-                            empty_or_root(pfrom) &&
-                            is_kernel_thread(pid) > 0)
-                                continue;
-
-                        r = cg_attach(cto, pto, pid);
-                        if (r < 0) {
-                                if (ret >= 0 && r != -ESRCH)
-                                        ret = r;
-                        } else if (ret == 0)
-                                ret = 1;
-
-                        done = false;
-
-                        r = set_put(s, PID_TO_PTR(pid));
-                        if (r < 0) {
-                                if (ret >= 0)
-                                        return r;
-
-                                return ret;
-                        }
-                }
-
-                if (r < 0) {
-                        if (ret >= 0)
-                                return r;
-
-                        return ret;
-                }
-        } while (!done);
-
-        return ret;
-}
-
-int cg_migrate_recursive(
-                const char *cfrom,
-                const char *pfrom,
-                const char *cto,
-                const char *pto,
-                CGroupFlags flags) {
-
-        _cleanup_closedir_ DIR *d = NULL;
-        int r, ret = 0;
-        char *fn;
-
-        assert(cfrom);
-        assert(pfrom);
-        assert(cto);
-        assert(pto);
-
-        ret = cg_migrate(cfrom, pfrom, cto, pto, flags);
-
-        r = cg_enumerate_subgroups(cfrom, pfrom, &d);
-        if (r < 0) {
-                if (ret >= 0 && r != -ENOENT)
-                        return r;
-
-                return ret;
-        }
-
-        while ((r = cg_read_subgroup(d, &fn)) > 0) {
-                _cleanup_free_ char *p = NULL;
-
-                p = path_join(empty_to_root(pfrom), fn);
-                free(fn);
-                if (!p)
-                        return -ENOMEM;
-
-                r = cg_migrate_recursive(cfrom, p, cto, pto, flags);
-                if (r != 0 && ret >= 0)
-                        ret = r;
-        }
-
-        if (r < 0 && ret >= 0)
-                ret = r;
-
-        if (flags & CGROUP_REMOVE) {
-                r = cg_rmdir(cfrom, pfrom);
-                if (r < 0 && ret >= 0 && !IN_SET(r, -ENOENT, -EBUSY))
-                        return r;
-        }
-
-        return ret;
-}
-
-int cg_migrate_recursive_fallback(
-                const char *cfrom,
-                const char *pfrom,
-                const char *cto,
-                const char *pto,
-                CGroupFlags flags) {
-
-        int r;
-
-        assert(cfrom);
-        assert(pfrom);
-        assert(cto);
-        assert(pto);
-
-        r = cg_migrate_recursive(cfrom, pfrom, cto, pto, flags);
-        if (r < 0) {
-                char prefix[strlen(pto) + 1];
-
-                /* This didn't work? Then let's try all prefixes of the destination */
-
-                PATH_FOREACH_PREFIX(prefix, pto) {
-                        int q;
-
-                        q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, flags);
-                        if (q >= 0)
-                                return q;
-                }
-        }
-
-        return r;
-}
-
 static const char *controller_to_dirname(const char *controller) {
         const char *e;
 
@@ -740,253 +572,6 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
         return cg_get_path(controller, path, suffix, fs);
 }
 
-static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
-        assert(path);
-        assert(sb);
-        assert(ftwbuf);
-
-        if (typeflag != FTW_DP)
-                return 0;
-
-        if (ftwbuf->level < 1)
-                return 0;
-
-        (void) rmdir(path);
-        return 0;
-}
-
-int cg_trim(const char *controller, const char *path, bool delete_root) {
-        _cleanup_free_ char *fs = NULL;
-        int r = 0, q;
-
-        assert(path);
-
-        r = cg_get_path(controller, path, NULL, &fs);
-        if (r < 0)
-                return r;
-
-        errno = 0;
-        if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) {
-                if (errno == ENOENT)
-                        r = 0;
-                else
-                        r = errno_or_else(EIO);
-        }
-
-        if (delete_root) {
-                if (rmdir(fs) < 0 && errno != ENOENT)
-                        return -errno;
-        }
-
-        q = cg_hybrid_unified();
-        if (q < 0)
-                return q;
-        if (q > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
-                q = cg_trim(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, delete_root);
-                if (q < 0)
-                        log_warning_errno(q, "Failed to trim compat systemd cgroup %s: %m", path);
-        }
-
-        return r;
-}
-
-/* Create a cgroup in the hierarchy of controller.
- * Returns 0 if the group already existed, 1 on success, negative otherwise.
- */
-int cg_create(const char *controller, const char *path) {
-        _cleanup_free_ char *fs = NULL;
-        int r;
-
-        r = cg_get_path_and_check(controller, path, NULL, &fs);
-        if (r < 0)
-                return r;
-
-        r = mkdir_parents(fs, 0755);
-        if (r < 0)
-                return r;
-
-        r = mkdir_errno_wrapper(fs, 0755);
-        if (r == -EEXIST)
-                return 0;
-        if (r < 0)
-                return r;
-
-        r = cg_hybrid_unified();
-        if (r < 0)
-                return r;
-
-        if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
-                r = cg_create(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to create compat systemd cgroup %s: %m", path);
-        }
-
-        return 1;
-}
-
-int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
-        int r, q;
-
-        assert(pid >= 0);
-
-        r = cg_create(controller, path);
-        if (r < 0)
-                return r;
-
-        q = cg_attach(controller, path, pid);
-        if (q < 0)
-                return q;
-
-        /* This does not remove the cgroup on failure */
-        return r;
-}
-
-int cg_attach(const char *controller, const char *path, pid_t pid) {
-        _cleanup_free_ char *fs = NULL;
-        char c[DECIMAL_STR_MAX(pid_t) + 2];
-        int r;
-
-        assert(path);
-        assert(pid >= 0);
-
-        r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
-        if (r < 0)
-                return r;
-
-        if (pid == 0)
-                pid = getpid_cached();
-
-        xsprintf(c, PID_FMT "\n", pid);
-
-        r = write_string_file(fs, c, WRITE_STRING_FILE_DISABLE_BUFFER);
-        if (r < 0)
-                return r;
-
-        r = cg_hybrid_unified();
-        if (r < 0)
-                return r;
-
-        if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
-                r = cg_attach(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, pid);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to attach "PID_FMT" to compat systemd cgroup %s: %m", pid, path);
-        }
-
-        return 0;
-}
-
-int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
-        int r;
-
-        assert(controller);
-        assert(path);
-        assert(pid >= 0);
-
-        r = cg_attach(controller, path, pid);
-        if (r < 0) {
-                char prefix[strlen(path) + 1];
-
-                /* This didn't work? Then let's try all prefixes of
-                 * the destination */
-
-                PATH_FOREACH_PREFIX(prefix, path) {
-                        int q;
-
-                        q = cg_attach(controller, prefix, pid);
-                        if (q >= 0)
-                                return q;
-                }
-        }
-
-        return r;
-}
-
-int cg_set_access(
-                const char *controller,
-                const char *path,
-                uid_t uid,
-                gid_t gid) {
-
-        struct Attribute {
-                const char *name;
-                bool fatal;
-        };
-
-        /* cgroup v1, aka legacy/non-unified */
-        static const struct Attribute legacy_attributes[] = {
-                { "cgroup.procs",           true  },
-                { "tasks",                  false },
-                { "cgroup.clone_children",  false },
-                {},
-        };
-
-        /* cgroup v2, aka unified */
-        static const struct Attribute unified_attributes[] = {
-                { "cgroup.procs",           true  },
-                { "cgroup.subtree_control", true  },
-                { "cgroup.threads",         false },
-                {},
-        };
-
-        static const struct Attribute* const attributes[] = {
-                [false] = legacy_attributes,
-                [true]  = unified_attributes,
-        };
-
-        _cleanup_free_ char *fs = NULL;
-        const struct Attribute *i;
-        int r, unified;
-
-        assert(path);
-
-        if (uid == UID_INVALID && gid == GID_INVALID)
-                return 0;
-
-        unified = cg_unified_controller(controller);
-        if (unified < 0)
-                return unified;
-
-        /* Configure access to the cgroup itself */
-        r = cg_get_path(controller, path, NULL, &fs);
-        if (r < 0)
-                return r;
-
-        r = chmod_and_chown(fs, 0755, uid, gid);
-        if (r < 0)
-                return r;
-
-        /* Configure access to the cgroup's attributes */
-        for (i = attributes[unified]; i->name; i++) {
-                fs = mfree(fs);
-
-                r = cg_get_path(controller, path, i->name, &fs);
-                if (r < 0)
-                        return r;
-
-                r = chmod_and_chown(fs, 0644, uid, gid);
-                if (r < 0) {
-                        if (i->fatal)
-                                return r;
-
-                        log_debug_errno(r, "Failed to set access on cgroup %s, ignoring: %m", fs);
-                }
-        }
-
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
-                r = cg_hybrid_unified();
-                if (r < 0)
-                        return r;
-                if (r > 0) {
-                        /* Always propagate access mode from unified to legacy controller */
-                        r = cg_set_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, uid, gid);
-                        if (r < 0)
-                                log_debug_errno(r, "Failed to set access on compatibility systemd cgroup %s, ignoring: %m", path);
-                }
-        }
-
-        return 0;
-}
-
 int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags) {
         _cleanup_free_ char *fs = NULL;
         int r;
@@ -2141,194 +1726,6 @@ fail:
 done:
         memcpy(ret_values, v, sizeof(char*) * n);
         return 0;
-
-}
-
-int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {
-        CGroupController c;
-        CGroupMask done;
-        bool created;
-        int r;
-
-        /* This one will create a cgroup in our private tree, but also
-         * duplicate it in the trees specified in mask, and remove it
-         * in all others.
-         *
-         * Returns 0 if the group already existed in the systemd hierarchy,
-         * 1 on success, negative otherwise.
-         */
-
-        /* First create the cgroup in our own hierarchy. */
-        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
-        if (r < 0)
-                return r;
-        created = r;
-
-        /* If we are in the unified hierarchy, we are done now */
-        r = cg_all_unified();
-        if (r < 0)
-                return r;
-        if (r > 0)
-                return created;
-
-        supported &= CGROUP_MASK_V1;
-        mask = CGROUP_MASK_EXTEND_JOINED(mask);
-        done = 0;
-
-        /* Otherwise, do the same in the other hierarchies */
-        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
-                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
-                const char *n;
-
-                if (!FLAGS_SET(supported, bit))
-                        continue;
-
-                if (FLAGS_SET(done, bit))
-                        continue;
-
-                n = cgroup_controller_to_string(c);
-                if (FLAGS_SET(mask, bit))
-                        (void) cg_create(n, path);
-                else
-                        (void) cg_trim(n, path, true);
-
-                done |= CGROUP_MASK_EXTEND_JOINED(bit);
-        }
-
-        return created;
-}
-
-int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
-        CGroupController c;
-        CGroupMask done;
-        int r;
-
-        r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
-        if (r < 0)
-                return r;
-
-        r = cg_all_unified();
-        if (r < 0)
-                return r;
-        if (r > 0)
-                return 0;
-
-        supported &= CGROUP_MASK_V1;
-        done = 0;
-
-        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
-                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
-                const char *p = NULL;
-
-                if (!FLAGS_SET(supported, bit))
-                        continue;
-
-                if (FLAGS_SET(done, bit))
-                        continue;
-
-                if (path_callback)
-                        p = path_callback(bit, userdata);
-                if (!p)
-                        p = path;
-
-                (void) cg_attach_fallback(cgroup_controller_to_string(c), p, pid);
-                done |= CGROUP_MASK_EXTEND_JOINED(bit);
-        }
-
-        return 0;
-}
-
-int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
-        Iterator i;
-        void *pidp;
-        int r = 0;
-
-        SET_FOREACH(pidp, pids, i) {
-                pid_t pid = PTR_TO_PID(pidp);
-                int q;
-
-                q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
-                if (q < 0 && r >= 0)
-                        r = q;
-        }
-
-        return r;
-}
-
-int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
-        CGroupController c;
-        CGroupMask done;
-        int r = 0, q;
-
-        if (!path_equal(from, to))  {
-                r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, CGROUP_REMOVE);
-                if (r < 0)
-                        return r;
-        }
-
-        q = cg_all_unified();
-        if (q < 0)
-                return q;
-        if (q > 0)
-                return r;
-
-        supported &= CGROUP_MASK_V1;
-        done = 0;
-
-        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
-                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
-                const char *p = NULL;
-
-                if (!FLAGS_SET(supported, bit))
-                        continue;
-
-                if (FLAGS_SET(done, bit))
-                        continue;
-
-                if (to_callback)
-                        p = to_callback(bit, userdata);
-                if (!p)
-                        p = to;
-
-                (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, 0);
-                done |= CGROUP_MASK_EXTEND_JOINED(bit);
-        }
-
-        return r;
-}
-
-int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
-        CGroupController c;
-        CGroupMask done;
-        int r, q;
-
-        r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
-        if (r < 0)
-                return r;
-
-        q = cg_all_unified();
-        if (q < 0)
-                return q;
-        if (q > 0)
-                return r;
-
-        supported &= CGROUP_MASK_V1;
-        done = 0;
-
-        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
-                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
-
-                if (!FLAGS_SET(supported, bit))
-                        continue;
-
-                if (FLAGS_SET(done, bit))
-                        continue;
-
-                (void) cg_trim(cgroup_controller_to_string(c), path, delete_root);
-                done |= CGROUP_MASK_EXTEND_JOINED(bit);
-        }
-
-        return r;
 }
 
 int cg_mask_to_string(CGroupMask mask, char **ret) {
@@ -2523,20 +1920,20 @@ int cg_kernel_controllers(Set **ret) {
         return 0;
 }
 
-static thread_local CGroupUnified unified_cache = CGROUP_UNIFIED_UNKNOWN;
-
-/* The hybrid mode was initially implemented in v232 and simply mounted cgroup2 on /sys/fs/cgroup/systemd.  This
- * unfortunately broke other tools (such as docker) which expected the v1 "name=systemd" hierarchy on
- * /sys/fs/cgroup/systemd.  From v233 and on, the hybrid mode mountnbs v2 on /sys/fs/cgroup/unified and maintains
- * "name=systemd" hierarchy on /sys/fs/cgroup/systemd for compatibility with other tools.
+/* The hybrid mode was initially implemented in v232 and simply mounted cgroup2 on
+ * /sys/fs/cgroup/systemd. This unfortunately broke other tools (such as docker) which expected the v1
+ * "name=systemd" hierarchy on /sys/fs/cgroup/systemd. From v233 and on, the hybrid mode mounts v2 on
+ * /sys/fs/cgroup/unified and maintains "name=systemd" hierarchy on /sys/fs/cgroup/systemd for compatibility
+ * with other tools.
  *
- * To keep live upgrade working, we detect and support v232 layout.  When v232 layout is detected, to keep cgroup v2
- * process management but disable the compat dual layout, we return %true on
- * cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) and %false on cg_hybrid_unified().
+ * To keep live upgrade working, we detect and support v232 layout. When v232 layout is detected, to keep
+ * cgroup v2 process management but disable the compat dual layout, we return true on
+ * cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) and false on cg_hybrid_unified().
  */
 static thread_local bool unified_systemd_v232;
 
-static int cg_unified_update(void) {
+int cg_unified_cached(bool flush) {
+        static thread_local CGroupUnified unified_cache = CGROUP_UNIFIED_UNKNOWN;
 
         struct statfs fs;
 
@@ -2545,8 +1942,10 @@ static int cg_unified_update(void) {
          * have any other trouble determining if the unified hierarchy
          * is supported. */
 
-        if (unified_cache >= CGROUP_UNIFIED_NONE)
-                return 0;
+        if (flush)
+                unified_cache = CGROUP_UNIFIED_UNKNOWN;
+        else if (unified_cache >= CGROUP_UNIFIED_NONE)
+                return unified_cache;
 
         if (statfs("/sys/fs/cgroup/", &fs) < 0)
                 return log_debug_errno(errno, "statfs(\"/sys/fs/cgroup/\") failed: %m");
@@ -2582,20 +1981,20 @@ static int cg_unified_update(void) {
                                        "Unknown filesystem type %llx mounted on /sys/fs/cgroup.",
                                        (unsigned long long)fs.f_type);
 
-        return 0;
+        return unified_cache;
 }
 
 int cg_unified_controller(const char *controller) {
         int r;
 
-        r = cg_unified_update();
+        r = cg_unified_cached(false);
         if (r < 0)
                 return r;
 
-        if (unified_cache == CGROUP_UNIFIED_NONE)
+        if (r == CGROUP_UNIFIED_NONE)
                 return false;
 
-        if (unified_cache >= CGROUP_UNIFIED_ALL)
+        if (r >= CGROUP_UNIFIED_ALL)
                 return true;
 
         return streq_ptr(controller, SYSTEMD_CGROUP_CONTROLLER);
@@ -2604,231 +2003,21 @@ int cg_unified_controller(const char *controller) {
 int cg_all_unified(void) {
         int r;
 
-        r = cg_unified_update();
+        r = cg_unified_cached(false);
         if (r < 0)
                 return r;
 
-        return unified_cache >= CGROUP_UNIFIED_ALL;
+        return r >= CGROUP_UNIFIED_ALL;
 }
 
 int cg_hybrid_unified(void) {
         int r;
 
-        r = cg_unified_update();
-        if (r < 0)
-                return r;
-
-        return unified_cache == CGROUP_UNIFIED_SYSTEMD && !unified_systemd_v232;
-}
-
-int cg_unified_flush(void) {
-        unified_cache = CGROUP_UNIFIED_UNKNOWN;
-
-        return cg_unified_update();
-}
-
-int cg_enable_everywhere(
-                CGroupMask supported,
-                CGroupMask mask,
-                const char *p,
-                CGroupMask *ret_result_mask) {
-
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *fs = NULL;
-        CGroupController c;
-        CGroupMask ret = 0;
-        int r;
-
-        assert(p);
-
-        if (supported == 0) {
-                if (ret_result_mask)
-                        *ret_result_mask = 0;
-                return 0;
-        }
-
-        r = cg_all_unified();
-        if (r < 0)
-                return r;
-        if (r == 0) {
-                /* On the legacy hierarchy there's no concept of "enabling" controllers in cgroups defined. Let's claim
-                 * complete success right away. (If you wonder why we return the full mask here, rather than zero: the
-                 * caller tends to use the returned mask later on to compare if all controllers where properly joined,
-                 * and if not requeues realization. This use is the primary purpose of the return value, hence let's
-                 * minimize surprises here and reduce triggers for re-realization by always saying we fully
-                 * succeeded.) */
-                if (ret_result_mask)
-                        *ret_result_mask = mask & supported & CGROUP_MASK_V2; /* If you wonder why we mask this with
-                                                                               * CGROUP_MASK_V2: The 'supported' mask
-                                                                               * might contain pure-V1 or BPF
-                                                                               * controllers, and we never want to
-                                                                               * claim that we could enable those with
-                                                                               * cgroup.subtree_control */
-                return 0;
-        }
-
-        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, p, "cgroup.subtree_control", &fs);
-        if (r < 0)
-                return r;
-
-        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
-                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
-                const char *n;
-
-                if (!FLAGS_SET(CGROUP_MASK_V2, bit))
-                        continue;
-
-                if (!FLAGS_SET(supported, bit))
-                        continue;
-
-                n = cgroup_controller_to_string(c);
-                {
-                        char s[1 + strlen(n) + 1];
-
-                        s[0] = FLAGS_SET(mask, bit) ? '+' : '-';
-                        strcpy(s + 1, n);
-
-                        if (!f) {
-                                f = fopen(fs, "we");
-                                if (!f)
-                                        return log_debug_errno(errno, "Failed to open cgroup.subtree_control file of %s: %m", p);
-                        }
-
-                        r = write_string_stream(f, s, WRITE_STRING_FILE_DISABLE_BUFFER);
-                        if (r < 0) {
-                                log_debug_errno(r, "Failed to %s controller %s for %s (%s): %m",
-                                                FLAGS_SET(mask, bit) ? "enable" : "disable", n, p, fs);
-                                clearerr(f);
-
-                                /* If we can't turn off a controller, leave it on in the reported resulting mask. This
-                                 * happens for example when we attempt to turn off a controller up in the tree that is
-                                 * used down in the tree. */
-                                if (!FLAGS_SET(mask, bit) && r == -EBUSY) /* You might wonder why we check for EBUSY
-                                                                           * only here, and not follow the same logic
-                                                                           * for other errors such as EINVAL or
-                                                                           * EOPNOTSUPP or anything else. That's
-                                                                           * because EBUSY indicates that the
-                                                                           * controllers is currently enabled and
-                                                                           * cannot be disabled because something down
-                                                                           * the hierarchy is still using it. Any other
-                                                                           * error most likely means something like "I
-                                                                           * never heard of this controller" or
-                                                                           * similar. In the former case it's hence
-                                                                           * safe to assume the controller is still on
-                                                                           * after the failed operation, while in the
-                                                                           * latter case it's safer to assume the
-                                                                           * controller is unknown and hence certainly
-                                                                           * not enabled. */
-                                        ret |= bit;
-                        } else {
-                                /* Otherwise, if we managed to turn on a controller, set the bit reflecting that. */
-                                if (FLAGS_SET(mask, bit))
-                                        ret |= bit;
-                        }
-                }
-        }
-
-        /* Let's return the precise set of controllers now enabled for the cgroup. */
-        if (ret_result_mask)
-                *ret_result_mask = ret;
-
-        return 0;
-}
-
-bool cg_is_unified_wanted(void) {
-        static thread_local int wanted = -1;
-        int r;
-        bool b;
-        const bool is_default = DEFAULT_HIERARCHY == CGROUP_UNIFIED_ALL;
-        _cleanup_free_ char *c = NULL;
-
-        /* If we have a cached value, return that. */
-        if (wanted >= 0)
-                return wanted;
-
-        /* If the hierarchy is already mounted, then follow whatever
-         * was chosen for it. */
-        if (cg_unified_flush() >= 0)
-                return (wanted = unified_cache >= CGROUP_UNIFIED_ALL);
-
-        /* If we were explicitly passed systemd.unified_cgroup_hierarchy,
-         * respect that. */
-        r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", &b);
-        if (r > 0)
-                return (wanted = b);
-
-        /* If we passed cgroup_no_v1=all with no other instructions, it seems
-         * highly unlikely that we want to use hybrid or legacy hierarchy. */
-        r = proc_cmdline_get_key("cgroup_no_v1", 0, &c);
-        if (r > 0 && streq_ptr(c, "all"))
-                return (wanted = true);
-
-        return (wanted = is_default);
-}
-
-bool cg_is_legacy_wanted(void) {
-        static thread_local int wanted = -1;
-
-        /* If we have a cached value, return that. */
-        if (wanted >= 0)
-                return wanted;
-
-        /* Check if we have cgroup v2 already mounted. */
-        if (cg_unified_flush() >= 0 &&
-            unified_cache == CGROUP_UNIFIED_ALL)
-                return (wanted = false);
-
-        /* Otherwise, assume that at least partial legacy is wanted,
-         * since cgroup v2 should already be mounted at this point. */
-        return (wanted = true);
-}
-
-bool cg_is_hybrid_wanted(void) {
-        static thread_local int wanted = -1;
-        int r;
-        bool b;
-        const bool is_default = DEFAULT_HIERARCHY >= CGROUP_UNIFIED_SYSTEMD;
-        /* We default to true if the default is "hybrid", obviously,
-         * but also when the default is "unified", because if we get
-         * called, it means that unified hierarchy was not mounted. */
-
-        /* If we have a cached value, return that. */
-        if (wanted >= 0)
-                return wanted;
-
-        /* If the hierarchy is already mounted, then follow whatever
-         * was chosen for it. */
-        if (cg_unified_flush() >= 0 &&
-            unified_cache == CGROUP_UNIFIED_ALL)
-                return (wanted = false);
-
-        /* Otherwise, let's see what the kernel command line has to say.
-         * Since checking is expensive, cache a non-error result. */
-        r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", &b);
-
-        /* The meaning of the kernel option is reversed wrt. to the return value
-         * of this function, hence the negation. */
-        return (wanted = r > 0 ? !b : is_default);
-}
-
-int cg_weight_parse(const char *s, uint64_t *ret) {
-        uint64_t u;
-        int r;
-
-        if (isempty(s)) {
-                *ret = CGROUP_WEIGHT_INVALID;
-                return 0;
-        }
-
-        r = safe_atou64(s, &u);
+        r = cg_unified_cached(false);
         if (r < 0)
                 return r;
 
-        if (u < CGROUP_WEIGHT_MIN || u > CGROUP_WEIGHT_MAX)
-                return -ERANGE;
-
-        *ret = u;
-        return 0;
+        return r == CGROUP_UNIFIED_SYSTEMD && !unified_systemd_v232;
 }
 
 const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX] = {
@@ -2847,46 +2036,6 @@ static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] =
 
 DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType);
 
-int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
-        uint64_t u;
-        int r;
-
-        if (isempty(s)) {
-                *ret = CGROUP_CPU_SHARES_INVALID;
-                return 0;
-        }
-
-        r = safe_atou64(s, &u);
-        if (r < 0)
-                return r;
-
-        if (u < CGROUP_CPU_SHARES_MIN || u > CGROUP_CPU_SHARES_MAX)
-                return -ERANGE;
-
-        *ret = u;
-        return 0;
-}
-
-int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
-        uint64_t u;
-        int r;
-
-        if (isempty(s)) {
-                *ret = CGROUP_BLKIO_WEIGHT_INVALID;
-                return 0;
-        }
-
-        r = safe_atou64(s, &u);
-        if (r < 0)
-                return r;
-
-        if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX)
-                return -ERANGE;
-
-        *ret = u;
-        return 0;
-}
-
 bool is_cgroup_fs(const struct statfs *s) {
         return is_fs_type(s, CGROUP_SUPER_MAGIC) ||
                is_fs_type(s, CGROUP2_SUPER_MAGIC);
index ab094fdc4fb296f0e80cf097d5244b13a27a6014..0a64715af5e22066d745b1aa3282d6b00bdce739 100644 (file)
@@ -174,10 +174,6 @@ typedef int (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata);
 int cg_kill(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
 int cg_kill_recursive(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
 
-int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);
-int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);
-int cg_migrate_recursive_fallback(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);
-
 int cg_split_spec(const char *spec, char **controller, char **path);
 int cg_mangle_path(const char *path, char **result);
 
@@ -186,15 +182,8 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
 
 int cg_pid_get_path(const char *controller, pid_t pid, char **path);
 
-int cg_trim(const char *controller, const char *path, bool delete_root);
-
 int cg_rmdir(const char *controller, const char *path);
 
-int cg_create(const char *controller, const char *path);
-int cg_attach(const char *controller, const char *path, pid_t pid);
-int cg_attach_fallback(const char *controller, const char *path, pid_t pid);
-int cg_create_and_attach(const char *controller, const char *path, pid_t pid);
-
 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value);
 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret);
 int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, char **keys, char **values);
@@ -242,13 +231,6 @@ int cg_slice_to_path(const char *unit, char **ret);
 
 typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata);
 
-int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path);
-int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t callback, void *userdata);
-int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t callback, void *userdata);
-int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t callback, void *userdata);
-int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root);
-int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p, CGroupMask *ret_result_mask);
-
 int cg_mask_supported(CGroupMask *ret);
 int cg_mask_from_string(const char *s, CGroupMask *ret);
 int cg_mask_to_string(CGroupMask mask, char **ret);
@@ -260,18 +242,13 @@ bool cg_ns_supported(void);
 int cg_all_unified(void);
 int cg_hybrid_unified(void);
 int cg_unified_controller(const char *controller);
-int cg_unified_flush(void);
-
-bool cg_is_unified_wanted(void);
-bool cg_is_legacy_wanted(void);
-bool cg_is_hybrid_wanted(void);
+int cg_unified_cached(bool flush);
+static inline int cg_unified(void) {
+        return cg_unified_cached(true);
+}
 
 const char* cgroup_controller_to_string(CGroupController c) _const_;
 CGroupController cgroup_controller_from_string(const char *s) _pure_;
 
-int cg_weight_parse(const char *s, uint64_t *ret);
-int cg_cpu_shares_parse(const char *s, uint64_t *ret);
-int cg_blkio_weight_parse(const char *s, uint64_t *ret);
-
 bool is_cgroup_fs(const struct statfs *s);
 bool fd_is_cgroup_fs(int fd);
diff --git a/src/basic/efivars.c b/src/basic/efivars.c
new file mode 100644 (file)
index 0000000..53875de
--- /dev/null
@@ -0,0 +1,250 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <linux/fs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "chattr-util.h"
+#include "efivars.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "macro.h"
+#include "stdio-util.h"
+#include "strv.h"
+#include "time-util.h"
+#include "utf8.h"
+
+#if ENABLE_EFI
+
+char* efi_variable_path(sd_id128_t vendor, const char *name) {
+        char *p;
+
+        if (asprintf(&p,
+                     "/sys/firmware/efi/efivars/%s-" SD_ID128_UUID_FORMAT_STR,
+                     name, SD_ID128_FORMAT_VAL(vendor)) < 0)
+                return NULL;
+
+        return p;
+}
+
+int efi_get_variable(
+                sd_id128_t vendor,
+                const char *name,
+                uint32_t *ret_attribute,
+                void **ret_value,
+                size_t *ret_size) {
+
+        _cleanup_close_ int fd = -1;
+        _cleanup_free_ char *p = NULL;
+        _cleanup_free_ void *buf = NULL;
+        struct stat st;
+        uint32_t a;
+        ssize_t n;
+
+        assert(name);
+
+        p = efi_variable_path(vendor, name);
+        if (!p)
+                return -ENOMEM;
+
+        if (!ret_value && !ret_size && !ret_attribute) {
+                /* If caller is not interested in anything, just check if the variable exists and is readable
+                 * to us. */
+                if (access(p, R_OK) < 0)
+                        return -errno;
+
+                return 0;
+        }
+
+        fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+        if (st.st_size < 4)
+                return -ENODATA;
+        if (st.st_size > 4*1024*1024 + 4)
+                return -E2BIG;
+
+        if (ret_value || ret_attribute) {
+                n = read(fd, &a, sizeof(a));
+                if (n < 0)
+                        return -errno;
+                if (n != sizeof(a))
+                        return -EIO;
+        }
+
+        if (ret_value) {
+                buf = malloc(st.st_size - 4 + 2);
+                if (!buf)
+                        return -ENOMEM;
+
+                n = read(fd, buf, (size_t) st.st_size - 4);
+                if (n < 0)
+                        return -errno;
+                if (n != st.st_size - 4)
+                        return -EIO;
+
+                /* Always NUL terminate (2 bytes, to protect UTF-16) */
+                ((char*) buf)[st.st_size - 4] = 0;
+                ((char*) buf)[st.st_size - 4 + 1] = 0;
+        }
+
+        /* Note that efivarfs interestingly doesn't require ftruncate() to update an existing EFI variable
+         * with a smaller value. */
+
+        if (ret_attribute)
+                *ret_attribute = a;
+
+        if (ret_value)
+                *ret_value = TAKE_PTR(buf);
+
+        if (ret_size)
+                *ret_size = (size_t) st.st_size - 4;
+
+        return 0;
+}
+
+int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
+        _cleanup_free_ void *s = NULL;
+        size_t ss = 0;
+        int r;
+        char *x;
+
+        r = efi_get_variable(vendor, name, NULL, &s, &ss);
+        if (r < 0)
+                return r;
+
+        x = utf16_to_utf8(s, ss);
+        if (!x)
+                return -ENOMEM;
+
+        *p = x;
+        return 0;
+}
+
+int efi_set_variable(
+                sd_id128_t vendor,
+                const char *name,
+                const void *value,
+                size_t size) {
+
+        struct var {
+                uint32_t attr;
+                char buf[];
+        } _packed_ * _cleanup_free_ buf = NULL;
+        _cleanup_free_ char *p = NULL;
+        _cleanup_close_ int fd = -1;
+        bool saved_flags_valid = false;
+        unsigned saved_flags;
+        int r;
+
+        assert(name);
+        assert(value || size == 0);
+
+        p = efi_variable_path(vendor, name);
+        if (!p)
+                return -ENOMEM;
+
+        /* Newer efivarfs protects variables that are not in a whitelist with FS_IMMUTABLE_FL by default, to protect
+         * them for accidental removal and modification. We are not changing these variables accidentally however,
+         * hence let's unset the bit first. */
+
+        r = chattr_path(p, 0, FS_IMMUTABLE_FL, &saved_flags);
+        if (r < 0 && r != -ENOENT)
+                log_debug_errno(r, "Failed to drop FS_IMMUTABLE_FL flag from '%s', ignoring: %m", p);
+
+        saved_flags_valid = r >= 0;
+
+        if (size == 0) {
+                if (unlink(p) < 0) {
+                        r = -errno;
+                        goto finish;
+                }
+
+                return 0;
+        }
+
+        fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
+        if (fd < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        buf = malloc(sizeof(uint32_t) + size);
+        if (!buf) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+        memcpy(buf->buf, value, size);
+
+        r = loop_write(fd, buf, sizeof(uint32_t) + size, false);
+        if (r < 0)
+                goto finish;
+
+        r = 0;
+
+finish:
+        if (saved_flags_valid) {
+                int q;
+
+                /* Restore the original flags field, just in case */
+                if (fd < 0)
+                        q = chattr_path(p, saved_flags, FS_IMMUTABLE_FL, NULL);
+                else
+                        q = chattr_fd(fd, saved_flags, FS_IMMUTABLE_FL, NULL);
+                if (q < 0)
+                        log_debug_errno(q, "Failed to restore FS_IMMUTABLE_FL on '%s', ignoring: %m", p);
+        }
+
+        return r;
+}
+
+int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *v) {
+        _cleanup_free_ char16_t *u16 = NULL;
+
+        u16 = utf8_to_utf16(v, strlen(v));
+        if (!u16)
+                return -ENOMEM;
+
+        return efi_set_variable(vendor, name, u16, (char16_strlen(u16) + 1) * sizeof(char16_t));
+}
+
+int efi_systemd_options_variable(char **line) {
+        const char *e;
+        int r;
+
+        assert(line);
+
+        /* For testing purposes it is sometimes useful to be able to override this */
+        e = secure_getenv("SYSTEMD_EFI_OPTIONS");
+        if (e) {
+                char *m;
+
+                m = strdup(e);
+                if (!m)
+                        return -ENOMEM;
+
+                *line = m;
+                return 0;
+        }
+
+        r = efi_get_variable_string(EFI_VENDOR_SYSTEMD, "SystemdOptions", line);
+        if (r == -ENOENT)
+                return -ENODATA;
+
+        return r;
+}
+#endif
diff --git a/src/basic/efivars.h b/src/basic/efivars.h
new file mode 100644 (file)
index 0000000..22edbed
--- /dev/null
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if !ENABLE_EFI
+#  include <errno.h>
+#endif
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sd-id128.h"
+
+#include "efi/loader-features.h"
+#include "time-util.h"
+
+#define EFI_VENDOR_LOADER  SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
+#define EFI_VENDOR_GLOBAL  SD_ID128_MAKE(8b,e4,df,61,93,ca,11,d2,aa,0d,00,e0,98,03,2b,8c)
+#define EFI_VENDOR_SYSTEMD SD_ID128_MAKE(8c,f2,64,4b,4b,0b,42,8f,93,87,6d,87,60,50,dc,67)
+#define EFI_VARIABLE_NON_VOLATILE       0x0000000000000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
+#define EFI_VARIABLE_RUNTIME_ACCESS     0x0000000000000004
+
+#if ENABLE_EFI
+
+char* efi_variable_path(sd_id128_t vendor, const char *name);
+int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size);
+int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p);
+int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size);
+int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *p);
+
+int efi_systemd_options_variable(char **line);
+
+#else
+
+static inline char* efi_variable_path(sd_id128_t vendor, const char *name) {
+        return NULL;
+}
+
+static inline int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size) {
+        return -EOPNOTSUPP;
+}
+
+static inline int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
+        return -EOPNOTSUPP;
+}
+
+static inline int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size) {
+        return -EOPNOTSUPP;
+}
+
+static inline int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *p) {
+        return -EOPNOTSUPP;
+}
+
+static inline int efi_systemd_options_variable(char **line) {
+        return -ENODATA;
+}
+
+#endif
index 336cb3a099920de3bb32b3b95782ce73fa6f0aa8..18e5085669c0cb20421ff1ccc4bf0846040b7d4f 100644 (file)
@@ -307,17 +307,18 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
 
 extern void __coverity_panic__(void);
 
-static inline int __coverity_check__(int condition) {
+static inline void __coverity_check__(int condition) {
+        if (!condition)
+                __coverity_panic__();
+}
+
+static inline int __coverity_check_and_return__(int condition) {
         return condition;
 }
 
-#define assert_message_se(expr, message)                                \
-        do {                                                            \
-                if (__coverity_check__(!(expr)))                        \
-                        __coverity_panic__();                           \
-        } while (false)
+#define assert_message_se(expr, message) __coverity_check__(!!(expr))
 
-#define assert_log(expr, message) __coverity_check__(!!(expr))
+#define assert_log(expr, message) __coverity_check_and_return__(!!(expr))
 
 #else  /* ! __COVERITY__ */
 
index 9cb8ac3c10fcac861a76bd67262120d8eeaa804e..46a6907a0cf96baf6832e52080d75eee8144e573 100644 (file)
@@ -11,6 +11,7 @@
 
 size_t page_size(void) _pure_;
 #define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
+#define PAGE_ALIGN_DOWN(l) (l & ~(page_size() - 1))
 
 /* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
 static inline void memcpy_safe(void *dst, const void *src, size_t n) {
index d6caf28f144651e5abac0495567f3c110827b210..43ab1849f97a97855a4e84f0fe326dd5255a793b 100644 (file)
@@ -39,6 +39,8 @@ basic_sources = files('''
         device-nodes.h
         dirent-util.c
         dirent-util.h
+        efivars.c
+        efivars.h
         env-file.c
         env-file.h
         env-util.c
index cb8ddccecde63304d55f9bf4b8a040002651977b..74cf139aaf52de64ffcd5924ddf35659d1daa92f 100644 (file)
@@ -298,6 +298,7 @@ bool fstype_is_network(const char *fstype) {
         return STR_IN_SET(fstype,
                           "afs",
                           "cifs",
+                          "smb3",
                           "smbfs",
                           "sshfs",
                           "ncpfs",
index 18c7dabbae0bf7f741a7c580311d7eadf6a69af8..b9544b4bacce90cb906b29a743864ff98660a8d7 100644 (file)
@@ -651,7 +651,9 @@ int find_binary(const char *name, char **ret) {
                         return 0;
                 }
 
-                last_error = -errno;
+                /* PATH entries which we don't have access to are ignored, as per tradition. */
+                if (errno != EACCES)
+                        last_error = -errno;
         }
 
         return last_error;
index 09169cf96346f8563db98e9282aa9d819b9b9853..44d1e9aec40724af7d20514d71503d0982613f42 100644 (file)
@@ -5,6 +5,7 @@
 #include <string.h>
 
 #include "alloc-util.h"
+#include "efivars.h"
 #include "extract-word.h"
 #include "fileio.h"
 #include "macro.h"
@@ -117,6 +118,17 @@ int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, ProcCmdlineF
 
         assert(parse_item);
 
+        /* We parse the EFI variable first, because later settings have higher priority. */
+
+        r = efi_systemd_options_variable(&line);
+        if (r < 0 && r != -ENODATA)
+                log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m");
+
+        r = proc_cmdline_parse_given(line, parse_item, data, flags);
+        if (r < 0)
+                return r;
+
+        line = mfree(line);
         r = proc_cmdline(&line);
         if (r < 0)
                 return r;
@@ -156,34 +168,14 @@ bool proc_cmdline_key_streq(const char *x, const char *y) {
         return true;
 }
 
-int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_value) {
-        _cleanup_free_ char *line = NULL, *ret = NULL;
+static int cmdline_get_key(const char *line, const char *key, ProcCmdlineFlags flags, char **ret_value) {
+        _cleanup_free_ char *ret = NULL;
         bool found = false;
         const char *p;
         int r;
 
-        /* Looks for a specific key on the kernel command line. Supports three modes:
-         *
-         * a) The "ret_value" parameter is used. In this case a parameter beginning with the "key" string followed by
-         *    "=" is searched for, and the value following it is returned in "ret_value".
-         *
-         * b) as above, but the PROC_CMDLINE_VALUE_OPTIONAL flag is set. In this case if the key is found as a separate
-         *    word (i.e. not followed by "=" but instead by whitespace or the end of the command line), then this is
-         *    also accepted, and "value" is returned as NULL.
-         *
-         * c) The "ret_value" parameter is NULL. In this case a search for the exact "key" parameter is performed.
-         *
-         * In all three cases, > 0 is returned if the key is found, 0 if not. */
-
-        if (isempty(key))
-                return -EINVAL;
-
-        if (FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL) && !ret_value)
-                return -EINVAL;
-
-        r = proc_cmdline(&line);
-        if (r < 0)
-                return r;
+        assert(line);
+        assert(key);
 
         p = line;
         for (;;) {
@@ -226,6 +218,48 @@ int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_val
         return found;
 }
 
+int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_value) {
+        _cleanup_free_ char *line = NULL;
+        int r;
+
+        /* Looks for a specific key on the kernel command line and (with lower priority) the EFI variable.
+         * Supports three modes:
+         *
+         * a) The "ret_value" parameter is used. In this case a parameter beginning with the "key" string followed by
+         *    "=" is searched for, and the value following it is returned in "ret_value".
+         *
+         * b) as above, but the PROC_CMDLINE_VALUE_OPTIONAL flag is set. In this case if the key is found as a separate
+         *    word (i.e. not followed by "=" but instead by whitespace or the end of the command line), then this is
+         *    also accepted, and "value" is returned as NULL.
+         *
+         * c) The "ret_value" parameter is NULL. In this case a search for the exact "key" parameter is performed.
+         *
+         * In all three cases, > 0 is returned if the key is found, 0 if not. */
+
+        if (isempty(key))
+                return -EINVAL;
+
+        if (FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL) && !ret_value)
+                return -EINVAL;
+
+        r = proc_cmdline(&line);
+        if (r < 0)
+                return r;
+
+        r = cmdline_get_key(line, key, flags, ret_value);
+        if (r != 0) /* Either error or true if found. */
+                return r;
+
+        line = mfree(line);
+        r = efi_systemd_options_variable(&line);
+        if (r == -ENODATA)
+                return false; /* Not found */
+        if (r < 0)
+                return r;
+
+        return cmdline_get_key(line, key, flags, ret_value);
+}
+
 int proc_cmdline_get_bool(const char *key, bool *ret) {
         _cleanup_free_ char *v = NULL;
         int r;
@@ -306,58 +340,3 @@ int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...) {
 
         return ret;
 }
-
-int shall_restore_state(void) {
-        bool ret;
-        int r;
-
-        r = proc_cmdline_get_bool("systemd.restore_state", &ret);
-        if (r < 0)
-                return r;
-
-        return r > 0 ? ret : true;
-}
-
-static const char * const rlmap[] = {
-        "emergency", SPECIAL_EMERGENCY_TARGET,
-        "-b",        SPECIAL_EMERGENCY_TARGET,
-        "rescue",    SPECIAL_RESCUE_TARGET,
-        "single",    SPECIAL_RESCUE_TARGET,
-        "-s",        SPECIAL_RESCUE_TARGET,
-        "s",         SPECIAL_RESCUE_TARGET,
-        "S",         SPECIAL_RESCUE_TARGET,
-        "1",         SPECIAL_RESCUE_TARGET,
-        "2",         SPECIAL_MULTI_USER_TARGET,
-        "3",         SPECIAL_MULTI_USER_TARGET,
-        "4",         SPECIAL_MULTI_USER_TARGET,
-        "5",         SPECIAL_GRAPHICAL_TARGET,
-        NULL
-};
-
-static const char * const rlmap_initrd[] = {
-        "emergency", SPECIAL_EMERGENCY_TARGET,
-        "rescue",    SPECIAL_RESCUE_TARGET,
-        NULL
-};
-
-const char* runlevel_to_target(const char *word) {
-        const char * const *rlmap_ptr;
-        size_t i;
-
-        if (!word)
-                return NULL;
-
-        if (in_initrd()) {
-                word = startswith(word, "rd.");
-                if (!word)
-                        return NULL;
-        }
-
-        rlmap_ptr = in_initrd() ? rlmap_initrd : rlmap;
-
-        for (i = 0; rlmap_ptr[i]; i += 2)
-                if (streq(word, rlmap_ptr[i]))
-                        return rlmap_ptr[i+1];
-
-        return NULL;
-}
index ff04379fbd3fdefa1f480c72be68f7f13f45a22e..4115fdbc99fd7d00dbfc33b19681d16d54efcac6 100644 (file)
@@ -27,9 +27,6 @@ int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...);
 char *proc_cmdline_key_startswith(const char *s, const char *prefix);
 bool proc_cmdline_key_streq(const char *x, const char *y);
 
-int shall_restore_state(void);
-const char* runlevel_to_target(const char *rl);
-
 /* A little helper call, to be used in proc_cmdline_parse_t callbacks */
 static inline bool proc_cmdline_value_missing(const char *key, const char *value) {
         if (!value) {
index 76767afcac49a2e5ab89212f3a8b8fd81f1f2724..3981129db3180d7794ca99c62ad3a9ab638fcf29 100644 (file)
@@ -45,6 +45,22 @@ static inline const char *strna(const char *s) {
         return s ?: "n/a";
 }
 
+static inline const char* yes_no(bool b) {
+        return b ? "yes" : "no";
+}
+
+static inline const char* true_false(bool b) {
+        return b ? "true" : "false";
+}
+
+static inline const char* one_zero(bool b) {
+        return b ? "1" : "0";
+}
+
+static inline const char* enable_disable(bool b) {
+        return b ? "enable" : "disable";
+}
+
 static inline bool isempty(const char *p) {
         return !p || !p[0];
 }
index 93d610bc9890b629d6e5ac16be22f2e96f3ff71c..4989b8aa77584cc5762c66d3552ff062653fd378 100644 (file)
@@ -39,6 +39,7 @@
 #include "set.h"
 #include "signal-util.h"
 #include "stat-util.h"
+#include "static-destruct.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
 
 int saved_argc = 0;
 char **saved_argv = NULL;
+char **saved_env = NULL;
 static int saved_in_initrd = -1;
 
+STATIC_DESTRUCTOR_REGISTER(saved_env, strv_freep);
+
 bool kexec_loaded(void) {
        _cleanup_free_ char *s = NULL;
 
@@ -298,3 +302,7 @@ void disable_coredumps(void) {
         if (r < 0)
                 log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
 }
+
+void save_env(void) {
+        saved_env = strv_copy(environ);
+}
index 25e6ab81127d1049fac5d451ee9f658cfa285d01..15444b2e5c576c9d524cb2258521c1a460cc0201 100644 (file)
@@ -5,22 +5,6 @@
 
 #include "macro.h"
 
-static inline const char* yes_no(bool b) {
-        return b ? "yes" : "no";
-}
-
-static inline const char* true_false(bool b) {
-        return b ? "true" : "false";
-}
-
-static inline const char* one_zero(bool b) {
-        return b ? "1" : "0";
-}
-
-static inline const char* enable_disable(bool b) {
-        return b ? "enable" : "disable";
-}
-
 extern int saved_argc;
 extern char **saved_argv;
 
@@ -29,6 +13,9 @@ static inline void save_argc_argv(int argc, char **argv) {
         saved_argv = argv;
 }
 
+extern char **saved_env;
+void save_env(void);
+
 bool kexec_loaded(void);
 
 int prot_from_flags(int flags) _const_;
index e28cccd761137b2b1229305eba13ad4620f90c06..c59d8aed90ca528693ecd2d25630665a278467bc 100644 (file)
@@ -4,7 +4,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#include "efivars.h"
+#include "efi-loader.h"
 #include "generator.h"
 #include "log.h"
 #include "mkdir.h"
index f2d033fc407f624bbdfb7be438ad2466e79b898f..4747e7fb4f9ea354f8496720c9d68a36ecadba49 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "alloc-util.h"
 #include "bootspec.h"
+#include "efi-loader.h"
 #include "efivars.h"
 #include "fd-util.h"
 #include "fs-util.h"
index ddc267401f5431b5a3e293a4e6b9cb5b6f5ede4a..2c8163360fac47253e523bd2c6fe3e5c1754c7a1 100644 (file)
@@ -24,6 +24,7 @@
 #include "bootspec.h"
 #include "copy.h"
 #include "dirent-util.h"
+#include "efi-loader.h"
 #include "efivars.h"
 #include "env-util.h"
 #include "escape.h"
@@ -1051,8 +1052,9 @@ static int help(int argc, char *argv[], void *userdata) {
                "     install           Install systemd-boot to the ESP and EFI variables\n"
                "     update            Update systemd-boot in the ESP and EFI variables\n"
                "     remove            Remove systemd-boot from the ESP and EFI variables\n"
-               "     random-seed       Initialize random seed in ESP and EFI variables\n"
                "     is-installed      Test whether systemd-boot is installed in the ESP\n"
+               "     random-seed       Initialize random seed in ESP and EFI variables\n"
+               "     system-options    Query or set system options string in EFI variable\n"
                "\nBoot Loader Entries Commands:\n"
                "     list              List boot loader entries\n"
                "     set-default ID    Set default boot loader entry\n"
@@ -1709,18 +1711,40 @@ static int verb_random_seed(int argc, char *argv[], void *userdata) {
         return 0;
 }
 
+static int verb_system_options(int argc, char *argv[], void *userdata) {
+        int r;
+
+        if (argc == 1) {
+                _cleanup_free_ char *line = NULL;
+
+                r = efi_systemd_options_variable(&line);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to query SystemdOptions EFI variable: %m");
+
+                printf("SystemdOptions: %s\n", line);
+
+        } else {
+                r = efi_set_variable_string(EFI_VENDOR_SYSTEMD, "SystemdOptions", argv[1]);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to set SystemdOptions EFI variable: %m");
+        }
+
+        return 0;
+}
+
 static int bootctl_main(int argc, char *argv[]) {
         static const Verb verbs[] = {
-                { "help",         VERB_ANY, VERB_ANY, 0,            help              },
-                { "status",       VERB_ANY, 1,        VERB_DEFAULT, verb_status       },
-                { "install",      VERB_ANY, 1,        0,            verb_install      },
-                { "update",       VERB_ANY, 1,        0,            verb_install      },
-                { "remove",       VERB_ANY, 1,        0,            verb_remove       },
-                { "random-seed",  VERB_ANY, 1,        0,            verb_random_seed  },
-                { "is-installed", VERB_ANY, 1,        0,            verb_is_installed },
-                { "list",         VERB_ANY, 1,        0,            verb_list         },
-                { "set-default",  2,        2,        0,            verb_set_default  },
-                { "set-oneshot",  2,        2,        0,            verb_set_default  },
+                { "help",           VERB_ANY, VERB_ANY, 0,            help                },
+                { "status",         VERB_ANY, 1,        VERB_DEFAULT, verb_status         },
+                { "install",        VERB_ANY, 1,        0,            verb_install        },
+                { "update",         VERB_ANY, 1,        0,            verb_install        },
+                { "remove",         VERB_ANY, 1,        0,            verb_remove         },
+                { "is-installed",   VERB_ANY, 1,        0,            verb_is_installed   },
+                { "list",           VERB_ANY, 1,        0,            verb_list           },
+                { "set-default",    2,        2,        0,            verb_set_default    },
+                { "set-oneshot",    2,        2,        0,            verb_set_default    },
+                { "random-seed",    VERB_ANY, 1,        0,            verb_random_seed    },
+                { "system-options", VERB_ANY, 2,        0,            verb_system_options },
                 {}
         };
 
index bcdd7e19a99cfd5ced290e0a720138b4bc9674da..a54e56c3122ea52344a77673aaf9bd9705cb7d90 100644 (file)
@@ -568,7 +568,7 @@ static void automount_enter_waiting(Automount *a) {
         if (r < 0)
                 goto fail;
 
-        (void) mkdir_p_label(a->where, 0555);
+        (void) mkdir_p_label(a->where, a->directory_mode);
 
         unit_warn_if_dir_nonempty(UNIT(a), a->where);
 
index 423742969e59d94b72611dcdc5817b582f93c140..c67ecc37c53a08999065fa629f2e1e29ce8e3e02 100644 (file)
@@ -11,6 +11,7 @@
 #include "bpf-firewall.h"
 #include "btrfs-util.h"
 #include "bus-error.h"
+#include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "cgroup.h"
 #include "fd-util.h"
@@ -207,7 +208,158 @@ void cgroup_context_done(CGroupContext *c) {
         cpu_set_reset(&c->cpuset_mems);
 }
 
-void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
+static int unit_get_kernel_memory_limit(Unit *u, const char *file, uint64_t *ret) {
+        _cleanup_free_ char *raw_kval = NULL;
+        uint64_t kval;
+        int r;
+
+        assert(u);
+
+        if (!u->cgroup_realized)
+                return -EOWNERDEAD;
+
+        r = cg_get_attribute("memory", u->cgroup_path, file, &raw_kval);
+        if (r < 0)
+                return r;
+
+        if (streq(raw_kval, "max")) {
+                *ret = CGROUP_LIMIT_MAX;
+                return 0;
+        }
+
+        r = safe_atou64(raw_kval, &kval);
+        if (r < 0)
+                return r;
+
+        *ret = kval;
+
+        return 0;
+}
+
+static int unit_compare_memory_limit(Unit *u, const char *property_name, uint64_t *ret_unit_value, uint64_t *ret_kernel_value) {
+        CGroupContext *c;
+        CGroupMask m;
+        const char *file;
+        uint64_t unit_value;
+        int r;
+
+        /* Compare kernel memcg configuration against our internal systemd state. Unsupported (and will
+         * return -ENODATA) on cgroup v1.
+         *
+         * Returns:
+         *
+         * <0: On error.
+         *  0: If the kernel memory setting doesn't match our configuration.
+         * >0: If the kernel memory setting matches our configuration.
+         *
+         * The following values are only guaranteed to be populated on return >=0:
+         *
+         * - ret_unit_value will contain our internal expected value for the unit, page-aligned.
+         * - ret_kernel_value will contain the actual value presented by the kernel. */
+
+        assert(u);
+
+        r = cg_all_unified();
+        if (r < 0)
+                return log_debug_errno(r, "Failed to determine cgroup hierarchy version: %m");
+
+        /* Unsupported on v1.
+         *
+         * We don't return ENOENT, since that could actually mask a genuine problem where somebody else has
+         * silently masked the controller. */
+        if (r == 0)
+                return -ENODATA;
+
+        /* The root slice doesn't have any controller files, so we can't compare anything. */
+        if (unit_has_name(u, SPECIAL_ROOT_SLICE))
+                return -ENODATA;
+
+        /* It's possible to have MemoryFoo set without systemd wanting to have the memory controller enabled,
+         * for example, in the case of DisableControllers= or cgroup_disable on the kernel command line. To
+         * avoid specious errors in these scenarios, check that we even expect the memory controller to be
+         * enabled at all. */
+        m = unit_get_target_mask(u);
+        if (!FLAGS_SET(m, CGROUP_MASK_MEMORY))
+                return -ENODATA;
+
+        c = unit_get_cgroup_context(u);
+        assert(c);
+
+        if (streq(property_name, "MemoryLow")) {
+                unit_value = unit_get_ancestor_memory_low(u);
+                file = "memory.low";
+        } else if (streq(property_name, "MemoryMin")) {
+                unit_value = unit_get_ancestor_memory_min(u);
+                file = "memory.min";
+        } else if (streq(property_name, "MemoryHigh")) {
+                unit_value = c->memory_high;
+                file = "memory.high";
+        } else if (streq(property_name, "MemoryMax")) {
+                unit_value = c->memory_max;
+                file = "memory.max";
+        } else if (streq(property_name, "MemorySwapMax")) {
+                unit_value = c->memory_swap_max;
+                file = "memory.swap.max";
+        } else
+                return -EINVAL;
+
+        r = unit_get_kernel_memory_limit(u, file, ret_kernel_value);
+        if (r < 0)
+                return log_unit_debug_errno(u, r, "Failed to parse %s: %m", file);
+
+        /* It's intended (soon) in a future kernel to not expose cgroup memory limits rounded to page
+         * boundaries, but instead separate the user-exposed limit, which is whatever userspace told us, from
+         * our internal page-counting. To support those future kernels, just check the value itself first
+         * without any page-alignment. */
+        if (*ret_kernel_value == unit_value) {
+                *ret_unit_value = unit_value;
+                return 1;
+        }
+
+        /* The current kernel behaviour, by comparison, is that even if you write a particular number of
+         * bytes into a cgroup memory file, it always returns that number page-aligned down (since the kernel
+         * internally stores cgroup limits in pages). As such, so long as it aligns properly, everything is
+         * cricket. */
+        if (unit_value != CGROUP_LIMIT_MAX)
+                unit_value = PAGE_ALIGN_DOWN(unit_value);
+
+        *ret_unit_value = unit_value;
+
+        return *ret_kernel_value == *ret_unit_value;
+}
+
+#define FORMAT_CGROUP_DIFF_MAX 128
+
+static char *format_cgroup_memory_limit_comparison(char *buf, size_t l, Unit *u, const char *property_name) {
+        uint64_t kval, sval;
+        int r;
+
+        assert(u);
+        assert(buf);
+        assert(l > 0);
+
+        r = unit_compare_memory_limit(u, property_name, &sval, &kval);
+
+        /* memory.swap.max is special in that it relies on CONFIG_MEMCG_SWAP (and the default swapaccount=1).
+         * In the absence of reliably being able to detect whether memcg swap support is available or not,
+         * only complain if the error is not ENOENT. */
+        if (r > 0 || IN_SET(r, -ENODATA, -EOWNERDEAD) ||
+            (r == -ENOENT && streq(property_name, "MemorySwapMax"))) {
+                buf[0] = 0;
+                return buf;
+        }
+
+        if (r < 0) {
+                snprintf(buf, l, " (error getting kernel value: %s)", strerror_safe(r));
+                return buf;
+        }
+
+        snprintf(buf, l, " (different value in kernel: %" PRIu64 ")", kval);
+
+        return buf;
+}
+
+void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
         _cleanup_free_ char *disable_controllers_str = NULL;
         _cleanup_free_ char *cpuset_cpus = NULL;
         _cleanup_free_ char *cpuset_mems = NULL;
@@ -217,14 +369,24 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
         CGroupBlockIODeviceBandwidth *b;
         CGroupBlockIODeviceWeight *w;
         CGroupDeviceAllow *a;
+        CGroupContext *c;
         IPAddressAccessItem *iaai;
         char **path;
-        char u[FORMAT_TIMESPAN_MAX];
+        char q[FORMAT_TIMESPAN_MAX];
         char v[FORMAT_TIMESPAN_MAX];
 
-        assert(c);
+        char cda[FORMAT_CGROUP_DIFF_MAX];
+        char cdb[FORMAT_CGROUP_DIFF_MAX];
+        char cdc[FORMAT_CGROUP_DIFF_MAX];
+        char cdd[FORMAT_CGROUP_DIFF_MAX];
+        char cde[FORMAT_CGROUP_DIFF_MAX];
+
+        assert(u);
         assert(f);
 
+        c = unit_get_cgroup_context(u);
+        assert(c);
+
         prefix = strempty(prefix);
 
         (void) cg_mask_to_string(c->disable_controllers, &disable_controllers_str);
@@ -233,36 +395,36 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
         cpuset_mems = cpu_set_to_range_string(&c->cpuset_mems);
 
         fprintf(f,
-                "%sCPUAccounting=%s\n"
-                "%sIOAccounting=%s\n"
-                "%sBlockIOAccounting=%s\n"
-                "%sMemoryAccounting=%s\n"
-                "%sTasksAccounting=%s\n"
-                "%sIPAccounting=%s\n"
-                "%sCPUWeight=%" PRIu64 "\n"
-                "%sStartupCPUWeight=%" PRIu64 "\n"
-                "%sCPUShares=%" PRIu64 "\n"
-                "%sStartupCPUShares=%" PRIu64 "\n"
-                "%sCPUQuotaPerSecSec=%s\n"
-                "%sCPUQuotaPeriodSec=%s\n"
-                "%sAllowedCPUs=%s\n"
-                "%sAllowedMemoryNodes=%s\n"
-                "%sIOWeight=%" PRIu64 "\n"
-                "%sStartupIOWeight=%" PRIu64 "\n"
-                "%sBlockIOWeight=%" PRIu64 "\n"
-                "%sStartupBlockIOWeight=%" PRIu64 "\n"
-                "%sDefaultMemoryMin=%" PRIu64 "\n"
-                "%sDefaultMemoryLow=%" PRIu64 "\n"
-                "%sMemoryMin=%" PRIu64 "\n"
-                "%sMemoryLow=%" PRIu64 "\n"
-                "%sMemoryHigh=%" PRIu64 "\n"
-                "%sMemoryMax=%" PRIu64 "\n"
-                "%sMemorySwapMax=%" PRIu64 "\n"
-                "%sMemoryLimit=%" PRIu64 "\n"
-                "%sTasksMax=%" PRIu64 "\n"
-                "%sDevicePolicy=%s\n"
-                "%sDisableControllers=%s\n"
-                "%sDelegate=%s\n",
+                "%sCPUAccounting%s\n"
+                "%sIOAccounting%s\n"
+                "%sBlockIOAccounting%s\n"
+                "%sMemoryAccounting%s\n"
+                "%sTasksAccounting%s\n"
+                "%sIPAccounting%s\n"
+                "%sCPUWeight%" PRIu64 "\n"
+                "%sStartupCPUWeight%" PRIu64 "\n"
+                "%sCPUShares%" PRIu64 "\n"
+                "%sStartupCPUShares%" PRIu64 "\n"
+                "%sCPUQuotaPerSecSec%s\n"
+                "%sCPUQuotaPeriodSec%s\n"
+                "%sAllowedCPUs%s\n"
+                "%sAllowedMemoryNodes%s\n"
+                "%sIOWeight%" PRIu64 "\n"
+                "%sStartupIOWeight%" PRIu64 "\n"
+                "%sBlockIOWeight%" PRIu64 "\n"
+                "%sStartupBlockIOWeight%" PRIu64 "\n"
+                "%sDefaultMemoryMin%" PRIu64 "\n"
+                "%sDefaultMemoryLow%" PRIu64 "\n"
+                "%sMemoryMin: %" PRIu64 "%s\n"
+                "%sMemoryLow: %" PRIu64 "%s\n"
+                "%sMemoryHigh: %" PRIu64 "%s\n"
+                "%sMemoryMax: %" PRIu64 "%s\n"
+                "%sMemorySwapMax: %" PRIu64 "%s\n"
+                "%sMemoryLimit%" PRIu64 "\n"
+                "%sTasksMax%" PRIu64 "\n"
+                "%sDevicePolicy%s\n"
+                "%sDisableControllers%s\n"
+                "%sDelegate%s\n",
                 prefix, yes_no(c->cpu_accounting),
                 prefix, yes_no(c->io_accounting),
                 prefix, yes_no(c->blockio_accounting),
@@ -273,7 +435,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 prefix, c->startup_cpu_weight,
                 prefix, c->cpu_shares,
                 prefix, c->startup_cpu_shares,
-                prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
+                prefix, format_timespan(q, sizeof(q), c->cpu_quota_per_sec_usec, 1),
                 prefix, format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1),
                 prefix, cpuset_cpus,
                 prefix, cpuset_mems,
@@ -283,11 +445,11 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 prefix, c->startup_blockio_weight,
                 prefix, c->default_memory_min,
                 prefix, c->default_memory_low,
-                prefix, c->memory_min,
-                prefix, c->memory_low,
-                prefix, c->memory_high,
-                prefix, c->memory_max,
-                prefix, c->memory_swap_max,
+                prefix, c->memory_min, format_cgroup_memory_limit_comparison(cda, sizeof(cda), u, "MemoryMin"),
+                prefix, c->memory_low, format_cgroup_memory_limit_comparison(cdb, sizeof(cdb), u, "MemoryLow"),
+                prefix, c->memory_high, format_cgroup_memory_limit_comparison(cdc, sizeof(cdc), u, "MemoryHigh"),
+                prefix, c->memory_max, format_cgroup_memory_limit_comparison(cdd, sizeof(cdd), u, "MemoryMax"),
+                prefix, c->memory_swap_max, format_cgroup_memory_limit_comparison(cde, sizeof(cde), u, "MemorySwapMax"),
                 prefix, c->memory_limit,
                 prefix, c->tasks_max,
                 prefix, cgroup_device_policy_to_string(c->device_policy),
@@ -299,31 +461,31 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
 
                 (void) cg_mask_to_string(c->delegate_controllers, &t);
 
-                fprintf(f, "%sDelegateControllers=%s\n",
+                fprintf(f, "%sDelegateControllers%s\n",
                         prefix,
                         strempty(t));
         }
 
         LIST_FOREACH(device_allow, a, c->device_allow)
                 fprintf(f,
-                        "%sDeviceAllow=%s %s%s%s\n",
+                        "%sDeviceAllow%s %s%s%s\n",
                         prefix,
                         a->path,
                         a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
 
         LIST_FOREACH(device_weights, iw, c->io_device_weights)
                 fprintf(f,
-                        "%sIODeviceWeight=%s %" PRIu64 "\n",
+                        "%sIODeviceWeight%s %" PRIu64 "\n",
                         prefix,
                         iw->path,
                         iw->weight);
 
         LIST_FOREACH(device_latencies, l, c->io_device_latencies)
                 fprintf(f,
-                        "%sIODeviceLatencyTargetSec=%s %s\n",
+                        "%sIODeviceLatencyTargetSec%s %s\n",
                         prefix,
                         l->path,
-                        format_timespan(u, sizeof(u), l->target_usec, 1));
+                        format_timespan(q, sizeof(q), l->target_usec, 1));
 
         LIST_FOREACH(device_limits, il, c->io_device_limits) {
                 char buf[FORMAT_BYTES_MAX];
@@ -332,7 +494,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
                         if (il->limits[type] != cgroup_io_limit_defaults[type])
                                 fprintf(f,
-                                        "%s%s=%s %s\n",
+                                        "%s%s%s %s\n",
                                         prefix,
                                         cgroup_io_limit_type_to_string(type),
                                         il->path,
@@ -341,7 +503,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
 
         LIST_FOREACH(device_weights, w, c->blockio_device_weights)
                 fprintf(f,
-                        "%sBlockIODeviceWeight=%s %" PRIu64,
+                        "%sBlockIODeviceWeight%s %" PRIu64,
                         prefix,
                         w->path,
                         w->weight);
@@ -351,13 +513,13 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
 
                 if (b->rbps != CGROUP_LIMIT_MAX)
                         fprintf(f,
-                                "%sBlockIOReadBandwidth=%s %s\n",
+                                "%sBlockIOReadBandwidth%s %s\n",
                                 prefix,
                                 b->path,
                                 format_bytes(buf, sizeof(buf), b->rbps));
                 if (b->wbps != CGROUP_LIMIT_MAX)
                         fprintf(f,
-                                "%sBlockIOWriteBandwidth=%s %s\n",
+                                "%sBlockIOWriteBandwidth%s %s\n",
                                 prefix,
                                 b->path,
                                 format_bytes(buf, sizeof(buf), b->wbps));
@@ -367,21 +529,21 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 _cleanup_free_ char *k = NULL;
 
                 (void) in_addr_to_string(iaai->family, &iaai->address, &k);
-                fprintf(f, "%sIPAddressAllow=%s/%u\n", prefix, strnull(k), iaai->prefixlen);
+                fprintf(f, "%sIPAddressAllow%s/%u\n", prefix, strnull(k), iaai->prefixlen);
         }
 
         LIST_FOREACH(items, iaai, c->ip_address_deny) {
                 _cleanup_free_ char *k = NULL;
 
                 (void) in_addr_to_string(iaai->family, &iaai->address, &k);
-                fprintf(f, "%sIPAddressDeny=%s/%u\n", prefix, strnull(k), iaai->prefixlen);
+                fprintf(f, "%sIPAddressDeny%s/%u\n", prefix, strnull(k), iaai->prefixlen);
         }
 
         STRV_FOREACH(path, c->ip_filters_ingress)
-                fprintf(f, "%sIPIngressFilterPath=%s\n", prefix, *path);
+                fprintf(f, "%sIPIngressFilterPath%s\n", prefix, *path);
 
         STRV_FOREACH(path, c->ip_filters_egress)
-                fprintf(f, "%sIPEgressFilterPath=%s\n", prefix, *path);
+                fprintf(f, "%sIPEgressFilterPath%s\n", prefix, *path);
 }
 
 int cgroup_add_device_allow(CGroupContext *c, const char *dev, const char *mode) {
@@ -955,7 +1117,7 @@ static bool unit_has_unified_memory_config(Unit *u) {
         c = unit_get_cgroup_context(u);
         assert(c);
 
-        return c->memory_min > 0 || unit_get_ancestor_memory_low(u) > 0 ||
+        return unit_get_ancestor_memory_min(u) > 0 || unit_get_ancestor_memory_low(u) > 0 ||
                c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX ||
                c->memory_swap_max != CGROUP_LIMIT_MAX;
 }
@@ -1227,7 +1389,7 @@ static void cgroup_context_apply(
                                         log_cgroup_compat(u, "Applying MemoryLimit=%" PRIu64 " as MemoryMax=", max);
                         }
 
-                        cgroup_apply_unified_memory_limit(u, "memory.min", c->memory_min);
+                        cgroup_apply_unified_memory_limit(u, "memory.min", unit_get_ancestor_memory_min(u));
                         cgroup_apply_unified_memory_limit(u, "memory.low", unit_get_ancestor_memory_low(u));
                         cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high);
                         cgroup_apply_unified_memory_limit(u, "memory.max", max);
@@ -2869,7 +3031,7 @@ int manager_setup_cgroup(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Cannot find cgroup mount point: %m");
 
-        r = cg_unified_flush();
+        r = cg_unified();
         if (r < 0)
                 return log_error_errno(r, "Couldn't determine if we are running in the unified hierarchy: %m");
 
index bca53fb9809b63d495e88f38d74d57226f1eaee8..a66c70212562d6dcf053d4efac6690963c6b879d 100644 (file)
@@ -166,7 +166,7 @@ usec_t cgroup_cpu_adjust_period(usec_t period, usec_t quota, usec_t resolution,
 
 void cgroup_context_init(CGroupContext *c);
 void cgroup_context_done(CGroupContext *c);
-void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix);
+void cgroup_context_dump(Unit *u, FILE* f, const char *prefix);
 
 void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a);
 void cgroup_context_free_io_device_weight(CGroupContext *c, CGroupIODeviceWeight *w);
index bd0e73befc0cb58b17b5f2b70c1e0b6f413e18c9..b30318b943f857fd2c7e76e3cf6fbbc1a6f379f7 100644 (file)
@@ -554,7 +554,7 @@ static int bus_cgroup_set_transient_property(
                                         static bool warned = false;
 
                                         log_full(warned ? LOG_DEBUG : LOG_WARNING,
-                                                 "Transient unit %s configures an IP firewall with BPF, but the local system does not support BPF/cgroup firewalling with mulitiple filters.\n"
+                                                 "Transient unit %s configures an IP firewall with BPF, but the local system does not support BPF/cgroup firewalling with multiple filters.\n"
                                                  "Starting this unit will fail! (This warning is only shown for the first started transient unit using IP firewalling.)", u->id);
                                         warned = true;
                                 }
@@ -772,17 +772,33 @@ int bus_cgroup_set_property(
         if (streq(name, "MemoryAccounting"))
                 return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, error);
 
-        if (streq(name, "MemoryMin"))
-                return bus_cgroup_set_memory_protection(u, name, &c->memory_min, message, flags, error);
+        if (streq(name, "MemoryMin")) {
+                r = bus_cgroup_set_memory_protection(u, name, &c->memory_min, message, flags, error);
+                if (r > 0)
+                        c->memory_min_set = true;
+                return r;
+        }
 
-        if (streq(name, "MemoryLow"))
-                return bus_cgroup_set_memory_protection(u, name, &c->memory_low, message, flags, error);
+        if (streq(name, "MemoryLow")) {
+                r = bus_cgroup_set_memory_protection(u, name, &c->memory_low, message, flags, error);
+                if (r > 0)
+                        c->memory_low_set = true;
+                return r;
+        }
 
-        if (streq(name, "DefaultMemoryMin"))
-                return bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, message, flags, error);
+        if (streq(name, "DefaultMemoryMin")) {
+                r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, message, flags, error);
+                if (r > 0)
+                        c->default_memory_min_set = true;
+                return r;
+        }
 
-        if (streq(name, "DefaultMemoryLow"))
-                return bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, message, flags, error);
+        if (streq(name, "DefaultMemoryLow")) {
+                r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, message, flags, error);
+                if (r > 0)
+                        c->default_memory_low_set = true;
+                return r;
+        }
 
         if (streq(name, "MemoryHigh"))
                 return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, error);
@@ -796,17 +812,33 @@ int bus_cgroup_set_property(
         if (streq(name, "MemoryLimit"))
                 return bus_cgroup_set_memory(u, name, &c->memory_limit, message, flags, error);
 
-        if (streq(name, "MemoryMinScale"))
-                return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, error);
+        if (streq(name, "MemoryMinScale")) {
+                r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, error);
+                if (r > 0)
+                        c->memory_min_set = true;
+                return r;
+        }
 
-        if (streq(name, "MemoryLowScale"))
-                return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, message, flags, error);
+        if (streq(name, "MemoryLowScale")) {
+                r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, message, flags, error);
+                if (r > 0)
+                        c->memory_low_set = true;
+                return r;
+        }
 
-        if (streq(name, "DefaultMemoryMinScale"))
-                return bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, message, flags, error);
+        if (streq(name, "DefaultMemoryMinScale")) {
+                r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, message, flags, error);
+                if (r > 0)
+                        c->default_memory_min_set = true;
+                return r;
+        }
 
-        if (streq(name, "DefaultMemoryLowScale"))
-                return bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, message, flags, error);
+        if (streq(name, "DefaultMemoryLowScale")) {
+                r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, message, flags, error);
+                if (r > 0)
+                        c->default_memory_low_set = true;
+                return r;
+        }
 
         if (streq(name, "MemoryHighScale"))
                 return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, error);
index c9f6fc718719861cd6e8fae308843fcb17fc1003..380e117fca9141418c1ee14cd4f1f352a5a38ede 100644 (file)
@@ -4,7 +4,7 @@
 #include "sd-bus.h"
 #include "sd-bus-vtable.h"
 
-#include "job.h"
+#include "unit.h"
 
 extern const sd_bus_vtable bus_job_vtable[];
 
index e2b3a0d51750a5e233f3e2472e47f54013a1f445..30597e86f0d1dabb6c2087fb2dfa29deafd8463d 100644 (file)
@@ -8,10 +8,28 @@
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode);
 
+static int property_get_restart_kill_signal(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+        KillContext *c = userdata;
+        int s;
+
+        assert(c);
+
+        s = restart_kill_signal(c);
+        return sd_bus_message_append_basic(reply, 'i', &s);
+}
+
 const sd_bus_vtable bus_kill_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("KillMode", "s", property_get_kill_mode, offsetof(KillContext, kill_mode), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("KillSignal", "i", bus_property_get_int, offsetof(KillContext, kill_signal), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RestartKillSignal", "i", property_get_restart_kill_signal, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         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),
@@ -21,6 +39,7 @@ const sd_bus_vtable bus_kill_vtable[] = {
 
 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(restart_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);
 
@@ -51,6 +70,9 @@ int bus_kill_context_set_transient_property(
         if (streq(name, "KillSignal"))
                 return bus_set_transient_kill_signal(u, name, &c->kill_signal, message, flags, error);
 
+        if (streq(name, "RestartKillSignal"))
+                return bus_set_transient_restart_kill_signal(u, name, &c->restart_kill_signal, message, flags, error);
+
         if (streq(name, "FinalKillSignal"))
                 return bus_set_transient_final_kill_signal(u, name, &c->final_kill_signal, message, flags, error);
 
index 24abf3c088e9226f2bdb9a37abc5b9bc29bb2292..91711311a7836b9f7aae865dd7a798a41b3c0569 100644 (file)
@@ -4,7 +4,6 @@
 #include "sd-bus.h"
 #include "sd-bus-vtable.h"
 
-#include "job.h"
 #include "unit.h"
 
 extern const sd_bus_vtable bus_unit_vtable[];
index ec95ce3d1049a613913cae6a2737e335b647df99..82e7428c3c94632da08102f427a84317e9de8f93 100644 (file)
@@ -48,6 +48,7 @@
 #include "cap-list.h"
 #include "capability-util.h"
 #include "chown-recursive.h"
+#include "cgroup-setup.h"
 #include "cpu-set-util.h"
 #include "def.h"
 #include "env-file.h"
@@ -1621,7 +1622,7 @@ static void do_idle_pipe_dance(int idle_pipe[static 4]) {
                         n = write(idle_pipe[3], "x", 1);
                         if (n > 0)
                                 /* Wait for systemd to react to the signal above. */
-                                fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
+                                (void) fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
                 }
 
                 idle_pipe[0] = safe_close(idle_pipe[0]);
index 6fe96cfc07c0f2018989b07e742eb02d0d6cf954..a9f468e29efaee3ff2a0e2cc3ee86b0c3485fa56 100644 (file)
@@ -9,6 +9,7 @@ void kill_context_init(KillContext *c) {
         assert(c);
 
         c->kill_signal = SIGTERM;
+        /* restart_kill_signal is unset by default and we fall back to kill_signal */
         c->final_kill_signal = SIGKILL;
         c->send_sigkill = true;
         c->send_sighup = false;
@@ -23,11 +24,13 @@ void kill_context_dump(KillContext *c, FILE *f, const char *prefix) {
         fprintf(f,
                 "%sKillMode: %s\n"
                 "%sKillSignal: SIG%s\n"
+                "%sRestartKillSignal: SIG%s\n"
                 "%sFinalKillSignal: SIG%s\n"
                 "%sSendSIGKILL: %s\n"
-                "%sSendSIGHUP:  %s\n",
+                "%sSendSIGHUP: %s\n",
                 prefix, kill_mode_to_string(c->kill_mode),
                 prefix, signal_to_string(c->kill_signal),
+                prefix, signal_to_string(restart_kill_signal(c)),
                 prefix, signal_to_string(c->final_kill_signal),
                 prefix, yes_no(c->send_sigkill),
                 prefix, yes_no(c->send_sighup));
@@ -35,20 +38,20 @@ void kill_context_dump(KillContext *c, FILE *f, const char *prefix) {
 
 static const char* const kill_mode_table[_KILL_MODE_MAX] = {
         [KILL_CONTROL_GROUP] = "control-group",
-        [KILL_PROCESS] = "process",
-        [KILL_MIXED] = "mixed",
-        [KILL_NONE] = "none"
+        [KILL_PROCESS]       = "process",
+        [KILL_MIXED]         = "mixed",
+        [KILL_NONE]          = "none",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
 
 static const char* const kill_who_table[_KILL_WHO_MAX] = {
-        [KILL_MAIN] = "main",
-        [KILL_CONTROL] = "control",
-        [KILL_ALL] = "all",
-        [KILL_MAIN_FAIL] = "main-fail",
+        [KILL_MAIN]         = "main",
+        [KILL_CONTROL]      = "control",
+        [KILL_ALL]          = "all",
+        [KILL_MAIN_FAIL]    = "main-fail",
         [KILL_CONTROL_FAIL] = "control-fail",
-        [KILL_ALL_FAIL] = "all-fail"
+        [KILL_ALL_FAIL]     = "all-fail",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
index 43648b6d8a2177c5016906839d52da8a31f56adb..1deb0aff9b6ed41fb07ba87ee37517ea4152b18d 100644 (file)
@@ -21,6 +21,7 @@ typedef enum KillMode {
 struct KillContext {
         KillMode kill_mode;
         int kill_signal;
+        int restart_kill_signal;
         int final_kill_signal;
         int watchdog_signal;
         bool send_sigkill;
@@ -47,3 +48,9 @@ KillMode kill_mode_from_string(const char *s) _pure_;
 
 const char *kill_who_to_string(KillWho k) _const_;
 KillWho kill_who_from_string(const char *s) _pure_;
+
+static inline int restart_kill_signal(const KillContext *c) {
+        if (c->restart_kill_signal != 0)
+                return c->restart_kill_signal;
+        return c->kill_signal;
+}
index 62dff99d86b607ca26a8c5ec2cffdb054709c9ac..d057c0d18b67b4d93ede581e0074cd952c9460fd 100644 (file)
@@ -161,6 +161,7 @@ m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
 $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.RestartKillSignal,            config_parse_signal,                0,                             offsetof($1, kill_context.restart_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
index 5fdead22f9d82b88546d8f01b61b211dc23594a9..72eb13cc006cf82b7f1f9bf295a05ef253460406 100644 (file)
@@ -24,7 +24,7 @@
 #include "bus-util.h"
 #include "cap-list.h"
 #include "capability-util.h"
-#include "cgroup.h"
+#include "cgroup-setup.h"
 #include "conf-parser.h"
 #include "cpu-set-util.h"
 #include "env-util.h"
index e29d58f7062f3ed05bf4872219af2ec69125451d..f369c4dc4f6eb095d24414a808bea34ac35bb82d 100644 (file)
@@ -43,8 +43,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
 CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
-CONFIG_PARSER_PROTOTYPE(config_parse_kill_signal);
-CONFIG_PARSER_PROTOTYPE(config_parse_final_kill_signal);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
 CONFIG_PARSER_PROTOTYPE(config_parse_timer);
 CONFIG_PARSER_PROTOTYPE(config_parse_trigger_unit);
index 2e95edfbd8691648dadad93677acc00d0c0eaa09..b3a665b119644da38cd4cc0056af347287609f84 100644 (file)
@@ -1648,7 +1648,7 @@ static void do_reexecute(
 
         if (switch_root_init) {
                 args[0] = switch_root_init;
-                (void) execv(args[0], (char* const*) args);
+                (void) execve(args[0], (char* const*) args, saved_env);
                 log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m");
         }
 
@@ -1665,7 +1665,7 @@ static void do_reexecute(
 
                 args[0] = "/bin/sh";
                 args[1] = NULL;
-                (void) execv(args[0], (char* const*) args);
+                (void) execve(args[0], (char* const*) args, saved_env);
                 log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
         } else
                 log_warning_errno(r, "Failed to execute /sbin/init, giving up: %m");
@@ -2133,7 +2133,7 @@ static void reset_arguments(void) {
         arg_default_blockio_accounting = false;
         arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT;
         arg_default_tasks_accounting = true;
-        arg_default_tasks_max = UINT64_MAX;
+        arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U);
         arg_machine_id = (sd_id128_t) {};
         arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
         arg_default_oom_policy = OOM_STOP;
@@ -2149,8 +2149,6 @@ static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
         assert(saved_rlimit_nofile);
         assert(saved_rlimit_memlock);
 
-        arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U);
-
         /* Assign configuration defaults */
         reset_arguments();
 
@@ -2394,6 +2392,10 @@ int main(int argc, char *argv[]) {
         /* Save the original command line */
         save_argc_argv(argc, argv);
 
+        /* Save the original environment as we might need to restore it if we're requested to
+         * execute another system manager later. */
+        save_env();
+
         /* Make sure that if the user says "syslog" we actually log to the journal. */
         log_set_upgrade_syslog_to_journal(true);
 
index 9d9263e8faf602cf38df897cf98bf654a4474305..f05445e4fb452a9a7291622420b1f1efd09d0dcb 100644 (file)
 #include "bus-util.h"
 #include "cgroup-util.h"
 #include "conf-files.h"
+#include "cgroup-setup.h"
 #include "dev-setup.h"
-#include "efivars.h"
+#include "dirent-util.h"
+#include "efi-loader.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
index fb3467c3503c42f264f28a5ca1ba0488d94a547a..09d08f3990fd5523fa469534c6d44ef70eba320e 100644 (file)
@@ -769,7 +769,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
 
         exec_context_dump(&m->exec_context, f, prefix);
         kill_context_dump(&m->kill_context, f, prefix);
-        cgroup_context_dump(&m->cgroup_context, f, prefix);
+        cgroup_context_dump(UNIT(m), f, prefix);
 }
 
 static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
@@ -866,6 +866,8 @@ static int state_to_kill_operation(MountState state) {
         switch (state) {
 
         case MOUNT_REMOUNTING_SIGTERM:
+                return KILL_RESTART;
+
         case MOUNT_UNMOUNTING_SIGTERM:
                 return KILL_TERMINATE;
 
index bb1e60dd11fa56ab4b589f01ab43afbeb6b5931d..79470a0a9beb89afe31cde591248405bad1f2af4 100644 (file)
@@ -234,7 +234,7 @@ static void scope_dump(Unit *u, FILE *f, const char *prefix) {
                 prefix, scope_state_to_string(s->state),
                 prefix, scope_result_to_string(s->result));
 
-        cgroup_context_dump(&s->cgroup_context, f, prefix);
+        cgroup_context_dump(UNIT(s), f, prefix);
         kill_context_dump(&s->kill_context, f, prefix);
 }
 
index 71befcddc835404f0fd59518f534f6a53977d716..ada25e634a063f5c169968f134456590948863e8 100644 (file)
@@ -905,7 +905,7 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
                         prefix, s->n_fd_store_max,
                         prefix, s->n_fd_store);
 
-        cgroup_context_dump(&s->cgroup_context, f, prefix);
+        cgroup_context_dump(UNIT(s), f, prefix);
 }
 
 static int service_is_suitable_main_pid(Service *s, pid_t pid, int prio) {
@@ -1838,13 +1838,17 @@ fail:
         service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
 }
 
-static int state_to_kill_operation(ServiceState state) {
+static int state_to_kill_operation(Service *s, ServiceState state) {
         switch (state) {
 
         case SERVICE_STOP_WATCHDOG:
                 return KILL_WATCHDOG;
 
         case SERVICE_STOP_SIGTERM:
+                if (unit_has_job_type(UNIT(s), JOB_RESTART))
+                        return KILL_RESTART;
+                _fallthrough_;
+
         case SERVICE_FINAL_SIGTERM:
                 return KILL_TERMINATE;
 
@@ -1875,7 +1879,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
         r = unit_kill_context(
                         UNIT(s),
                         &s->kill_context,
-                        state_to_kill_operation(state),
+                        state_to_kill_operation(s, state),
                         s->main_pid,
                         s->control_pid,
                         s->main_pid_alien);
@@ -2245,7 +2249,7 @@ static void service_enter_restart(Service *s) {
 
         assert(s);
 
-        if (UNIT(s)->job && UNIT(s)->job->type == JOB_STOP) {
+        if (unit_has_job_type(UNIT(s), JOB_STOP)) {
                 /* Don't restart things if we are going down anyway */
                 log_unit_info(UNIT(s), "Stop job pending for unit, delaying automatic restart.");
 
index 489d5ace6a1d70d756abb7c13921cef1ee9f1b5a..c12328b3b736daad43607709a5aa33f1b544fc07 100644 (file)
@@ -215,7 +215,7 @@ static void slice_dump(Unit *u, FILE *f, const char *prefix) {
                 "%sSlice State: %s\n",
                 prefix, slice_state_to_string(t->state));
 
-        cgroup_context_dump(&t->cgroup_context, f, prefix);
+        cgroup_context_dump(UNIT(t), f, prefix);
 }
 
 static int slice_start(Unit *u) {
index b95e6239d4b217c1302f02c611505fc419a88ab7..e2d4c0d6e1726ab3d6f73b0d2f576e98e3d0c8ca 100644 (file)
@@ -84,6 +84,7 @@ static int write_access2_rules(const char *srcdir) {
         FOREACH_DIRENT(entry, dir, return 0) {
                 _cleanup_fclose_ FILE *policy = NULL;
 
+                dirent_ensure_type(dir, entry);
                 if (!dirent_is_file(entry))
                         continue;
 
@@ -150,6 +151,7 @@ static int write_cipso2_rules(const char *srcdir) {
         FOREACH_DIRENT(entry, dir, return 0) {
                 _cleanup_fclose_ FILE *policy = NULL;
 
+                dirent_ensure_type(dir, entry);
                 if (!dirent_is_file(entry))
                         continue;
 
index d7ff7d1501a68faa44f2bd37277534af870eb596..f31d3bd971d64b5e16cc6d9b895b1a09c47fbb57 100644 (file)
@@ -843,7 +843,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
                 exec_command_dump_list(s->exec_command[c], f, prefix2);
         }
 
-        cgroup_context_dump(&s->cgroup_context, f, prefix);
+        cgroup_context_dump(UNIT(s), f, prefix);
 }
 
 static int instance_from_socket(int fd, unsigned nr, char **instance) {
@@ -2077,6 +2077,16 @@ fail:
         socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
 }
 
+static int state_to_kill_operation(Socket *s, SocketState state) {
+        if (state == SOCKET_STOP_PRE_SIGTERM && unit_has_job_type(UNIT(s), JOB_RESTART))
+                return KILL_RESTART;
+
+        if (state == SOCKET_FINAL_SIGTERM)
+                return KILL_TERMINATE;
+
+        return KILL_KILL;
+}
+
 static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
         int r;
 
@@ -2088,8 +2098,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
         r = unit_kill_context(
                         UNIT(s),
                         &s->kill_context,
-                        !IN_SET(state, SOCKET_STOP_PRE_SIGTERM, SOCKET_FINAL_SIGTERM) ?
-                        KILL_KILL : KILL_TERMINATE,
+                        state_to_kill_operation(s, state),
                         -1,
                         s->control_pid,
                         false);
index 6d0cd517504f228cf0ad13579647971e5350ddf8..ad1da6dddb6f977ed8fe2339c56943c25c3fa1db 100644 (file)
@@ -621,7 +621,7 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) {
 
         exec_context_dump(&s->exec_context, f, prefix);
         kill_context_dump(&s->kill_context, f, prefix);
-        cgroup_context_dump(&s->cgroup_context, f, prefix);
+        cgroup_context_dump(UNIT(s), f, prefix);
 }
 
 static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
@@ -712,21 +712,32 @@ static void swap_enter_dead_or_active(Swap *s, SwapResult f) {
                 swap_enter_dead(s, f);
 }
 
+static int state_to_kill_operation(Swap *s, SwapState state) {
+        if (state == SWAP_DEACTIVATING_SIGTERM) {
+                if (unit_has_job_type(UNIT(s), JOB_RESTART))
+                        return KILL_RESTART;
+                else
+                        return KILL_TERMINATE;
+        }
+
+        return KILL_KILL;
+}
+
 static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
         int r;
-        KillOperation kop;
 
         assert(s);
 
         if (s->result == SWAP_SUCCESS)
                 s->result = f;
 
-        if (state == SWAP_DEACTIVATING_SIGTERM)
-                kop = KILL_TERMINATE;
-        else
-                kop = KILL_KILL;
 
-        r = unit_kill_context(UNIT(s), &s->kill_context, kop, -1, s->control_pid, false);
+        r = unit_kill_context(UNIT(s),
+                              &s->kill_context,
+                              state_to_kill_operation(s, state),
+                              -1,
+                              s->control_pid,
+                              false);
         if (r < 0)
                 goto fail;
 
index b9fb7dbc0e134cd94b9b6610d4c83e3b26a99ecb..6dd075faa775c67e7c003681cbdbb27e307d4f52 100644 (file)
@@ -15,6 +15,7 @@
 #include "bpf-firewall.h"
 #include "bus-common-errors.h"
 #include "bus-util.h"
+#include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "dbus-unit.h"
 #include "dbus.h"
@@ -4022,7 +4023,7 @@ bool unit_stop_pending(Unit *u) {
          * different from unit_inactive_or_pending() which checks both
          * the current state and for a queued job. */
 
-        return u->job && u->job->type == JOB_STOP;
+        return unit_has_job_type(u, JOB_STOP);
 }
 
 bool unit_inactive_or_pending(Unit *u) {
@@ -4057,12 +4058,7 @@ bool unit_active_or_pending(Unit *u) {
 bool unit_will_restart_default(Unit *u) {
         assert(u);
 
-        if (!u->job)
-                return false;
-        if (u->job->type == JOB_START)
-                return true;
-
-        return false;
+        return unit_has_job_type(u, JOB_START);
 }
 
 bool unit_will_restart(Unit *u) {
@@ -4691,19 +4687,26 @@ static int log_kill(pid_t pid, int sig, void *userdata) {
         return 1;
 }
 
-static int operation_to_signal(KillContext *c, KillOperation k) {
+static int operation_to_signal(const KillContext *c, KillOperation k, bool *noteworthy) {
         assert(c);
 
         switch (k) {
 
         case KILL_TERMINATE:
         case KILL_TERMINATE_AND_LOG:
+                *noteworthy = false;
                 return c->kill_signal;
 
+        case KILL_RESTART:
+                *noteworthy = false;
+                return restart_kill_signal(c);
+
         case KILL_KILL:
+                *noteworthy = true;
                 return c->final_kill_signal;
 
         case KILL_WATCHDOG:
+                *noteworthy = true;
                 return c->watchdog_signal;
 
         default:
@@ -4732,16 +4735,16 @@ int unit_kill_context(
         if (c->kill_mode == KILL_NONE)
                 return 0;
 
-        sig = operation_to_signal(c, k);
+        bool noteworthy;
+        sig = operation_to_signal(c, k, &noteworthy);
+        if (noteworthy)
+                log_func = log_kill;
 
         send_sighup =
                 c->send_sighup &&
                 IN_SET(k, KILL_TERMINATE, KILL_TERMINATE_AND_LOG) &&
                 sig != SIGHUP;
 
-        if (k != KILL_TERMINATE || IN_SET(sig, SIGKILL, SIGABRT))
-                log_func = log_kill;
-
         if (main_pid > 0) {
                 if (log_func)
                         log_func(main_pid, sig, u);
index 3b0042a9ebe91d9468b254bc1ff572507a833320..96f718acdcc638f4587faefd11f88d3a94c31361 100644 (file)
@@ -18,6 +18,7 @@ typedef struct UnitRef UnitRef;
 typedef enum KillOperation {
         KILL_TERMINATE,
         KILL_TERMINATE_AND_LOG,
+        KILL_RESTART,
         KILL_KILL,
         KILL_WATCHDOG,
         _KILL_OPERATION_MAX,
@@ -842,6 +843,10 @@ const char *unit_label_path(Unit *u);
 
 int unit_pid_attachable(Unit *unit, pid_t pid, sd_bus_error *error);
 
+static inline bool unit_has_job_type(Unit *u, JobType type) {
+        return u && u->job && u->job->type == type;
+}
+
 /* unit_log_skip is for cases like ExecCondition= where a unit is considered "done"
  * after some execution, rather than succeeded or failed. */
 void unit_log_skip(Unit *u, const char *result);
index 78732a0a577f994b2e63ab4cde7954f88c4ca193..ebefb4d4d27386be83e860721434a62a8192f5d5 100644 (file)
@@ -35,9 +35,7 @@
 static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT or CRYPT_PLAIN */
 static char *arg_cipher = NULL;
 static unsigned arg_key_size = 0;
-#if HAVE_LIBCRYPTSETUP_SECTOR_SIZE
 static unsigned arg_sector_size = CRYPT_SECTOR_SIZE;
-#endif
 static int arg_key_slot = CRYPT_ANY_SLOT;
 static unsigned arg_keyfile_size = 0;
 static uint64_t arg_keyfile_offset = 0;
@@ -51,9 +49,7 @@ static bool arg_same_cpu_crypt = false;
 static bool arg_submit_from_crypt_cpus = false;
 static bool arg_tcrypt_hidden = false;
 static bool arg_tcrypt_system = false;
-#ifdef CRYPT_TCRYPT_VERA_MODES
 static bool arg_tcrypt_veracrypt = false;
-#endif
 static char **arg_tcrypt_keyfiles = NULL;
 static uint64_t arg_offset = 0;
 static uint64_t arg_skip = 0;
@@ -109,7 +105,6 @@ static int parse_one_option(const char *option) {
 
         } else if ((val = startswith(option, "sector-size="))) {
 
-#if HAVE_LIBCRYPTSETUP_SECTOR_SIZE
                 r = safe_atou(val, &arg_sector_size);
                 if (r < 0) {
                         log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
@@ -125,10 +120,6 @@ static int parse_one_option(const char *option) {
                         log_error("sector-size= is outside of %u and %u, ignoring.", CRYPT_SECTOR_SIZE, CRYPT_MAX_SECTOR_SIZE);
                         return 0;
                 }
-#else
-                log_error("sector-size= is not supported, compiled with old libcryptsetup.");
-                return 0;
-#endif
 
         } else if ((val = startswith(option, "key-slot="))) {
 
@@ -157,22 +148,13 @@ static int parse_one_option(const char *option) {
                 }
 
         } else if ((val = startswith(option, "keyfile-offset="))) {
-                uint64_t off;
 
-                r = safe_atou64(val, &off);
+                r = safe_atou64(val, &arg_keyfile_offset);
                 if (r < 0) {
                         log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
                         return 0;
                 }
 
-                if ((size_t) off != off) {
-                        /* https://gitlab.com/cryptsetup/cryptsetup/issues/359 */
-                        log_error("keyfile-offset= value would truncated to %zu, ignoring.", (size_t) off);
-                        return 0;
-                }
-
-                arg_keyfile_offset = off;
-
         } else if ((val = startswith(option, "hash="))) {
                 r = free_and_strdup(&arg_hash, val);
                 if (r < 0)
@@ -222,13 +204,8 @@ static int parse_one_option(const char *option) {
                 arg_type = CRYPT_TCRYPT;
                 arg_tcrypt_system = true;
         } else if (streq(option, "tcrypt-veracrypt")) {
-#ifdef CRYPT_TCRYPT_VERA_MODES
                 arg_type = CRYPT_TCRYPT;
                 arg_tcrypt_veracrypt = true;
-#else
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "This version of cryptsetup does not support tcrypt-veracrypt; refusing.");
-#endif
         } else if (STR_IN_SET(option, "plain", "swap", "tmp"))
                 arg_type = CRYPT_PLAIN;
         else if ((val = startswith(option, "timeout="))) {
@@ -453,10 +430,8 @@ static int attach_tcrypt(
         if (arg_tcrypt_system)
                 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
 
-#ifdef CRYPT_TCRYPT_VERA_MODES
         if (arg_tcrypt_veracrypt)
                 params.flags |= CRYPT_TCRYPT_VERA_MODES;
-#endif
 
         if (key_file) {
                 r = read_one_line_file(key_file, &passphrase);
@@ -503,9 +478,7 @@ static int attach_luks_or_plain(struct crypt_device *cd,
                 struct crypt_params_plain params = {
                         .offset = arg_offset,
                         .skip = arg_skip,
-#if HAVE_LIBCRYPTSETUP_SECTOR_SIZE
                         .sector_size = arg_sector_size,
-#endif
                 };
                 const char *cipher, *cipher_mode;
                 _cleanup_free_ char *truncated_cipher = NULL;
@@ -554,7 +527,7 @@ static int attach_luks_or_plain(struct crypt_device *cd,
                  crypt_get_device_name(cd));
 
         if (key_file) {
-                r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
+                r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
                 if (r == -EPERM) {
                         log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
                         return -EAGAIN; /* Log actual error, but return EAGAIN */
@@ -723,7 +696,7 @@ static int run(int argc, char *argv[]) {
                                 if (r < 0)
                                         return log_error_errno(r, "Failed to set LUKS data device %s: %m", argv[3]);
                         }
-#ifdef CRYPT_ANY_TOKEN
+
                         /* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
                         if (!key_file) {
                                 r = crypt_activate_by_token(cd, argv[2], CRYPT_ANY_TOKEN, NULL, flags);
@@ -734,7 +707,6 @@ static int run(int argc, char *argv[]) {
 
                                 log_debug_errno(r, "Token activation unsuccessful for device %s: %m", crypt_get_device_name(cd));
                         }
-#endif
                 }
 
                 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
index e73dde32b883b9423ac0abd550a9638680cd201f..bc8714c4c7f5cbae20cca42f15a141c26c60284b 100644 (file)
@@ -12,6 +12,7 @@
 #include "special.h"
 #include "string-util.h"
 #include "strv.h"
+#include "unit-file.h"
 #include "unit-name.h"
 
 static const char *arg_dest = NULL;
index 49149b59be5df457af238399053b67b15d4a070c..5002eb9d7435c6f1b43974eebb1dc1cf7393ee66 100644 (file)
@@ -15,7 +15,7 @@
 #include "device-util.h"
 #include "dirent-util.h"
 #include "dissect-image.h"
-#include "efivars.h"
+#include "efi-loader.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
index e0269b54564f15837f4e98fc5473d2bfbf89998c..c231773bddb324f0c332037d6e18e91aeefe6d10 100644 (file)
@@ -19,7 +19,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
                                  uint32_t xid, const uint8_t *mac_addr,
                                  size_t mac_addr_len, uint16_t arp_type,
                                  uint16_t port);
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port);
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
                                  const void *packet, size_t len);
 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
@@ -41,7 +41,7 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
 
 void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
                                    uint16_t source, be32_t destination_addr,
-                                   uint16_t destination, uint16_t len);
+                                   uint16_t destination, uint16_t len, int ip_service_type);
 
 int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port);
 
index 94c10ed14c01ac37175a4eab0e2b371d8f376197..8e7f8a65ab64014064456fa08bfa8635f2da795b 100644 (file)
@@ -146,7 +146,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
                                 bcast_addr, &eth_mac, arp_type, dhcp_hlen, port);
 }
 
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
         union sockaddr_union src = {
                 .in.sin_family = AF_INET,
                 .in.sin_port = htobe16(port),
@@ -159,7 +159,11 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
         if (s < 0)
                 return -errno;
 
-        r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
+        if (ip_service_type >= 0)
+                r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type);
+        else
+                r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
+
         if (r < 0)
                 return r;
 
index ad5f8e267abd20a1461cc46ef34e4d79fe3b4210..fe7d51703badb3669c65637a1176dafe7abf442a 100644 (file)
@@ -75,12 +75,15 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
 
 void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
                                    uint16_t source_port, be32_t destination_addr,
-                                   uint16_t destination_port, uint16_t len) {
+                                   uint16_t destination_port, uint16_t len, int ip_service_type) {
         packet->ip.version = IPVERSION;
         packet->ip.ihl = DHCP_IP_SIZE / 4;
         packet->ip.tot_len = htobe16(len);
 
-        packet->ip.tos = IPTOS_CLASS_CS6;
+        if (ip_service_type >= 0)
+                packet->ip.tos = ip_service_type;
+        else
+                packet->ip.tos = IPTOS_CLASS_CS6;
 
         packet->ip.protocol = IPPROTO_UDP;
         packet->ip.saddr = source_addr;
index f28ba68dd1e9a8e09bbc879414887570c8ebafe4..517e357d3df22b6c251d0dd1fc38a79588d2fb0f 100644 (file)
@@ -85,7 +85,7 @@ typedef struct DHCP6IA DHCP6IA;
 int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
                         size_t optlen, const void *optval);
 int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
-int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd);
+int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix);
 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);
index 017402c53bf20d69cc1c44272e2c8d99e2a988c3..ca67559e6f04b86de032afa2c4fe23438b916735 100644 (file)
@@ -168,9 +168,10 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
         return r;
 }
 
-int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) {
+int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) {
         DHCP6Option *option = (DHCP6Option *)buf;
         size_t i = sizeof(*option) + sizeof(pd->ia_pd);
+        DHCP6PDPrefixOption *prefix_opt;
         DHCP6Address *prefix;
 
         assert_return(buf, -EINVAL);
@@ -183,10 +184,7 @@ int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) {
         option->code = htobe16(SD_DHCP6_OPTION_IA_PD);
 
         memcpy(&option->data, &pd->ia_pd, sizeof(pd->ia_pd));
-
         LIST_FOREACH(addresses, prefix, pd->addresses) {
-                DHCP6PDPrefixOption *prefix_opt;
-
                 if (len < i + sizeof(*prefix_opt))
                         return -ENOBUFS;
 
@@ -194,9 +192,19 @@ int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) {
                 prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX);
                 prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix));
 
-                memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix,
-                       sizeof(struct iapdprefix));
+                memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, sizeof(struct iapdprefix));
+                i += sizeof(*prefix_opt);
+        }
+
+        if (hint_pd_prefix && hint_pd_prefix->iapdprefix.prefixlen > 0) {
+                if (len < i + sizeof(*prefix_opt))
+                        return -ENOBUFS;
+
+                prefix_opt = (DHCP6PDPrefixOption *)&buf[i];
+                prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX);
+                prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix));
 
+                memcpy(&prefix_opt->iapdprefix, &hint_pd_prefix->iapdprefix, sizeof(struct iapdprefix));
                 i += sizeof(*prefix_opt);
         }
 
index cadacc24d46925b2bc390f41000dcbd1e26d9b4a..02f3569edca877a0b117417318a33a4fc2aa7603 100644 (file)
@@ -98,6 +98,7 @@ struct sd_dhcp_client {
         void *userdata;
         sd_dhcp_lease *lease;
         usec_t start_delay;
+        int ip_service_type;
 };
 
 static const uint8_t default_req_opts[] = {
@@ -541,6 +542,14 @@ int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
         return 0;
 }
 
+int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
+        assert_return(client, -EINVAL);
+
+        client->ip_service_type = type;
+
+        return 0;
+}
+
 static int client_notify(sd_dhcp_client *client, int event) {
         assert(client);
 
@@ -773,7 +782,7 @@ static int dhcp_client_send_raw(
                 size_t len) {
 
         dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
-                                      INADDR_BROADCAST, DHCP_PORT_SERVER, len);
+                                      INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type);
 
         return dhcp_network_send_raw_socket(client->fd, &client->link,
                                             packet, len);
@@ -861,41 +870,6 @@ static int client_send_discover(sd_dhcp_client *client) {
         return 0;
 }
 
-static int client_send_release(sd_dhcp_client *client) {
-        _cleanup_free_ DHCPPacket *release = NULL;
-        size_t optoffset, optlen;
-        int r;
-
-        assert(client);
-        assert(!IN_SET(client->state, DHCP_STATE_STOPPED));
-
-        r = client_message_init(client, &release, DHCP_RELEASE,
-                                &optlen, &optoffset);
-        if (r < 0)
-                return r;
-
-        /* Fill up release IP and MAC */
-        release->dhcp.ciaddr = client->lease->address;
-        memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
-
-        r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
-                               SD_DHCP_OPTION_END, 0, NULL);
-        if (r < 0)
-                return r;
-
-        r = dhcp_network_send_udp_socket(client->fd,
-                                         client->lease->server_address,
-                                         DHCP_PORT_SERVER,
-                                         &release->dhcp,
-                                         sizeof(DHCPMessage) + optoffset);
-        if (r < 0)
-                return r;
-
-        log_dhcp_client(client, "RELEASE");
-
-        return 0;
-}
-
 static int client_send_request(sd_dhcp_client *client) {
         _cleanup_free_ DHCPPacket *request = NULL;
         size_t optoffset, optlen;
@@ -1661,7 +1635,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
                                 goto error;
                         }
 
-                        r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port);
+                        r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port, client->ip_service_type);
                         if (r < 0) {
                                 log_dhcp_client(client, "could not bind UDP socket");
                                 goto error;
@@ -1920,8 +1894,35 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
 
 int sd_dhcp_client_send_release(sd_dhcp_client *client) {
         assert_return(client, -EINVAL);
+        assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
+        assert_return(client->lease, -EUNATCH);
+
+        _cleanup_free_ DHCPPacket *release = NULL;
+        size_t optoffset, optlen;
+        int r;
+
+        r = client_message_init(client, &release, DHCP_RELEASE, &optlen, &optoffset);
+        if (r < 0)
+                return r;
 
-        client_send_release(client);
+        /* Fill up release IP and MAC */
+        release->dhcp.ciaddr = client->lease->address;
+        memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
+
+        r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
+                               SD_DHCP_OPTION_END, 0, NULL);
+        if (r < 0)
+                return r;
+
+        r = dhcp_network_send_udp_socket(client->fd,
+                                         client->lease->server_address,
+                                         DHCP_PORT_SERVER,
+                                         &release->dhcp,
+                                         sizeof(DHCPMessage) + optoffset);
+        if (r < 0)
+                return r;
+
+        log_dhcp_client(client, "RELEASE");
 
         return 0;
 }
@@ -2013,6 +2014,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
                 .port = DHCP_PORT_CLIENT,
                 .anonymize = !!anonymize,
                 .max_attempts = (uint64_t) -1,
+                .ip_service_type = -1,
         };
         /* NOTE: this could be moved to a function. */
         if (anonymize) {
index 13f104f9ef556519b89bc8aeec6f0b5cba6402a6..bba82c21dd7f70a503a8777fc45ac2346f541019 100644 (file)
@@ -244,7 +244,7 @@ static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
 
         dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
                                       packet->dhcp.yiaddr,
-                                      DHCP_PORT_CLIENT, len);
+                                      DHCP_PORT_CLIENT, len, -1);
 
         return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
 }
@@ -994,7 +994,7 @@ int sd_dhcp_server_start(sd_dhcp_server *server) {
         }
         server->fd_raw = r;
 
-        r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER);
+        r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER, -1);
         if (r < 0) {
                 sd_dhcp_server_stop(server);
                 return r;
index 9773a067d5858464ce67884861102b35c9f6b94c..33420fd4c095c3c56d82e465caf775fcc3d1ddda 100644 (file)
@@ -46,6 +46,7 @@ struct sd_dhcp6_client {
         sd_event *event;
         int event_priority;
         int ifindex;
+        DHCP6Address hint_pd_prefix;
         struct in6_addr local_address;
         uint8_t mac_addr[MAX_MAC_ADDR_LEN];
         size_t mac_addr_len;
@@ -187,6 +188,22 @@ int sd_dhcp6_client_set_mac(
         return 0;
 }
 
+int sd_dhcp6_client_set_prefix_delegation_hint(
+                sd_dhcp6_client *client,
+                uint8_t prefixlen,
+                const struct in6_addr *pd_address) {
+
+        assert_return(client, -EINVAL);
+        assert_return(pd_address, -EINVAL);
+
+        assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+
+        client->hint_pd_prefix.iapdprefix.address = *pd_address;
+        client->hint_pd_prefix.iapdprefix.prefixlen = prefixlen;
+
+        return 0;
+}
+
 static int client_ensure_duid(sd_dhcp6_client *client) {
         if (client->duid_len != 0)
                 return 0;
@@ -492,7 +509,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 }
 
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
-                        r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd);
+                        r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
                         if (r < 0)
                                 return r;
 
@@ -530,7 +547,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 }
 
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
-                        r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
+                        r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
                         if (r < 0)
                                 return r;
 
@@ -556,7 +573,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 }
 
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
-                        r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
+                        r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
                         if (r < 0)
                                 return r;
 
@@ -1537,6 +1554,8 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
                 .request = DHCP6_REQUEST_IA_NA,
                 .fd = -1,
                 .req_opts_len = ELEMENTSOF(default_req_opts),
+                .hint_pd_prefix.iapdprefix.lifetime_preferred = (be32_t) -1,
+                .hint_pd_prefix.iapdprefix.lifetime_valid = (be32_t) -1,
                 .req_opts = TAKE_PTR(req_opts),
         };
 
index 5f31d24d20bd4d3e750d5bd88d02a9c835909746..4e9b388a451aa0be06c3838d9aa34773b8e45717 100644 (file)
@@ -269,7 +269,7 @@ int dhcp_network_bind_raw_socket(
         return test_fd[0];
 }
 
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
         int fd;
 
         fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
index c02c459663b883f68c7c652704f274df9859b0b6..7f7bc491d2586faf050141d7f386d284060a38e3 100644 (file)
@@ -13,7 +13,7 @@ int main(int argc, char *argv[]) {
 
         test_setup_logging(LOG_DEBUG);
 
-        if (cg_unified_flush() == -ENOMEDIUM)
+        if (cg_unified() == -ENOMEDIUM)
                 return log_tests_skipped("/sys/fs/cgroup/ not available");
 
         r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL);
index 5adbceeb0247c7a7dcdf8e9ab22df27fe0927bed..ee10728ece26370bd918714c39c20b42178fb823 100644 (file)
@@ -2552,7 +2552,7 @@ static int process_child(sd_event *e) {
                                  * benefit in leaving it queued */
 
                                 assert(s->child.options & (WSTOPPED|WCONTINUED));
-                                waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
+                                (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
                         }
 
                         r = source_set_pending(s, true);
index 30b9a66334fa7914e4f6984da46c49dd678e12aa..20a8591bd8e58ec06b8688c260506c7d50849b0d 100644 (file)
@@ -20,6 +20,7 @@
 #include "device-util.h"
 #include "dirent-util.h"
 #include "efivars.h"
+#include "efi-loader.h"
 #include "env-util.h"
 #include "escape.h"
 #include "fd-util.h"
@@ -1378,6 +1379,7 @@ static int flush_devices(Manager *m) {
                 struct dirent *de;
 
                 FOREACH_DIRENT_ALL(de, d, break) {
+                        dirent_ensure_type(d, de);
                         if (!dirent_is_file(de))
                                 continue;
 
index 3a16e6c8712a89740a1ae1e173e74f39d8180975..d889d7b9bec953851354a57a7f89810868261843 100644 (file)
@@ -291,6 +291,7 @@ static int manager_enumerate_linger_users(Manager *m) {
         FOREACH_DIRENT(de, d, return -errno) {
                 int k;
 
+                dirent_ensure_type(d, de);
                 if (!dirent_is_file(de))
                         continue;
 
index 3f762cbbc30b4d7d8c89f025bbad38c5491f0202..766d651c3fb11a9c65ec7cdd7e72f4ec803882af 100644 (file)
@@ -20,7 +20,7 @@
 #include "bus-error.h"
 #include "bus-internal.h"
 #include "bus-util.h"
-#include "cgroup-util.h"
+#include "cgroup-setup.h"
 #include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
index 1ef5beb2032d48c4b29d0bd9028aa19a4c8f881f..eef7788c49efbd88509a9f90df576929e8ce12da 100644 (file)
@@ -4,6 +4,7 @@
  ***/
 
 #include <ctype.h>
+#include <netinet/ip.h>
 
 #include "conf-parser.h"
 #include "def.h"
@@ -14,6 +15,7 @@
 #include "networkd-manager.h"
 #include "networkd-network.h"
 #include "networkd-speed-meter.h"
+#include "networkd-dhcp4.h"
 #include "string-table.h"
 
 int manager_parse_config_file(Manager *m) {
@@ -180,3 +182,30 @@ int config_parse_duid_rawdata(
         ret->raw_data_len = count;
         return 0;
 }
+
+int config_parse_ip_service_type(
+                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) {
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        if (streq(rvalue, "CS4"))
+                *((int *)data) = IPTOS_CLASS_CS4;
+        else if (streq(rvalue, "CS6"))
+                *((int *)data) = IPTOS_CLASS_CS6;
+        else
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "Failed to parse IPServiceType type '%s', ignoring.", rvalue);
+
+        return 0;
+}
index 88a2c64031c22fcc5a497c3e380d2699695a4074..a615998f92d922946fe2f2ed075643bacba8a678 100644 (file)
@@ -15,3 +15,4 @@ const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, GPERF_LEN_TY
 
 CONFIG_PARSER_PROTOTYPE(config_parse_duid_type);
 CONFIG_PARSER_PROTOTYPE(config_parse_duid_rawdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_ip_service_type);
index 36ae728e24623e73797e3bcbf463cee055537820..bbf10affc4561136e32d08cc53dac0820192a5ff 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include "in-addr-util.h"
 #include "networkd-dhcp-common.h"
 #include "networkd-network.h"
 #include "parse-util.h"
@@ -227,6 +228,41 @@ int config_parse_iaid(const char *unit,
         return 0;
 }
 
+int config_parse_dhcp6_pd_hint(
+                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) {
+
+        Network *network = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = in_addr_prefix_from_string(rvalue, AF_INET6, (union in_addr_union *) &network->dhcp6_pd_address, &network->dhcp6_pd_length);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue);
+                return 0;
+        }
+
+        if (network->dhcp6_pd_length < 1 || network->dhcp6_pd_length > 128) {
+                log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid prefix length='%d', ignoring assignment", network->dhcp6_pd_length);
+                network->dhcp6_pd_length = 0;
+                return 0;
+        }
+
+        return 0;
+}
+
 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
                          "Failed to parse DHCP use domains setting");
 
index 3e079b91b9cf3d80d2d9b301de61666b71e0f179..8f280190b9978bbe1efd8464b782389fcd9bd78f 100644 (file)
@@ -34,3 +34,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_ntp);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_sip);
 CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
 CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
index 06e87199c69debc162e2ebb85e50349cba2e12a6..6b85428758e5ab87bbfa67ab1d3e93485c85ff4d 100644 (file)
@@ -19,7 +19,9 @@
 static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
 static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
 static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
-static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, const struct in_addr *address);
+static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, link_netlink_message_handler_t callback);
+static int dhcp_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link);
+static int dhcp_lease_renew(sd_dhcp_client *client, Link *link);
 
 void dhcp4_release_old_lease(Link *link) {
         struct in_addr address = {}, address_old = {};
@@ -39,7 +41,7 @@ void dhcp4_release_old_lease(Link *link) {
         (void) dhcp_remove_dns_routes(link, link->dhcp_lease_old, &address_old, false);
 
         if (!in4_addr_equal(&address_old, &address))
-                (void) dhcp_remove_address(link, link->dhcp_lease_old, &address_old);
+                (void) dhcp_remove_address(link, link->dhcp_lease_old, &address_old, NULL);
 
         link->dhcp_lease_old = sd_dhcp_lease_unref(link->dhcp_lease_old);
         link_dirty(link);
@@ -57,13 +59,35 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
                 return 1;
 
         r = sd_netlink_message_get_errno(m);
-        if (r < 0 && r != -EEXIST) {
+        if (r == -ENETUNREACH && !link->dhcp4_route_retrying) {
+
+                /* It seems kernel does not support that the prefix route cannot be configured with
+                 * route table. Let's once drop the config and reconfigure them later. */
+
+                log_link_debug_errno(link, r, "Could not set DHCPv4 route, retrying later: %m");
+                link->dhcp4_route_failed = true;
+                link->manager->dhcp4_prefix_root_cannot_set_table = true;
+        } else if (r < 0 && r != -EEXIST) {
                 log_link_error_errno(link, r, "Could not set DHCPv4 route: %m");
                 link_enter_failed(link);
                 return 1;
         }
 
         if (link->dhcp4_messages == 0) {
+                if (link->dhcp4_route_failed) {
+                        struct in_addr address = {};
+
+                        link->dhcp4_route_failed = false;
+                        link->dhcp4_route_retrying = true;
+
+                        (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
+                        (void) dhcp_remove_routes(link, link->dhcp_lease, &address, true);
+                        (void) dhcp_remove_router(link, link->dhcp_lease, &address, true);
+                        (void) dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true);
+                        (void) dhcp_remove_address(link, link->dhcp_lease, &address, dhcp_remove_address_handler);
+
+                        return 1;
+                }
                 link->dhcp4_configured = true;
                 /* New address and routes are configured now. Let's release old lease. */
                 dhcp4_release_old_lease(link);
@@ -86,6 +110,12 @@ static int route_scope_from_address(const Route *route, const struct in_addr *se
                 return RT_SCOPE_UNIVERSE;
 }
 
+static bool link_noprefixroute(Link *link) {
+        return link->network->dhcp_route_table_set &&
+                link->network->dhcp_route_table != RT_TABLE_MAIN &&
+                !link->manager->dhcp4_prefix_root_cannot_set_table;
+}
+
 static int dhcp_route_configure(Route **route, Link *link) {
         int r;
 
@@ -157,6 +187,35 @@ static int link_set_dns_routes(Link *link, const struct in_addr *address) {
         return 0;
 }
 
+static int dhcp_prefix_route_from_lease(
+                const sd_dhcp_lease *lease,
+                uint32_t table,
+                const struct in_addr *address,
+                Route **ret_route) {
+
+        Route *route;
+        struct in_addr netmask;
+        int r;
+
+        r = sd_dhcp_lease_get_netmask((sd_dhcp_lease*) lease, &netmask);
+        if (r < 0)
+                return r;
+
+        r = route_new(&route);
+        if (r < 0)
+                return r;
+
+        route->family = AF_INET;
+        route->dst.in.s_addr = address->s_addr & netmask.s_addr;
+        route->dst_prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
+        route->prefsrc.in = *address;
+        route->scope = RT_SCOPE_LINK;
+        route->protocol = RTPROT_DHCP;
+        route->table = table;
+        *ret_route = route;
+        return 0;
+}
+
 static int link_set_dhcp_routes(Link *link) {
         _cleanup_free_ sd_dhcp_route **static_routes = NULL;
         bool classless_route = false, static_route = false;
@@ -194,6 +253,18 @@ static int link_set_dhcp_routes(Link *link) {
         if (r < 0)
                 return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
 
+        if (link_noprefixroute(link)) {
+                _cleanup_(route_freep) Route *prefix_route = NULL;
+
+                r = dhcp_prefix_route_from_lease(link->dhcp_lease, table, &address, &prefix_route);
+                if (r < 0)
+                        return log_link_error_errno(link, r,  "Could not create prefix route: %m");
+
+                r = dhcp_route_configure(&prefix_route, link);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not set prefix route: %m");
+        }
+
         n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
         if (n == -ENODATA)
                 log_link_debug_errno(link, n, "DHCP: No routes received from DHCP server: %m");
@@ -444,10 +515,46 @@ static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct
                 (void) route_remove(route, link, NULL);
         }
 
+        if (link_noprefixroute(link)) {
+                _cleanup_(route_freep) Route *prefix_route = NULL;
+
+                r = dhcp_prefix_route_from_lease(lease, table, address, &prefix_route);
+                if (r < 0)
+                        return log_link_warning_errno(link, r,  "Could not delete prefix route: %m");
+
+                if (remove_all || !set_contains(link->dhcp_routes, prefix_route))
+                        (void) route_remove(prefix_route, link, NULL);
+        }
+
         return 0;
 }
 
-static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, const struct in_addr *address) {
+static int dhcp_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(link);
+
+        /* This is only used when retrying to assign the address received from DHCPv4 server.
+         * See dhcp4_route_handler(). */
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0)
+                log_link_debug_errno(link, r, "Failed to remove DHCPv4 address, ignoring: %m");
+        else
+                (void) manager_rtnl_process_address(rtnl, m, link->manager);
+
+        (void) dhcp_lease_renew(link->dhcp_client, link);
+        return 1;
+}
+
+static int dhcp_remove_address(
+                        Link *link, sd_dhcp_lease *lease,
+                        const struct in_addr *address,
+                        link_netlink_message_handler_t callback) {
+
         _cleanup_(address_freep) Address *a = NULL;
         struct in_addr netmask;
         int r;
@@ -468,7 +575,7 @@ static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, const struct in
         if (sd_dhcp_lease_get_netmask(lease, &netmask) >= 0)
                 a->prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
 
-        (void) address_remove(a, link, NULL);
+        (void) address_remove(a, link, callback);
 
         return 0;
 }
@@ -537,7 +644,7 @@ static int dhcp_lease_lost(Link *link) {
         (void) dhcp_remove_routes(link, link->dhcp_lease, &address, true);
         (void) dhcp_remove_router(link, link->dhcp_lease, &address, true);
         (void) dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true);
-        (void) dhcp_remove_address(link, link->dhcp_lease, &address);
+        (void) dhcp_remove_address(link, link->dhcp_lease, &address, NULL);
         (void) dhcp_reset_mtu(link);
         (void) dhcp_reset_hostname(link);
 
@@ -611,6 +718,7 @@ static int dhcp4_update_address(Link *link,
         addr->cinfo.ifa_valid = lifetime;
         addr->prefixlen = prefixlen;
         addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
+        addr->prefix_route = link_noprefixroute(link);
 
         /* allow reusing an existing address and simply update its lifetime
          * in case it already exists */
@@ -864,10 +972,10 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
                                 return 0;
                         }
 
-                        if (link->network->dhcp_send_release)
-                                (void) sd_dhcp_client_send_release(client);
-
                         if (link->dhcp_lease) {
+                                if (link->network->dhcp_send_release)
+                                        (void) sd_dhcp_client_send_release(client);
+
                                 r = dhcp_lease_lost(link);
                                 if (r < 0) {
                                         link_enter_failed(link);
@@ -1213,7 +1321,12 @@ int dhcp4_configure(Link *link) {
                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
         }
 
-        return dhcp4_set_client_identifier(link);
+        if (link->network->ip_service_type > 0) {
+                r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->ip_service_type);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ip service type: %m");
+        }
+       return dhcp4_set_client_identifier(link);
 }
 
 int config_parse_dhcp_max_attempts(
index e61eeda7d0e7fc5eb54cf3c478db06a18725b61f..647623ac37783c81b751606100ff01a99d6e1fd9 100644 (file)
@@ -686,6 +686,12 @@ int dhcp6_configure(Link *link) {
                         return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix delegation: %m");
         }
 
+        if (link->network->dhcp6_pd_length > 0) {
+                r = sd_dhcp6_client_set_prefix_delegation_hint(client, link->network->dhcp6_pd_length, &link->network->dhcp6_pd_address);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix hint: %m");
+        }
+
         link->dhcp6_client = TAKE_PTR(client);
 
         return 0;
index 54cbc678b44137712e2bcf05f2da2f14464e244e..a23bddde9b67675fd3d948f8074f922950b2d166 100644 (file)
@@ -770,8 +770,12 @@ int link_stop_clients(Link *link, bool may_keep_dhcp) {
 
         dhcp4_release_old_lease(link);
 
-        if (link->dhcp_client && (!may_keep_dhcp || !link->network ||
-                                  !FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP))) {
+        bool keep_dhcp = may_keep_dhcp &&
+                         link->network &&
+                         (link->manager->restarting ||
+                          FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP));
+
+        if (link->dhcp_client && !keep_dhcp) {
                 k = sd_dhcp_client_stop(link->dhcp_client);
                 if (k < 0)
                         r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
@@ -856,8 +860,6 @@ static void link_enter_configured(Link *link) {
         if (link->state != LINK_STATE_CONFIGURING)
                 return;
 
-        log_link_info(link, "Configured");
-
         link_set_state(link, LINK_STATE_CONFIGURED);
 
         (void) link_join_netdevs_after_configured(link);
index d364692c864d1100ad04ab8307f223934cfbb60b..446c042fb9b9d125a8bdb6e561a126a6a150dc90 100644 (file)
@@ -89,8 +89,10 @@ typedef struct Link {
         char *lease_file;
         uint32_t original_mtu;
         unsigned dhcp4_messages;
-        bool dhcp4_configured;
-        bool dhcp6_configured;
+        bool dhcp4_route_failed:1;
+        bool dhcp4_route_retrying:1;
+        bool dhcp4_configured:1;
+        bool dhcp6_configured:1;
 
         unsigned ndisc_messages;
         bool ndisc_configured;
@@ -98,11 +100,10 @@ typedef struct Link {
         sd_ipv4ll *ipv4ll;
         bool ipv4ll_address:1;
 
-        bool neighbors_configured;
-
-        bool static_routes_configured;
-        bool routing_policy_rules_configured;
-        bool setting_mtu;
+        bool neighbors_configured:1;
+        bool static_routes_configured:1;
+        bool routing_policy_rules_configured:1;
+        bool setting_mtu:1;
 
         LIST_HEAD(Address, pool_addresses);
 
index e0c095d022373db4cd7f993ac5e43bd2fab8307d..546bb2375ce7306650929caed259415aae2127c5 100644 (file)
@@ -30,6 +30,7 @@
 #include "ordered-set.h"
 #include "path-util.h"
 #include "set.h"
+#include "signal-util.h"
 #include "strv.h"
 #include "sysctl-util.h"
 #include "tmpfile-util.h"
@@ -1561,6 +1562,28 @@ static int manager_dirty_handler(sd_event_source *s, void *userdata) {
         return 1;
 }
 
+static int signal_terminate_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+        Manager *m = userdata;
+
+        assert(m);
+        m->restarting = false;
+
+        log_debug("Terminate operation initiated.");
+
+        return sd_event_exit(sd_event_source_get_event(s), 0);
+}
+
+static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+        Manager *m = userdata;
+
+        assert(m);
+        m->restarting = true;
+
+        log_debug("Restart operation initiated.");
+
+        return sd_event_exit(sd_event_source_get_event(s), 0);
+}
+
 int manager_new(Manager **ret) {
         _cleanup_(manager_freep) Manager *m = NULL;
         int r;
@@ -1581,9 +1604,12 @@ int manager_new(Manager **ret) {
         if (r < 0)
                 return r;
 
+        assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR2, -1) >= 0);
+
         (void) sd_event_set_watchdog(m->event, true);
-        (void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
-        (void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
+        (void) sd_event_add_signal(m->event, NULL, SIGTERM, signal_terminate_callback, m);
+        (void) sd_event_add_signal(m->event, NULL, SIGINT, signal_terminate_callback, m);
+        (void) sd_event_add_signal(m->event, NULL, SIGUSR2, signal_restart_callback, m);
 
         r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m);
         if (r < 0)
index f5166dad126cc342dc2dd206e0f1e2bd2b78b0d4..d5049df8688d678abfc231b16ecf6b2afd5b8698 100644 (file)
@@ -29,6 +29,7 @@ struct Manager {
 
         bool enumerating:1;
         bool dirty:1;
+        bool restarting:1;
 
         Set *dirty_links;
 
@@ -64,6 +65,8 @@ struct Manager {
         usec_t speed_meter_interval_usec;
         usec_t speed_meter_usec_new;
         usec_t speed_meter_usec_old;
+
+        bool dhcp4_prefix_root_cannot_set_table;
 };
 
 int manager_new(Manager **ret);
index 11e541e0932fef56acdfa4988d57cb29a7b8c7b6..689b1a123ebbcdfe9e901c3a66b13da62654ad4d 100644 (file)
@@ -167,10 +167,12 @@ DHCPv4.IAID,                            config_parse_iaid,
 DHCPv4.ListenPort,                      config_parse_uint16,                             0,                             offsetof(Network, dhcp_client_port)
 DHCPv4.SendRelease,                     config_parse_bool,                               0,                             offsetof(Network, dhcp_send_release)
 DHCPv4.BlackList,                       config_parse_dhcp_black_listed_ip_address,       0,                             0
+DHCPv4.IPServiceType,                   config_parse_ip_service_type,                    0,                             offsetof(Network, ip_service_type)
 DHCPv6.UseDNS,                          config_parse_bool,                               0,                             offsetof(Network, dhcp6_use_dns)
 DHCPv6.UseNTP,                          config_parse_bool,                               0,                             offsetof(Network, dhcp6_use_ntp)
 DHCPv6.RapidCommit,                     config_parse_bool,                               0,                             offsetof(Network, rapid_commit)
 DHCPv6.ForceDHCPv6PDOtherInformation,   config_parse_bool,                               0,                             offsetof(Network, dhcp6_force_pd_other_information)
+DHCPv6.PrefixDelegationHint,            config_parse_dhcp6_pd_hint,                    0,                             0
 IPv6AcceptRA.UseAutonomousPrefix,       config_parse_bool,                               0,                             offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
 IPv6AcceptRA.UseOnLinkPrefix,           config_parse_bool,                               0,                             offsetof(Network, ipv6_accept_ra_use_onlink_prefix)
 IPv6AcceptRA.UseDNS,                    config_parse_bool,                               0,                             offsetof(Network, ipv6_accept_ra_use_dns)
index a2cd7f4c602f1d2295bc4cd057fda07a78353feb..3ea76a034a6edf4d1aa7a1e3d2d01c52e08cdfe6 100644 (file)
@@ -268,13 +268,11 @@ int network_verify(Network *network) {
                         /* CriticalConnection=yes also preserve foreign static configurations. */
                         network->keep_configuration = KEEP_CONFIGURATION_YES;
                 else
-                        /* For backward compatibility, we do not release DHCP addresses on manager stop. */
-                        network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
+                        network->keep_configuration = KEEP_CONFIGURATION_NO;
         }
 
         if (network->keep_configuration < 0)
-                /* For backward compatibility, we do not release DHCP addresses on manager stop. */
-                network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
+                network->keep_configuration = KEEP_CONFIGURATION_NO;
 
         LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
                 if (address_section_verify(address) < 0)
@@ -373,6 +371,7 @@ int network_load_one(Manager *manager, const char *filename) {
                 .dhcp_use_routes = true,
                 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
                 .dhcp_send_hostname = true,
+                .dhcp_send_release = true,
                 /* To enable/disable RFC7844 Anonymity Profiles */
                 .dhcp_anonymize = false,
                 .dhcp_route_metric = DHCP_ROUTE_METRIC,
@@ -442,6 +441,7 @@ int network_load_one(Manager *manager, const char *filename) {
                 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
 
                 .can_triple_sampling = -1,
+                .ip_service_type = -1,
         };
 
         r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
index 837206a29cabc4371adbd056080904fe9f7e92f8..35469c05edf25d74c113b39ee309a107cd7fe837 100644 (file)
@@ -104,10 +104,13 @@ struct Network {
         DHCPUseDomains dhcp_use_domains;
         Set *dhcp_black_listed_ip;
         Set *dhcp_request_options;
+        int ip_service_type;
 
         /* DHCPv6 Client support*/
         bool dhcp6_use_dns;
         bool dhcp6_use_ntp;
+        uint8_t dhcp6_pd_length;
+        struct in6_addr dhcp6_pd_address;
 
         /* DHCP Server Support */
         bool dhcp_server;
index 0462b4641307f1fb84a5813c7db4300d50579013..f5048d9473cb2c11c53b4077af2718911090ae7e 100644 (file)
@@ -3,6 +3,7 @@
 #include <sys/mount.h>
 
 #include "alloc-util.h"
+#include "cgroup-setup.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
index ebf4f0f523c989d64724967b68996d317ce9c92c..0589685afe308fff8a92a990a86c5340c11f68e3 100644 (file)
@@ -53,6 +53,12 @@ int stub_pid1(sd_id128_t uuid) {
         assert_se(sigfillset(&fullmask) >= 0);
         assert_se(sigprocmask(SIG_BLOCK, &fullmask, &oldmask) >= 0);
 
+        /* Surrender the terminal this stub may control so that child processes can have a controlling terminal
+         * without resorting to setsid hacks. */
+        r = ioctl(STDIN_FILENO, TIOCNOTTY);
+        if (r < 0 && errno != ENOTTY)
+                return log_error_errno(errno, "Failed to surrender controlling terminal: %m");
+
         pid = fork();
         if (pid < 0)
                 return log_error_errno(errno, "Failed to fork child pid: %m");
index 2aec8041f007923a6c27719aa65b8a25210ff3a8..0cd960157ce34b06abd04b6114f510700ca17d0c 100644 (file)
@@ -412,15 +412,27 @@ static int custom_mount_check_all(void) {
 }
 
 static int detect_unified_cgroup_hierarchy_from_environment(void) {
-        const char *e;
+        const char *e, *var = "SYSTEMD_NSPAWN_UNIFIED_HIERARCHY";
         int r;
 
         /* Allow the user to control whether the unified hierarchy is used */
-        e = getenv("UNIFIED_CGROUP_HIERARCHY");
-        if (e) {
+
+        e = getenv(var);
+        if (!e) {
+                static bool warned = false;
+
+                var = "UNIFIED_CGROUP_HIERARCHY";
+                e = getenv(var);
+                if (e && !warned) {
+                        log_info("$UNIFIED_CGROUP_HIERARCHY has been renamed to $SYSTEMD_NSPAWN_UNIFIED_HIERARCHY.");
+                        warned = true;
+                }
+        }
+
+        if (!isempty(e)) {
                 r = parse_boolean(e);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to parse $UNIFIED_CGROUP_HIERARCHY.");
+                        return log_error_errno(r, "Failed to parse $%s: %m", var);
                 if (r > 0)
                         arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL;
                 else
@@ -433,8 +445,8 @@ static int detect_unified_cgroup_hierarchy_from_environment(void) {
 static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
         int r;
 
-        /* Let's inherit the mode to use from the host system, but let's take into consideration what systemd in the
-         * image actually supports. */
+        /* Let's inherit the mode to use from the host system, but let's take into consideration what systemd
+         * in the image actually supports. */
         r = cg_all_unified();
         if (r < 0)
                 return log_error_errno(r, "Failed to determine whether we are in all unified mode.");
@@ -467,58 +479,66 @@ static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
         return 0;
 }
 
-static void parse_share_ns_env(const char *name, unsigned long ns_flag) {
+static int parse_share_ns_env(const char *name, unsigned long ns_flag) {
         int r;
 
         r = getenv_bool(name);
         if (r == -ENXIO)
-                return;
+                return 0;
         if (r < 0)
-                log_warning_errno(r, "Failed to parse %s from environment, defaulting to false.", name);
+                return log_error_errno(r, "Failed to parse $%s: %m", name);
 
         arg_clone_ns_flags = (arg_clone_ns_flags & ~ns_flag) | (r > 0 ? 0 : ns_flag);
         arg_settings_mask |= SETTING_CLONE_NS_FLAGS;
+        return 0;
 }
 
-static void parse_mount_settings_env(void) {
+static int parse_mount_settings_env(void) {
         const char *e;
         int r;
 
         r = getenv_bool("SYSTEMD_NSPAWN_TMPFS_TMP");
+        if (r < 0 && r != -ENXIO)
+                return log_error_errno(r, "Failed to parse $SYSTEMD_NSPAWN_TMPFS_TMP: %m");
         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)
-                return;
-
-        if (streq(e, "network")) {
+        if (streq_ptr(e, "network"))
                 arg_mount_settings |= MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_APIVFS_NETNS;
-                return;
-        }
 
-        r = parse_boolean(e);
-        if (r < 0) {
-                log_warning_errno(r, "Failed to parse SYSTEMD_NSPAWN_API_VFS_WRITABLE from environment, ignoring.");
-                return;
+        else if (e) {
+                r = parse_boolean(e);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse $SYSTEMD_NSPAWN_API_VFS_WRITABLE: %m");
+
+                SET_FLAG(arg_mount_settings, MOUNT_APPLY_APIVFS_RO, r == 0);
+                SET_FLAG(arg_mount_settings, MOUNT_APPLY_APIVFS_NETNS, false);
         }
 
-        SET_FLAG(arg_mount_settings, MOUNT_APPLY_APIVFS_RO, r == 0);
-        SET_FLAG(arg_mount_settings, MOUNT_APPLY_APIVFS_NETNS, false);
+        return 0;
 }
 
-static void parse_environment(void) {
+static int parse_environment(void) {
         const char *e;
         int r;
 
-        parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_IPC", CLONE_NEWIPC);
-        parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_PID", CLONE_NEWPID);
-        parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_UTS", CLONE_NEWUTS);
-        parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_SYSTEM", CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS);
+        r = parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_IPC", CLONE_NEWIPC);
+        if (r < 0)
+                return r;
+        r = parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_PID", CLONE_NEWPID);
+        if (r < 0)
+                return r;
+        r = parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_UTS", CLONE_NEWUTS);
+        if (r < 0)
+                return r;
+        r = parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_SYSTEM", CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS);
+        if (r < 0)
+                return r;
 
-        parse_mount_settings_env();
+        r = parse_mount_settings_env();
+        if (r < 0)
+                return r;
 
         /* SYSTEMD_NSPAWN_USE_CGNS=0 can be used to disable CLONE_NEWCGROUP use,
          * even if it is supported. If not supported, it has no effect. */
@@ -528,7 +548,7 @@ static void parse_environment(void) {
                 r = getenv_bool("SYSTEMD_NSPAWN_USE_CGNS");
                 if (r < 0) {
                         if (r != -ENXIO)
-                                log_warning_errno(r, "Failed to parse $SYSTEMD_NSPAWN_USE_CGNS, ignoring: %m");
+                                return log_error_errno(r, "Failed to parse $SYSTEMD_NSPAWN_USE_CGNS: %m");
 
                         arg_use_cgns = true;
                 } else {
@@ -541,7 +561,7 @@ static void parse_environment(void) {
         if (e)
                 arg_container_service_name = e;
 
-        detect_unified_cgroup_hierarchy_from_environment();
+        return detect_unified_cgroup_hierarchy_from_environment();
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -1424,7 +1444,9 @@ static int parse_argv(int argc, char *argv[]) {
         arg_caps_retain = (arg_caps_retain | plus | (arg_private_network ? UINT64_C(1) << CAP_NET_ADMIN : 0)) & ~minus;
 
         /* Make sure to parse environment before we reset the settings mask below */
-        parse_environment();
+        r = parse_environment();
+        if (r < 0)
+                return r;
 
         /* Load all settings from .nspawn files */
         if (mask_no_settings)
@@ -1440,6 +1462,25 @@ static int parse_argv(int argc, char *argv[]) {
 static int verify_arguments(void) {
         int r;
 
+        if (arg_start_mode == START_PID2 && arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) {
+                /* If we are running the stub init in the container, we don't need to look at what the init
+                 * in the container supports, because we are not using it. Let's immediately pick the right
+                 * setting based on the host system configuration.
+                 *
+                 * We only do this, if the user didn't use an environment variable to override the detection.
+                 */
+
+                r = cg_all_unified();
+                if (r < 0)
+                        return log_error_errno(r, "Failed to determine whether we are in all unified mode.");
+                if (r > 0)
+                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL;
+                else if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0)
+                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_SYSTEMD;
+                else
+                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE;
+        }
+
         if (arg_userns_mode != USER_NAMESPACE_NO)
                 arg_mount_settings |= MOUNT_USE_USERNS;
 
@@ -4720,7 +4761,7 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
-        r = cg_unified_flush();
+        r = cg_unified();
         if (r < 0) {
                 log_error_errno(r, "Failed to determine whether the unified cgroups hierarchy is used: %m");
                 goto finish;
@@ -4730,9 +4771,8 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
-        r = detect_unified_cgroup_hierarchy_from_environment();
-        if (r < 0)
-                goto finish;
+        /* Reapply environment settings. */
+        (void) detect_unified_cgroup_hierarchy_from_environment();
 
         /* Ignore SIGPIPE here, because we use splice() on the ptyfwd stuff and that will generate SIGPIPE if
          * the result is closed. Note that the container payload child will reset signal mask+handler anyway,
index b50f0990d842d5044e0baf3c734ea0a8c17107d1..a6829629b49c8c59ee95c62d8b3e2f0ee9ad0d7e 100644 (file)
@@ -5,8 +5,8 @@
 #include "log.h"
 #include "nspawn-patch-uid.h"
 #include "user-util.h"
+#include "string-util.h"
 #include "tests.h"
-#include "util.h"
 
 int main(int argc, char *argv[]) {
         uid_t shift, range;
index f9d309c909a7ecddc235948b09187dc2e2f3d2ad..501982819aa2e9d967b5fefabdca2964c5031dff 100644 (file)
 #include "fd-util.h"
 #include "fileio.h"
 #include "io-util.h"
+#include "list.h"
 #include "main-func.h"
 #include "mkdir.h"
 #include "parse-util.h"
-#include "proc-cmdline.h"
+#include "reboot-util.h"
 #include "string-table.h"
 #include "string-util.h"
 #include "udev-util.h"
 #include "util.h"
-#include "list.h"
 
 /* Note that any write is delayed until exit and the rfkill state will not be
  * stored for rfkill indices that disappear after a change. */
index bcbb86d1b1e76975edc82d340ba2b32d887ed1ac..4ce146033d5227e1feea42c55bbb7b93ac13f56a 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "acpi-fpdt.h"
 #include "boot-timestamps.h"
-#include "efivars.h"
+#include "efi-loader.h"
 #include "macro.h"
 #include "time-util.h"
 
index 355b1bebf610ac09ad38cfc356656a64543ca041..4f750dc1da1b50c282576429529bd0024a3b2b63 100644 (file)
@@ -15,6 +15,7 @@
 #include "device-nodes.h"
 #include "dirent-util.h"
 #include "efivars.h"
+#include "efi-loader.h"
 #include "env-file.h"
 #include "env-util.h"
 #include "fd-util.h"
@@ -475,6 +476,7 @@ static int boot_entries_find_unified(
                 _cleanup_free_ char *j = NULL, *osrelease = NULL, *cmdline = NULL;
                 _cleanup_close_ int fd = -1;
 
+                dirent_ensure_type(d, de);
                 if (!dirent_is_file(de))
                         continue;
 
index 2cd5adfd30c90575db957c2141adbd8b3bab4129..0992ffac3a80e3414dd44eb165663afdfa823f80 100644 (file)
@@ -5,6 +5,7 @@
 #include "bus-unit-util.h"
 #include "bus-util.h"
 #include "cap-list.h"
+#include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "condition.h"
 #include "cpu-set-util.h"
@@ -1355,15 +1356,12 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
 static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
 
         if (streq(field, "KillMode"))
-
                 return bus_append_string(m, field, eq);
 
         if (STR_IN_SET(field, "SendSIGHUP", "SendSIGKILL"))
-
                 return bus_append_parse_boolean(m, field, eq);
 
-        if (STR_IN_SET(field, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
-
+        if (STR_IN_SET(field, "KillSignal", "RestartKillSignal", "FinalKillSignal", "WatchdogSignal"))
                 return bus_append_signal_from_string(m, field, eq);
 
         return 0;
diff --git a/src/shared/cgroup-setup.c b/src/shared/cgroup-setup.c
new file mode 100644 (file)
index 0000000..ddcd156
--- /dev/null
@@ -0,0 +1,860 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <ftw.h>
+#include <unistd.h>
+
+#include "cgroup-setup.h"
+#include "cgroup-util.h"
+#include "errno-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "fs-util.h"
+#include "mkdir.h"
+#include "process-util.h"
+#include "fileio.h"
+#include "user-util.h"
+#include "fd-util.h"
+
+bool cg_is_unified_wanted(void) {
+        static thread_local int wanted = -1;
+        bool b;
+        const bool is_default = DEFAULT_HIERARCHY == CGROUP_UNIFIED_ALL;
+        _cleanup_free_ char *c = NULL;
+        int r;
+
+        /* If we have a cached value, return that. */
+        if (wanted >= 0)
+                return wanted;
+
+        /* If the hierarchy is already mounted, then follow whatever was chosen for it. */
+        r = cg_unified_cached(true);
+        if (r >= 0)
+                return (wanted = r >= CGROUP_UNIFIED_ALL);
+
+        /* If we were explicitly passed systemd.unified_cgroup_hierarchy, respect that. */
+        r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", &b);
+        if (r > 0)
+                return (wanted = b);
+
+        /* If we passed cgroup_no_v1=all with no other instructions, it seems highly unlikely that we want to
+         * use hybrid or legacy hierarchy. */
+        r = proc_cmdline_get_key("cgroup_no_v1", 0, &c);
+        if (r > 0 && streq_ptr(c, "all"))
+                return (wanted = true);
+
+        return (wanted = is_default);
+}
+
+bool cg_is_legacy_wanted(void) {
+        static thread_local int wanted = -1;
+
+        /* If we have a cached value, return that. */
+        if (wanted >= 0)
+                return wanted;
+
+        /* Check if we have cgroup v2 already mounted. */
+        if (cg_unified_cached(true) == CGROUP_UNIFIED_ALL)
+                return (wanted = false);
+
+        /* Otherwise, assume that at least partial legacy is wanted,
+         * since cgroup v2 should already be mounted at this point. */
+        return (wanted = true);
+}
+
+bool cg_is_hybrid_wanted(void) {
+        static thread_local int wanted = -1;
+        int r;
+        bool b;
+        const bool is_default = DEFAULT_HIERARCHY >= CGROUP_UNIFIED_SYSTEMD;
+        /* We default to true if the default is "hybrid", obviously, but also when the default is "unified",
+         * because if we get called, it means that unified hierarchy was not mounted. */
+
+        /* If we have a cached value, return that. */
+        if (wanted >= 0)
+                return wanted;
+
+        /* If the hierarchy is already mounted, then follow whatever was chosen for it. */
+        if (cg_unified_cached(true) == CGROUP_UNIFIED_ALL)
+                return (wanted = false);
+
+        /* Otherwise, let's see what the kernel command line has to say.  Since checking is expensive, cache
+         * a non-error result. */
+        r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", &b);
+
+        /* The meaning of the kernel option is reversed wrt. to the return value of this function, hence the
+         * negation. */
+        return (wanted = r > 0 ? !b : is_default);
+}
+
+int cg_weight_parse(const char *s, uint64_t *ret) {
+        uint64_t u;
+        int r;
+
+        if (isempty(s)) {
+                *ret = CGROUP_WEIGHT_INVALID;
+                return 0;
+        }
+
+        r = safe_atou64(s, &u);
+        if (r < 0)
+                return r;
+
+        if (u < CGROUP_WEIGHT_MIN || u > CGROUP_WEIGHT_MAX)
+                return -ERANGE;
+
+        *ret = u;
+        return 0;
+}
+
+int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
+        uint64_t u;
+        int r;
+
+        if (isempty(s)) {
+                *ret = CGROUP_CPU_SHARES_INVALID;
+                return 0;
+        }
+
+        r = safe_atou64(s, &u);
+        if (r < 0)
+                return r;
+
+        if (u < CGROUP_CPU_SHARES_MIN || u > CGROUP_CPU_SHARES_MAX)
+                return -ERANGE;
+
+        *ret = u;
+        return 0;
+}
+
+int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
+        uint64_t u;
+        int r;
+
+        if (isempty(s)) {
+                *ret = CGROUP_BLKIO_WEIGHT_INVALID;
+                return 0;
+        }
+
+        r = safe_atou64(s, &u);
+        if (r < 0)
+                return r;
+
+        if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX)
+                return -ERANGE;
+
+        *ret = u;
+        return 0;
+}
+
+
+static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
+        assert(path);
+        assert(sb);
+        assert(ftwbuf);
+
+        if (typeflag != FTW_DP)
+                return 0;
+
+        if (ftwbuf->level < 1)
+                return 0;
+
+        (void) rmdir(path);
+        return 0;
+}
+
+int cg_trim(const char *controller, const char *path, bool delete_root) {
+        _cleanup_free_ char *fs = NULL;
+        int r = 0, q;
+
+        assert(path);
+
+        r = cg_get_path(controller, path, NULL, &fs);
+        if (r < 0)
+                return r;
+
+        errno = 0;
+        if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) {
+                if (errno == ENOENT)
+                        r = 0;
+                else
+                        r = errno_or_else(EIO);
+        }
+
+        if (delete_root) {
+                if (rmdir(fs) < 0 && errno != ENOENT)
+                        return -errno;
+        }
+
+        q = cg_hybrid_unified();
+        if (q < 0)
+                return q;
+        if (q > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
+                q = cg_trim(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, delete_root);
+                if (q < 0)
+                        log_warning_errno(q, "Failed to trim compat systemd cgroup %s: %m", path);
+        }
+
+        return r;
+}
+
+/* Create a cgroup in the hierarchy of controller.
+ * Returns 0 if the group already existed, 1 on success, negative otherwise.
+ */
+int cg_create(const char *controller, const char *path) {
+        _cleanup_free_ char *fs = NULL;
+        int r;
+
+        r = cg_get_path_and_check(controller, path, NULL, &fs);
+        if (r < 0)
+                return r;
+
+        r = mkdir_parents(fs, 0755);
+        if (r < 0)
+                return r;
+
+        r = mkdir_errno_wrapper(fs, 0755);
+        if (r == -EEXIST)
+                return 0;
+        if (r < 0)
+                return r;
+
+        r = cg_hybrid_unified();
+        if (r < 0)
+                return r;
+
+        if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
+                r = cg_create(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to create compat systemd cgroup %s: %m", path);
+        }
+
+        return 1;
+}
+
+int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
+        int r, q;
+
+        assert(pid >= 0);
+
+        r = cg_create(controller, path);
+        if (r < 0)
+                return r;
+
+        q = cg_attach(controller, path, pid);
+        if (q < 0)
+                return q;
+
+        /* This does not remove the cgroup on failure */
+        return r;
+}
+
+int cg_attach(const char *controller, const char *path, pid_t pid) {
+        _cleanup_free_ char *fs = NULL;
+        char c[DECIMAL_STR_MAX(pid_t) + 2];
+        int r;
+
+        assert(path);
+        assert(pid >= 0);
+
+        r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
+        if (r < 0)
+                return r;
+
+        if (pid == 0)
+                pid = getpid_cached();
+
+        xsprintf(c, PID_FMT "\n", pid);
+
+        r = write_string_file(fs, c, WRITE_STRING_FILE_DISABLE_BUFFER);
+        if (r < 0)
+                return r;
+
+        r = cg_hybrid_unified();
+        if (r < 0)
+                return r;
+
+        if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
+                r = cg_attach(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, pid);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to attach "PID_FMT" to compat systemd cgroup %s: %m", pid, path);
+        }
+
+        return 0;
+}
+
+int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
+        int r;
+
+        assert(controller);
+        assert(path);
+        assert(pid >= 0);
+
+        r = cg_attach(controller, path, pid);
+        if (r < 0) {
+                char prefix[strlen(path) + 1];
+
+                /* This didn't work? Then let's try all prefixes of
+                 * the destination */
+
+                PATH_FOREACH_PREFIX(prefix, path) {
+                        int q;
+
+                        q = cg_attach(controller, prefix, pid);
+                        if (q >= 0)
+                                return q;
+                }
+        }
+
+        return r;
+}
+
+int cg_set_access(
+                const char *controller,
+                const char *path,
+                uid_t uid,
+                gid_t gid) {
+
+        struct Attribute {
+                const char *name;
+                bool fatal;
+        };
+
+        /* cgroup v1, aka legacy/non-unified */
+        static const struct Attribute legacy_attributes[] = {
+                { "cgroup.procs",           true  },
+                { "tasks",                  false },
+                { "cgroup.clone_children",  false },
+                {},
+        };
+
+        /* cgroup v2, aka unified */
+        static const struct Attribute unified_attributes[] = {
+                { "cgroup.procs",           true  },
+                { "cgroup.subtree_control", true  },
+                { "cgroup.threads",         false },
+                {},
+        };
+
+        static const struct Attribute* const attributes[] = {
+                [false] = legacy_attributes,
+                [true]  = unified_attributes,
+        };
+
+        _cleanup_free_ char *fs = NULL;
+        const struct Attribute *i;
+        int r, unified;
+
+        assert(path);
+
+        if (uid == UID_INVALID && gid == GID_INVALID)
+                return 0;
+
+        unified = cg_unified_controller(controller);
+        if (unified < 0)
+                return unified;
+
+        /* Configure access to the cgroup itself */
+        r = cg_get_path(controller, path, NULL, &fs);
+        if (r < 0)
+                return r;
+
+        r = chmod_and_chown(fs, 0755, uid, gid);
+        if (r < 0)
+                return r;
+
+        /* Configure access to the cgroup's attributes */
+        for (i = attributes[unified]; i->name; i++) {
+                fs = mfree(fs);
+
+                r = cg_get_path(controller, path, i->name, &fs);
+                if (r < 0)
+                        return r;
+
+                r = chmod_and_chown(fs, 0644, uid, gid);
+                if (r < 0) {
+                        if (i->fatal)
+                                return r;
+
+                        log_debug_errno(r, "Failed to set access on cgroup %s, ignoring: %m", fs);
+                }
+        }
+
+        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
+                r = cg_hybrid_unified();
+                if (r < 0)
+                        return r;
+                if (r > 0) {
+                        /* Always propagate access mode from unified to legacy controller */
+                        r = cg_set_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, uid, gid);
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to set access on compatibility systemd cgroup %s, ignoring: %m", path);
+                }
+        }
+
+        return 0;
+}
+
+int cg_migrate(
+                const char *cfrom,
+                const char *pfrom,
+                const char *cto,
+                const char *pto,
+                CGroupFlags flags) {
+
+        bool done = false;
+        _cleanup_set_free_ Set *s = NULL;
+        int r, ret = 0;
+        pid_t my_pid;
+
+        assert(cfrom);
+        assert(pfrom);
+        assert(cto);
+        assert(pto);
+
+        s = set_new(NULL);
+        if (!s)
+                return -ENOMEM;
+
+        my_pid = getpid_cached();
+
+        do {
+                _cleanup_fclose_ FILE *f = NULL;
+                pid_t pid = 0;
+                done = true;
+
+                r = cg_enumerate_processes(cfrom, pfrom, &f);
+                if (r < 0) {
+                        if (ret >= 0 && r != -ENOENT)
+                                return r;
+
+                        return ret;
+                }
+
+                while ((r = cg_read_pid(f, &pid)) > 0) {
+
+                        /* This might do weird stuff if we aren't a
+                         * single-threaded program. However, we
+                         * luckily know we are not */
+                        if ((flags & CGROUP_IGNORE_SELF) && pid == my_pid)
+                                continue;
+
+                        if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
+                                continue;
+
+                        /* Ignore kernel threads. Since they can only
+                         * exist in the root cgroup, we only check for
+                         * them there. */
+                        if (cfrom &&
+                            empty_or_root(pfrom) &&
+                            is_kernel_thread(pid) > 0)
+                                continue;
+
+                        r = cg_attach(cto, pto, pid);
+                        if (r < 0) {
+                                if (ret >= 0 && r != -ESRCH)
+                                        ret = r;
+                        } else if (ret == 0)
+                                ret = 1;
+
+                        done = false;
+
+                        r = set_put(s, PID_TO_PTR(pid));
+                        if (r < 0) {
+                                if (ret >= 0)
+                                        return r;
+
+                                return ret;
+                        }
+                }
+
+                if (r < 0) {
+                        if (ret >= 0)
+                                return r;
+
+                        return ret;
+                }
+        } while (!done);
+
+        return ret;
+}
+
+int cg_migrate_recursive(
+                const char *cfrom,
+                const char *pfrom,
+                const char *cto,
+                const char *pto,
+                CGroupFlags flags) {
+
+        _cleanup_closedir_ DIR *d = NULL;
+        int r, ret = 0;
+        char *fn;
+
+        assert(cfrom);
+        assert(pfrom);
+        assert(cto);
+        assert(pto);
+
+        ret = cg_migrate(cfrom, pfrom, cto, pto, flags);
+
+        r = cg_enumerate_subgroups(cfrom, pfrom, &d);
+        if (r < 0) {
+                if (ret >= 0 && r != -ENOENT)
+                        return r;
+
+                return ret;
+        }
+
+        while ((r = cg_read_subgroup(d, &fn)) > 0) {
+                _cleanup_free_ char *p = NULL;
+
+                p = path_join(empty_to_root(pfrom), fn);
+                free(fn);
+                if (!p)
+                        return -ENOMEM;
+
+                r = cg_migrate_recursive(cfrom, p, cto, pto, flags);
+                if (r != 0 && ret >= 0)
+                        ret = r;
+        }
+
+        if (r < 0 && ret >= 0)
+                ret = r;
+
+        if (flags & CGROUP_REMOVE) {
+                r = cg_rmdir(cfrom, pfrom);
+                if (r < 0 && ret >= 0 && !IN_SET(r, -ENOENT, -EBUSY))
+                        return r;
+        }
+
+        return ret;
+}
+
+int cg_migrate_recursive_fallback(
+                const char *cfrom,
+                const char *pfrom,
+                const char *cto,
+                const char *pto,
+                CGroupFlags flags) {
+
+        int r;
+
+        assert(cfrom);
+        assert(pfrom);
+        assert(cto);
+        assert(pto);
+
+        r = cg_migrate_recursive(cfrom, pfrom, cto, pto, flags);
+        if (r < 0) {
+                char prefix[strlen(pto) + 1];
+
+                /* This didn't work? Then let's try all prefixes of the destination */
+
+                PATH_FOREACH_PREFIX(prefix, pto) {
+                        int q;
+
+                        q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, flags);
+                        if (q >= 0)
+                                return q;
+                }
+        }
+
+        return r;
+}
+
+int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {
+        CGroupController c;
+        CGroupMask done;
+        bool created;
+        int r;
+
+        /* This one will create a cgroup in our private tree, but also
+         * duplicate it in the trees specified in mask, and remove it
+         * in all others.
+         *
+         * Returns 0 if the group already existed in the systemd hierarchy,
+         * 1 on success, negative otherwise.
+         */
+
+        /* First create the cgroup in our own hierarchy. */
+        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
+        if (r < 0)
+                return r;
+        created = r;
+
+        /* If we are in the unified hierarchy, we are done now */
+        r = cg_all_unified();
+        if (r < 0)
+                return r;
+        if (r > 0)
+                return created;
+
+        supported &= CGROUP_MASK_V1;
+        mask = CGROUP_MASK_EXTEND_JOINED(mask);
+        done = 0;
+
+        /* Otherwise, do the same in the other hierarchies */
+        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
+                const char *n;
+
+                if (!FLAGS_SET(supported, bit))
+                        continue;
+
+                if (FLAGS_SET(done, bit))
+                        continue;
+
+                n = cgroup_controller_to_string(c);
+                if (FLAGS_SET(mask, bit))
+                        (void) cg_create(n, path);
+                else
+                        (void) cg_trim(n, path, true);
+
+                done |= CGROUP_MASK_EXTEND_JOINED(bit);
+        }
+
+        return created;
+}
+
+int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
+        CGroupController c;
+        CGroupMask done;
+        int r;
+
+        r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
+        if (r < 0)
+                return r;
+
+        r = cg_all_unified();
+        if (r < 0)
+                return r;
+        if (r > 0)
+                return 0;
+
+        supported &= CGROUP_MASK_V1;
+        done = 0;
+
+        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
+                const char *p = NULL;
+
+                if (!FLAGS_SET(supported, bit))
+                        continue;
+
+                if (FLAGS_SET(done, bit))
+                        continue;
+
+                if (path_callback)
+                        p = path_callback(bit, userdata);
+                if (!p)
+                        p = path;
+
+                (void) cg_attach_fallback(cgroup_controller_to_string(c), p, pid);
+                done |= CGROUP_MASK_EXTEND_JOINED(bit);
+        }
+
+        return 0;
+}
+
+int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
+        Iterator i;
+        void *pidp;
+        int r = 0;
+
+        SET_FOREACH(pidp, pids, i) {
+                pid_t pid = PTR_TO_PID(pidp);
+                int q;
+
+                q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
+                if (q < 0 && r >= 0)
+                        r = q;
+        }
+
+        return r;
+}
+
+int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
+        CGroupController c;
+        CGroupMask done;
+        int r = 0, q;
+
+        if (!path_equal(from, to))  {
+                r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, CGROUP_REMOVE);
+                if (r < 0)
+                        return r;
+        }
+
+        q = cg_all_unified();
+        if (q < 0)
+                return q;
+        if (q > 0)
+                return r;
+
+        supported &= CGROUP_MASK_V1;
+        done = 0;
+
+        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
+                const char *p = NULL;
+
+                if (!FLAGS_SET(supported, bit))
+                        continue;
+
+                if (FLAGS_SET(done, bit))
+                        continue;
+
+                if (to_callback)
+                        p = to_callback(bit, userdata);
+                if (!p)
+                        p = to;
+
+                (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, 0);
+                done |= CGROUP_MASK_EXTEND_JOINED(bit);
+        }
+
+        return r;
+}
+
+int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
+        CGroupController c;
+        CGroupMask done;
+        int r, q;
+
+        r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
+        if (r < 0)
+                return r;
+
+        q = cg_all_unified();
+        if (q < 0)
+                return q;
+        if (q > 0)
+                return r;
+
+        supported &= CGROUP_MASK_V1;
+        done = 0;
+
+        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
+
+                if (!FLAGS_SET(supported, bit))
+                        continue;
+
+                if (FLAGS_SET(done, bit))
+                        continue;
+
+                (void) cg_trim(cgroup_controller_to_string(c), path, delete_root);
+                done |= CGROUP_MASK_EXTEND_JOINED(bit);
+        }
+
+        return r;
+}
+
+int cg_enable_everywhere(
+                CGroupMask supported,
+                CGroupMask mask,
+                const char *p,
+                CGroupMask *ret_result_mask) {
+
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *fs = NULL;
+        CGroupController c;
+        CGroupMask ret = 0;
+        int r;
+
+        assert(p);
+
+        if (supported == 0) {
+                if (ret_result_mask)
+                        *ret_result_mask = 0;
+                return 0;
+        }
+
+        r = cg_all_unified();
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                /* On the legacy hierarchy there's no concept of "enabling" controllers in cgroups defined. Let's claim
+                 * complete success right away. (If you wonder why we return the full mask here, rather than zero: the
+                 * caller tends to use the returned mask later on to compare if all controllers where properly joined,
+                 * and if not requeues realization. This use is the primary purpose of the return value, hence let's
+                 * minimize surprises here and reduce triggers for re-realization by always saying we fully
+                 * succeeded.) */
+                if (ret_result_mask)
+                        *ret_result_mask = mask & supported & CGROUP_MASK_V2; /* If you wonder why we mask this with
+                                                                               * CGROUP_MASK_V2: The 'supported' mask
+                                                                               * might contain pure-V1 or BPF
+                                                                               * controllers, and we never want to
+                                                                               * claim that we could enable those with
+                                                                               * cgroup.subtree_control */
+                return 0;
+        }
+
+        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, p, "cgroup.subtree_control", &fs);
+        if (r < 0)
+                return r;
+
+        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
+                const char *n;
+
+                if (!FLAGS_SET(CGROUP_MASK_V2, bit))
+                        continue;
+
+                if (!FLAGS_SET(supported, bit))
+                        continue;
+
+                n = cgroup_controller_to_string(c);
+                {
+                        char s[1 + strlen(n) + 1];
+
+                        s[0] = FLAGS_SET(mask, bit) ? '+' : '-';
+                        strcpy(s + 1, n);
+
+                        if (!f) {
+                                f = fopen(fs, "we");
+                                if (!f)
+                                        return log_debug_errno(errno, "Failed to open cgroup.subtree_control file of %s: %m", p);
+                        }
+
+                        r = write_string_stream(f, s, WRITE_STRING_FILE_DISABLE_BUFFER);
+                        if (r < 0) {
+                                log_debug_errno(r, "Failed to %s controller %s for %s (%s): %m",
+                                                FLAGS_SET(mask, bit) ? "enable" : "disable", n, p, fs);
+                                clearerr(f);
+
+                                /* If we can't turn off a controller, leave it on in the reported resulting mask. This
+                                 * happens for example when we attempt to turn off a controller up in the tree that is
+                                 * used down in the tree. */
+                                if (!FLAGS_SET(mask, bit) && r == -EBUSY) /* You might wonder why we check for EBUSY
+                                                                           * only here, and not follow the same logic
+                                                                           * for other errors such as EINVAL or
+                                                                           * EOPNOTSUPP or anything else. That's
+                                                                           * because EBUSY indicates that the
+                                                                           * controllers is currently enabled and
+                                                                           * cannot be disabled because something down
+                                                                           * the hierarchy is still using it. Any other
+                                                                           * error most likely means something like "I
+                                                                           * never heard of this controller" or
+                                                                           * similar. In the former case it's hence
+                                                                           * safe to assume the controller is still on
+                                                                           * after the failed operation, while in the
+                                                                           * latter case it's safer to assume the
+                                                                           * controller is unknown and hence certainly
+                                                                           * not enabled. */
+                                        ret |= bit;
+                        } else {
+                                /* Otherwise, if we managed to turn on a controller, set the bit reflecting that. */
+                                if (FLAGS_SET(mask, bit))
+                                        ret |= bit;
+                        }
+                }
+        }
+
+        /* Let's return the precise set of controllers now enabled for the cgroup. */
+        if (ret_result_mask)
+                *ret_result_mask = ret;
+
+        return 0;
+}
diff --git a/src/shared/cgroup-setup.h b/src/shared/cgroup-setup.h
new file mode 100644 (file)
index 0000000..6e9b685
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "cgroup-util.h"
+
+bool cg_is_unified_wanted(void);
+bool cg_is_legacy_wanted(void);
+bool cg_is_hybrid_wanted(void);
+
+int cg_weight_parse(const char *s, uint64_t *ret);
+int cg_cpu_shares_parse(const char *s, uint64_t *ret);
+int cg_blkio_weight_parse(const char *s, uint64_t *ret);
+
+int cg_trim(const char *controller, const char *path, bool delete_root);
+
+int cg_create(const char *controller, const char *path);
+int cg_attach(const char *controller, const char *path, pid_t pid);
+int cg_attach_fallback(const char *controller, const char *path, pid_t pid);
+int cg_create_and_attach(const char *controller, const char *path, pid_t pid);
+
+int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);
+int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);
+int cg_migrate_recursive_fallback(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);
+
+int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path);
+int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t callback, void *userdata);
+int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t callback, void *userdata);
+int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t callback, void *userdata);
+int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root);
+int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p, CGroupMask *ret_result_mask);
index e5e6c6cc13082632863db14c989afe540ce08d2b..5a5d35bcc383b1c27bcb5580886142f44d75fddf 100644 (file)
@@ -22,7 +22,7 @@
 #include "cgroup-util.h"
 #include "condition.h"
 #include "cpu-set-util.h"
-#include "efivars.h"
+#include "efi-loader.h"
 #include "env-file.h"
 #include "extract-word.h"
 #include "fd-util.h"
index bdc2d046ecc786e6a36b9e9e61845c05a9f446ef..c25b11599c5d85ac39ea5950b1b13c546ccbeff7 100644 (file)
@@ -6,19 +6,6 @@
 
 #include "macro.h"
 
-/* libcryptsetup define for any LUKS version, compatible with libcryptsetup 1.x */
-#ifndef CRYPT_LUKS
-#define CRYPT_LUKS NULL
-#endif
-
-#ifndef CRYPT_ACTIVATE_SAME_CPU_CRYPT
-#define CRYPT_ACTIVATE_SAME_CPU_CRYPT (1 << 6)
-#endif
-
-#ifndef CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS
-#define CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS (1 << 7)
-#endif
-
 DEFINE_TRIVIAL_CLEANUP_FUNC(struct crypt_device *, crypt_free);
 
 void cryptsetup_log_glue(int level, const char *msg, void *usrptr);
similarity index 79%
rename from src/shared/efivars.c
rename to src/shared/efi-loader.c
index 3597ddf4a7522d5511bd7089e87ff6a83fd70682..46e187000f56ca079a8110fd130e84432e735f1c 100644 (file)
@@ -1,30 +1,18 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <linux/fs.h>
-#include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
 #include <unistd.h>
 
-#include "sd-id128.h"
-
 #include "alloc-util.h"
-#include "chattr-util.h"
 #include "dirent-util.h"
+#include "efi-loader.h"
 #include "efivars.h"
 #include "fd-util.h"
 #include "io-util.h"
-#include "macro.h"
 #include "parse-util.h"
 #include "sort-util.h"
 #include "stdio-util.h"
-#include "strv.h"
-#include "time-util.h"
+#include "string-util.h"
 #include "utf8.h"
 #include "virt.h"
 
@@ -193,202 +181,6 @@ int efi_set_reboot_to_firmware(bool value) {
         return 0;
 }
 
-char* efi_variable_path(sd_id128_t vendor, const char *name) {
-        char *p;
-
-        if (asprintf(&p,
-                     "/sys/firmware/efi/efivars/%s-" SD_ID128_UUID_FORMAT_STR,
-                     name, SD_ID128_FORMAT_VAL(vendor)) < 0)
-                return NULL;
-
-        return p;
-}
-
-int efi_get_variable(
-                sd_id128_t vendor,
-                const char *name,
-                uint32_t *ret_attribute,
-                void **ret_value,
-                size_t *ret_size) {
-
-        _cleanup_close_ int fd = -1;
-        _cleanup_free_ char *p = NULL;
-        _cleanup_free_ void *buf = NULL;
-        struct stat st;
-        uint32_t a;
-        ssize_t n;
-
-        assert(name);
-
-        p = efi_variable_path(vendor, name);
-        if (!p)
-                return -ENOMEM;
-
-        if (!ret_value && !ret_size && !ret_attribute) {
-                /* If caller is not interested in anything, just check if the variable exists and is readable
-                 * to us. */
-                if (access(p, R_OK) < 0)
-                        return -errno;
-
-                return 0;
-        }
-
-        fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-        if (st.st_size < 4)
-                return -ENODATA;
-        if (st.st_size > 4*1024*1024 + 4)
-                return -E2BIG;
-
-        if (ret_value || ret_attribute) {
-                n = read(fd, &a, sizeof(a));
-                if (n < 0)
-                        return -errno;
-                if (n != sizeof(a))
-                        return -EIO;
-        }
-
-        if (ret_value) {
-                buf = malloc(st.st_size - 4 + 2);
-                if (!buf)
-                        return -ENOMEM;
-
-                n = read(fd, buf, (size_t) st.st_size - 4);
-                if (n < 0)
-                        return -errno;
-                if (n != st.st_size - 4)
-                        return -EIO;
-
-                /* Always NUL terminate (2 bytes, to protect UTF-16) */
-                ((char*) buf)[st.st_size - 4] = 0;
-                ((char*) buf)[st.st_size - 4 + 1] = 0;
-        }
-
-        /* Note that efivarfs interestingly doesn't require ftruncate() to update an existing EFI variable
-         * with a smaller value. */
-
-        if (ret_attribute)
-                *ret_attribute = a;
-
-        if (ret_value)
-                *ret_value = TAKE_PTR(buf);
-
-        if (ret_size)
-                *ret_size = (size_t) st.st_size - 4;
-
-        return 0;
-}
-
-int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
-        _cleanup_free_ void *s = NULL;
-        size_t ss = 0;
-        int r;
-        char *x;
-
-        r = efi_get_variable(vendor, name, NULL, &s, &ss);
-        if (r < 0)
-                return r;
-
-        x = utf16_to_utf8(s, ss);
-        if (!x)
-                return -ENOMEM;
-
-        *p = x;
-        return 0;
-}
-
-int efi_set_variable(
-                sd_id128_t vendor,
-                const char *name,
-                const void *value,
-                size_t size) {
-
-        struct var {
-                uint32_t attr;
-                char buf[];
-        } _packed_ * _cleanup_free_ buf = NULL;
-        _cleanup_free_ char *p = NULL;
-        _cleanup_close_ int fd = -1;
-        bool saved_flags_valid = false;
-        unsigned saved_flags;
-        int r;
-
-        assert(name);
-        assert(value || size == 0);
-
-        p = efi_variable_path(vendor, name);
-        if (!p)
-                return -ENOMEM;
-
-        /* Newer efivarfs protects variables that are not in a whitelist with FS_IMMUTABLE_FL by default, to protect
-         * them for accidental removal and modification. We are not changing these variables accidentally however,
-         * hence let's unset the bit first. */
-
-        r = chattr_path(p, 0, FS_IMMUTABLE_FL, &saved_flags);
-        if (r < 0 && r != -ENOENT)
-                log_debug_errno(r, "Failed to drop FS_IMMUTABLE_FL flag from '%s', ignoring: %m", p);
-
-        saved_flags_valid = r >= 0;
-
-        if (size == 0) {
-                if (unlink(p) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                return 0;
-        }
-
-        fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
-        if (fd < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        buf = malloc(sizeof(uint32_t) + size);
-        if (!buf) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
-        memcpy(buf->buf, value, size);
-
-        r = loop_write(fd, buf, sizeof(uint32_t) + size, false);
-        if (r < 0)
-                goto finish;
-
-        r = 0;
-
-finish:
-        if (saved_flags_valid) {
-                int q;
-
-                /* Restore the original flags field, just in case */
-                if (fd < 0)
-                        q = chattr_path(p, saved_flags, FS_IMMUTABLE_FL, NULL);
-                else
-                        q = chattr_fd(fd, saved_flags, FS_IMMUTABLE_FL, NULL);
-                if (q < 0)
-                        log_debug_errno(q, "Failed to restore FS_IMMUTABLE_FL on '%s', ignoring: %m", p);
-        }
-
-        return r;
-}
-
-int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *v) {
-        _cleanup_free_ char16_t *u16 = NULL;
-
-        u16 = utf8_to_utf16(v, strlen(v));
-        if (!u16)
-                return -ENOMEM;
-
-        return efi_set_variable(vendor, name, u16, (char16_strlen(u16) + 1) * sizeof(char16_t));
-}
 
 static ssize_t utf16_size(const uint16_t *s, size_t buf_len_bytes) {
         size_t l = 0;
similarity index 61%
rename from src/shared/efivars.h
rename to src/shared/efi-loader.h
index fad129794d2fa52088c1329edc3bb9c1820f3aa3..7d41fbb3593608b2128d0d62171346e689654f97 100644 (file)
@@ -1,23 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#if ! ENABLE_EFI
-#include <errno.h>
-#endif
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include "sd-id128.h"
-
-#include "efi/loader-features.h"
-#include "time-util.h"
-
-#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
-#define EFI_VENDOR_GLOBAL SD_ID128_MAKE(8b,e4,df,61,93,ca,11,d2,aa,0d,00,e0,98,03,2b,8c)
-#define EFI_VARIABLE_NON_VOLATILE       0x0000000000000001
-#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
-#define EFI_VARIABLE_RUNTIME_ACCESS     0x0000000000000004
+#include "efivars.h"
 
 #if ENABLE_EFI
 
@@ -28,12 +12,6 @@ int efi_reboot_to_firmware_supported(void);
 int efi_get_reboot_to_firmware(void);
 int efi_set_reboot_to_firmware(bool value);
 
-char* efi_variable_path(sd_id128_t vendor, const char *name);
-int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size);
-int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p);
-int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size);
-int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *p);
-
 int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *part_uuid, char **path, bool *active);
 int efi_add_boot_option(uint16_t id, const char *title, uint32_t part, uint64_t pstart, uint64_t psize, sd_id128_t part_uuid, const char *path);
 int efi_remove_boot_option(uint16_t id);
@@ -74,26 +52,6 @@ static inline int efi_set_reboot_to_firmware(bool value) {
         return -EOPNOTSUPP;
 }
 
-static inline char* efi_variable_path(sd_id128_t vendor, const char *name) {
-        return NULL;
-}
-
-static inline int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size) {
-        return -EOPNOTSUPP;
-}
-
-static inline int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
-        return -EOPNOTSUPP;
-}
-
-static inline int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size) {
-        return -EOPNOTSUPP;
-}
-
-static inline int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *p) {
-        return -EOPNOTSUPP;
-}
-
 static inline int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *part_uuid, char **path, bool *active) {
         return -EOPNOTSUPP;
 }
index 4cab2ef6b06e3d1667a6673774a170f384283a13..346277c83a3a86d91f3183ee6de3ca79ea0e534e 100644 (file)
@@ -395,7 +395,7 @@ int ethtool_set_nic_buffer_size(int *fd, const char *ifname, netdev_ring_param *
         }
 
         if (ring->tx_pending_set) {
-                   if (ecmd.tx_pending != ring->rx_pending) {
+                   if (ecmd.tx_pending != ring->tx_pending) {
                            ecmd.tx_pending = ring->tx_pending;
                            need_update = true;
                 }
index e9005a30e3a5264e5526a522ee5be3aadf6dbe8f..40412de433bb15a7d145f2e191f42036985dfecf 100644 (file)
@@ -33,6 +33,8 @@ shared_sources = files('''
         bus-wait-for-units.h
         calendarspec.c
         calendarspec.h
+        cgroup-setup.c
+        cgroup-setup.h
         cgroup-show.c
         cgroup-show.h
         clean-ipc.c
@@ -58,8 +60,8 @@ shared_sources = files('''
         dns-domain.h
         dropin.c
         dropin.h
-        efivars.c
-        efivars.h
+        efi-loader.c
+        efi-loader.h
         enable-mempool.c
         env-file-label.c
         env-file-label.h
index 08569e8bf3409a01aa72bb15ea1fe11d2944c9da..5d76299179b9248d06b8b00dc60efc8120439643 100644 (file)
@@ -6,6 +6,7 @@
 #include "alloc-util.h"
 #include "fileio.h"
 #include "log.h"
+#include "proc-cmdline.h"
 #include "raw-reboot.h"
 #include "reboot-util.h"
 #include "string-util.h"
@@ -96,3 +97,14 @@ int reboot_with_parameter(RebootFlags flags) {
 
         return log_full_errno(flags & REBOOT_LOG ? LOG_ERR : LOG_DEBUG, errno, "Failed to reboot: %m");
 }
+
+int shall_restore_state(void) {
+        bool ret;
+        int r;
+
+        r = proc_cmdline_get_bool("systemd.restore_state", &ret);
+        if (r < 0)
+                return r;
+
+        return r > 0 ? ret : true;
+}
index 7bddc91ea60bbf5e840b3a7a5a8b64f8ad4623db..5aeb34821fbc5c2ef7c965ad4c94108a01a24694 100644 (file)
@@ -11,3 +11,5 @@ typedef enum RebootFlags {
 
 int read_reboot_parameter(char **parameter);
 int reboot_with_parameter(RebootFlags flags);
+
+int shall_restore_state(void);
index 8f4efc7996cc902838464e621a1530f5864b301b..9e61c825aa95ebc1feceb4e0bc2cf91d1fea7cdb 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "fdset.h"
 #include "macro.h"
+#include "string-util.h"
 #include "time-util.h"
 
 int serialize_item(FILE *f, const char *key, const char *value);
index 4a5f23e6c1bcbb0e76ffe9a508d661022fc98189..b015ff93381d1fe6f0350a0269466743e2f40024 100644 (file)
@@ -6,6 +6,7 @@
 #include "macro.h"
 #include "path-lookup.h"
 #include "set.h"
+#include "special.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -279,6 +280,7 @@ int unit_file_build_name_map(
                         if (hashmap_contains(ids, de->d_name))
                                 continue;
 
+                        dirent_ensure_type(d, de);
                         if (de->d_type == DT_LNK) {
                                 /* We don't explicitly check for alias loops here. unit_ids_map_get() which
                                  * limits the number of hops should be used to access the map. */
@@ -511,3 +513,47 @@ int unit_file_find_fragment(
         // FIXME: if instance, consider any unit names with different template name
         return 0;
 }
+
+static const char * const rlmap[] = {
+        "emergency", SPECIAL_EMERGENCY_TARGET,
+        "-b",        SPECIAL_EMERGENCY_TARGET,
+        "rescue",    SPECIAL_RESCUE_TARGET,
+        "single",    SPECIAL_RESCUE_TARGET,
+        "-s",        SPECIAL_RESCUE_TARGET,
+        "s",         SPECIAL_RESCUE_TARGET,
+        "S",         SPECIAL_RESCUE_TARGET,
+        "1",         SPECIAL_RESCUE_TARGET,
+        "2",         SPECIAL_MULTI_USER_TARGET,
+        "3",         SPECIAL_MULTI_USER_TARGET,
+        "4",         SPECIAL_MULTI_USER_TARGET,
+        "5",         SPECIAL_GRAPHICAL_TARGET,
+        NULL
+};
+
+static const char * const rlmap_initrd[] = {
+        "emergency", SPECIAL_EMERGENCY_TARGET,
+        "rescue",    SPECIAL_RESCUE_TARGET,
+        NULL
+};
+
+const char* runlevel_to_target(const char *word) {
+        const char * const *rlmap_ptr;
+        size_t i;
+
+        if (!word)
+                return NULL;
+
+        if (in_initrd()) {
+                word = startswith(word, "rd.");
+                if (!word)
+                        return NULL;
+        }
+
+        rlmap_ptr = in_initrd() ? rlmap_initrd : rlmap;
+
+        for (i = 0; rlmap_ptr[i]; i += 2)
+                if (streq(word, rlmap_ptr[i]))
+                        return rlmap_ptr[i+1];
+
+        return NULL;
+}
index 54cc7876fef15b807d5194d1c295ea836ced9a0f..98ba677f3f641bae584ad697db96f4345de5be00 100644 (file)
@@ -54,3 +54,5 @@ int unit_file_find_fragment(
                 const char *unit_name,
                 const char **ret_fragment_path,
                 Set **names);
+
+const char* runlevel_to_target(const char *rl);
index 0eb17989d0a54948eef3664bb9eb3bea9fcd24ab..08215fd3eee75a3bd12d1381b30d9fcbad93980e 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "alloc-util.h"
 #include "async.h"
+#include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "def.h"
 #include "exec-util.h"
index 6ec4986c10ce70b21345f4afb5b325fdecaebfdc..666affca190b06fad66c6e16db7688817d0aa2a5 100644 (file)
@@ -9,6 +9,7 @@
 #include "proc-cmdline.h"
 #include "special.h"
 #include "string-util.h"
+#include "unit-file.h"
 #include "util.h"
 
 /*
index f50edbcee7289f9ee4c6dca06f65b9bd9658db8b..e3d1385f4f15438ece969cba42cbd396e3bec6f5 100644 (file)
@@ -749,6 +749,64 @@ static int get_unit_list_recursive(
         return c;
 }
 
+static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
+        _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
+        char **name;
+        int r, i;
+
+        assert(bus);
+        assert(ret);
+
+        STRV_FOREACH(name, names) {
+                char *t;
+                UnitNameMangle options = UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN);
+
+                if (suffix)
+                        r = unit_name_mangle_with_suffix(*name, options, suffix, &t);
+                else
+                        r = unit_name_mangle(*name, options, &t);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to mangle name: %m");
+
+                if (string_is_glob(t))
+                        r = strv_consume(&globs, t);
+                else
+                        r = strv_consume(&mangled, t);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        /* Query the manager only if any of the names are a glob, since
+         * this is fairly expensive */
+        if (!strv_isempty(globs)) {
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                _cleanup_free_ UnitInfo *unit_infos = NULL;
+                size_t allocated, n;
+
+                r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
+                if (r < 0)
+                        return r;
+
+                n = strv_length(mangled);
+                allocated = n + 1;
+
+                for (i = 0; i < r; i++) {
+                        if (!GREEDY_REALLOC(mangled, allocated, n+2))
+                                return log_oom();
+
+                        mangled[n] = strdup(unit_infos[i].id);
+                        if (!mangled[n])
+                                return log_oom();
+
+                        mangled[++n] = NULL;
+                }
+        }
+
+        *ret = TAKE_PTR(mangled);
+        return 0;
+}
+
+
 static int list_units(int argc, char *argv[], void *userdata) {
         _cleanup_free_ UnitInfo *unit_infos = NULL;
         _cleanup_(message_set_freep) Set *replies = NULL;
@@ -959,6 +1017,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
 static int list_sockets(int argc, char *argv[], void *userdata) {
         _cleanup_(message_set_freep) Set *replies = NULL;
         _cleanup_strv_free_ char **machines = NULL;
+        _cleanup_strv_free_ char **sockets_with_suffix = NULL;
         _cleanup_free_ UnitInfo *unit_infos = NULL;
         _cleanup_free_ struct socket_info *socket_infos = NULL;
         const UnitInfo *u;
@@ -974,49 +1033,55 @@ static int list_sockets(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
-        if (n < 0)
-                return n;
+        r = expand_names(bus, strv_skip(argv, 1), ".socket", &sockets_with_suffix);
+        if (r < 0)
+                return r;
 
-        for (u = unit_infos; u < unit_infos + n; u++) {
-                _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
-                int i, c;
+        if (argc == 1 || sockets_with_suffix) {
+                n = get_unit_list_recursive(bus, sockets_with_suffix, &unit_infos, &replies, &machines);
+                if (n < 0)
+                        return n;
 
-                if (!endswith(u->id, ".socket"))
-                        continue;
+                for (u = unit_infos; u < unit_infos + n; u++) {
+                        _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
+                        int i, c;
 
-                r = get_triggered_units(bus, u->unit_path, &triggered);
-                if (r < 0)
-                        goto cleanup;
+                        if (!endswith(u->id, ".socket"))
+                                continue;
 
-                c = get_listening(bus, u->unit_path, &listening);
-                if (c < 0) {
-                        r = c;
-                        goto cleanup;
-                }
+                        r = get_triggered_units(bus, u->unit_path, &triggered);
+                        if (r < 0)
+                                goto cleanup;
 
-                if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
-                        r = log_oom();
-                        goto cleanup;
-                }
+                        c = get_listening(bus, u->unit_path, &listening);
+                        if (c < 0) {
+                                r = c;
+                                goto cleanup;
+                        }
 
-                for (i = 0; i < c; i++)
-                        socket_infos[cs + i] = (struct socket_info) {
-                                .machine = u->machine,
-                                .id = u->id,
-                                .type = listening[i*2],
-                                .path = listening[i*2 + 1],
-                                .triggered = triggered,
-                                .own_triggered = i==0,
-                        };
+                        if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
+                                r = log_oom();
+                                goto cleanup;
+                        }
 
-                /* from this point on we will cleanup those socket_infos */
-                cs += c;
-                free(listening);
-                listening = triggered = NULL; /* avoid cleanup */
-        }
+                        for (i = 0; i < c; i++)
+                                socket_infos[cs + i] = (struct socket_info) {
+                                        .machine = u->machine,
+                                        .id = u->id,
+                                        .type = listening[i*2],
+                                        .path = listening[i*2 + 1],
+                                        .triggered = triggered,
+                                        .own_triggered = i==0,
+                                };
+
+                        /* from this point on we will cleanup those socket_infos */
+                        cs += c;
+                        free(listening);
+                        listening = triggered = NULL; /* avoid cleanup */
+                }
 
-        typesafe_qsort(socket_infos, cs, socket_info_compare);
+                typesafe_qsort(socket_infos, cs, socket_info_compare);
+        }
 
         output_sockets_list(socket_infos, cs);
 
@@ -1263,6 +1328,7 @@ static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
 static int list_timers(int argc, char *argv[], void *userdata) {
         _cleanup_(message_set_freep) Set *replies = NULL;
         _cleanup_strv_free_ char **machines = NULL;
+        _cleanup_strv_free_ char **timers_with_suffix = NULL;
         _cleanup_free_ struct timer_info *timer_infos = NULL;
         _cleanup_free_ UnitInfo *unit_infos = NULL;
         struct timer_info *t;
@@ -1279,47 +1345,53 @@ static int list_timers(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
-        if (n < 0)
-                return n;
+        r = expand_names(bus, strv_skip(argv, 1), ".timer", &timers_with_suffix);
+        if (r < 0)
+                return r;
+
+        if (argc == 1 || timers_with_suffix) {
+                n = get_unit_list_recursive(bus, timers_with_suffix, &unit_infos, &replies, &machines);
+                if (n < 0)
+                        return n;
 
-        dual_timestamp_get(&nw);
+                dual_timestamp_get(&nw);
 
-        for (u = unit_infos; u < unit_infos + n; u++) {
-                _cleanup_strv_free_ char **triggered = NULL;
-                dual_timestamp next = DUAL_TIMESTAMP_NULL;
-                usec_t m, last = 0;
+                for (u = unit_infos; u < unit_infos + n; u++) {
+                        _cleanup_strv_free_ char **triggered = NULL;
+                        dual_timestamp next = DUAL_TIMESTAMP_NULL;
+                        usec_t m, last = 0;
 
-                if (!endswith(u->id, ".timer"))
-                        continue;
+                        if (!endswith(u->id, ".timer"))
+                                continue;
 
-                r = get_triggered_units(bus, u->unit_path, &triggered);
-                if (r < 0)
-                        goto cleanup;
+                        r = get_triggered_units(bus, u->unit_path, &triggered);
+                        if (r < 0)
+                                goto cleanup;
 
-                r = get_next_elapse(bus, u->unit_path, &next);
-                if (r < 0)
-                        goto cleanup;
+                        r = get_next_elapse(bus, u->unit_path, &next);
+                        if (r < 0)
+                                goto cleanup;
 
-                get_last_trigger(bus, u->unit_path, &last);
+                        get_last_trigger(bus, u->unit_path, &last);
 
-                if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
-                        r = log_oom();
-                        goto cleanup;
-                }
+                        if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
+                                r = log_oom();
+                                goto cleanup;
+                        }
 
-                m = calc_next_elapse(&nw, &next);
+                        m = calc_next_elapse(&nw, &next);
 
-                timer_infos[c++] = (struct timer_info) {
-                        .machine = u->machine,
-                        .id = u->id,
-                        .next_elapse = m,
-                        .last_trigger = last,
-                        .triggered = TAKE_PTR(triggered),
-                };
-        }
+                        timer_infos[c++] = (struct timer_info) {
+                                .machine = u->machine,
+                                .id = u->id,
+                                .next_elapse = m,
+                                .last_trigger = last,
+                                .triggered = TAKE_PTR(triggered),
+                        };
+                }
 
-        typesafe_qsort(timer_infos, c, timer_info_compare);
+                typesafe_qsort(timer_infos, c, timer_info_compare);
+        }
 
         output_timers_list(timer_infos, c);
 
@@ -2926,63 +2998,6 @@ fail:
         return r;
 }
 
-static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
-        _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
-        char **name;
-        int r, i;
-
-        assert(bus);
-        assert(ret);
-
-        STRV_FOREACH(name, names) {
-                char *t;
-                UnitNameMangle options = UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN);
-
-                if (suffix)
-                        r = unit_name_mangle_with_suffix(*name, options, suffix, &t);
-                else
-                        r = unit_name_mangle(*name, options, &t);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to mangle name: %m");
-
-                if (string_is_glob(t))
-                        r = strv_consume(&globs, t);
-                else
-                        r = strv_consume(&mangled, t);
-                if (r < 0)
-                        return log_oom();
-        }
-
-        /* Query the manager only if any of the names are a glob, since
-         * this is fairly expensive */
-        if (!strv_isempty(globs)) {
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-                _cleanup_free_ UnitInfo *unit_infos = NULL;
-                size_t allocated, n;
-
-                r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
-                if (r < 0)
-                        return r;
-
-                n = strv_length(mangled);
-                allocated = n + 1;
-
-                for (i = 0; i < r; i++) {
-                        if (!GREEDY_REALLOC(mangled, allocated, n+2))
-                                return log_oom();
-
-                        mangled[n] = strdup(unit_infos[i].id);
-                        if (!mangled[n])
-                                return log_oom();
-
-                        mangled[++n] = NULL;
-                }
-        }
-
-        *ret = TAKE_PTR(mangled);
-        return 0;
-}
-
 static const struct {
         const char *target;
         const char *verb;
index d2d74b2b4cf876e51b77d4023668b0e35443c927..98e328139784150c457bc04f97672d73cdd3f018 100644 (file)
@@ -174,6 +174,9 @@ int sd_dhcp_client_set_user_class(
 int sd_dhcp_client_get_lease(
                 sd_dhcp_client *client,
                 sd_dhcp_lease **ret);
+int sd_dhcp_client_set_service_type(
+                sd_dhcp_client *client,
+                int type);
 
 int sd_dhcp_client_stop(sd_dhcp_client *client);
 int sd_dhcp_client_start(sd_dhcp_client *client);
index 3aac3f14fe30f1a6e5007d1a15e3bf1b0cafd758..be34d43e748153f4bb1c37e10b1c56fcf6aa0bd1 100644 (file)
@@ -120,6 +120,10 @@ int sd_dhcp6_client_get_information_request(
 int sd_dhcp6_client_set_request_option(
                 sd_dhcp6_client *client,
                 uint16_t option);
+int sd_dhcp6_client_set_prefix_delegation_hint(
+                sd_dhcp6_client *client,
+                uint8_t prefixlen,
+                const struct in6_addr *pd_address);
 int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client,
                                           int *delegation);
 int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client,
index a8c3e59098e1c048cd7fd6129055dd36415f9fe8..5132145b415fda960251d74c81dd9d8f1c60bcd6 100644 (file)
@@ -615,6 +615,10 @@ tests += [
          [],
          []],
 
+        [['src/test/test-cgroup-setup.c'],
+         [],
+         []],
+
         [['src/test/test-env-file.c'],
          [],
          []],
index 79b8dd49a71655ff653c8e0f197ba34fa0ec6a6d..3c7f7a98cf8aa5d19798dcf45ab58d66733ac892 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "acpi-fpdt.h"
 #include "boot-timestamps.h"
-#include "efivars.h"
+#include "efi-loader.h"
 #include "log.h"
 #include "tests.h"
 #include "util.h"
index f9fae84ddeacb14c97883dc875f5163b660dff43..84a6e92df1ddc457ed62e24cfead11137e1543b2 100644 (file)
@@ -15,8 +15,8 @@
 #include "macro.h"
 #include "missing_prctl.h"
 #include "parse-util.h"
+#include "string-util.h"
 #include "tests.h"
-#include "util.h"
 
 static uid_t test_uid = -1;
 static gid_t test_gid = -1;
diff --git a/src/test/test-cgroup-setup.c b/src/test/test-cgroup-setup.c
new file mode 100644 (file)
index 0000000..330631a
--- /dev/null
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "build.h"
+#include "cgroup-setup.h"
+#include "log.h"
+#include "proc-cmdline.h"
+#include "string-util.h"
+#include "tests.h"
+
+static void test_is_wanted_print(bool header) {
+        _cleanup_free_ char *cmdline = NULL;
+
+        log_info("-- %s --", __func__);
+        assert_se(proc_cmdline(&cmdline) >= 0);
+        log_info("cmdline: %s", cmdline);
+        if (header) {
+                log_info(_CGROUP_HIERARCHY_);
+                (void) system("findmnt -n /sys/fs/cgroup");
+        }
+
+        log_info("is_unified_wanted() â†’ %s", yes_no(cg_is_unified_wanted()));
+        log_info("is_hybrid_wanted() â†’ %s", yes_no(cg_is_hybrid_wanted()));
+        log_info("is_legacy_wanted() â†’ %s", yes_no(cg_is_legacy_wanted()));
+        log_info(" ");
+}
+
+static void test_is_wanted(void) {
+        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
+                         "systemd.unified_cgroup_hierarchy", 1) >= 0);
+        test_is_wanted_print(false);
+
+        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
+                         "systemd.unified_cgroup_hierarchy=0", 1) >= 0);
+        test_is_wanted_print(false);
+
+        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
+                         "systemd.unified_cgroup_hierarchy=0 "
+                         "systemd.legacy_systemd_cgroup_controller", 1) >= 0);
+        test_is_wanted_print(false);
+
+        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
+                         "systemd.unified_cgroup_hierarchy=0 "
+                         "systemd.legacy_systemd_cgroup_controller=0", 1) >= 0);
+        test_is_wanted_print(false);
+
+        /* cgroup_no_v1=all implies unified cgroup hierarchy, unless otherwise
+         * explicitly specified. */
+        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
+                         "cgroup_no_v1=all", 1) >= 0);
+        test_is_wanted_print(false);
+
+        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
+                         "cgroup_no_v1=all "
+                         "systemd.unified_cgroup_hierarchy=0", 1) >= 0);
+        test_is_wanted_print(false);
+}
+
+int main(void) {
+        test_setup_logging(LOG_DEBUG);
+
+        test_is_wanted_print(true);
+        test_is_wanted_print(false); /* run twice to test caching */
+        test_is_wanted();
+
+        return 0;
+}
index b54b5e76c67a92a23895fe1cde26b906571df16d..e4fbb9edcee2c1466e9d90e7a53820e5ae63c1dc 100644 (file)
@@ -333,64 +333,15 @@ static void test_fd_is_cgroup_fs(void) {
         fd = safe_close(fd);
 }
 
-static void test_is_wanted_print(bool header) {
-        _cleanup_free_ char *cmdline = NULL;
-
-        log_info("-- %s --", __func__);
-        assert_se(proc_cmdline(&cmdline) >= 0);
-        log_info("cmdline: %s", cmdline);
-        if (header) {
-
-                log_info(_CGROUP_HIERARCHY_);
-                (void) system("findmnt -n /sys/fs/cgroup");
-        }
-
-        log_info("is_unified_wanted() â†’ %s", yes_no(cg_is_unified_wanted()));
-        log_info("is_hybrid_wanted() â†’ %s", yes_no(cg_is_hybrid_wanted()));
-        log_info("is_legacy_wanted() â†’ %s", yes_no(cg_is_legacy_wanted()));
-        log_info(" ");
-}
-
-static void test_is_wanted(void) {
-        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
-                         "systemd.unified_cgroup_hierarchy", 1) >= 0);
-        test_is_wanted_print(false);
-
-        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
-                         "systemd.unified_cgroup_hierarchy=0", 1) >= 0);
-        test_is_wanted_print(false);
-
-        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
-                         "systemd.unified_cgroup_hierarchy=0 "
-                         "systemd.legacy_systemd_cgroup_controller", 1) >= 0);
-        test_is_wanted_print(false);
-
-        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
-                         "systemd.unified_cgroup_hierarchy=0 "
-                         "systemd.legacy_systemd_cgroup_controller=0", 1) >= 0);
-        test_is_wanted_print(false);
-
-        /* cgroup_no_v1=all implies unified cgroup hierarchy, unless otherwise
-         * explicitly specified. */
-        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
-                         "cgroup_no_v1=all", 1) >= 0);
-        test_is_wanted_print(false);
-
-        assert_se(setenv("SYSTEMD_PROC_CMDLINE",
-                         "cgroup_no_v1=all "
-                         "systemd.unified_cgroup_hierarchy=0", 1) >= 0);
-        test_is_wanted_print(false);
-}
-
 static void test_cg_tests(void) {
         int all, hybrid, systemd, r;
 
-        r = cg_unified_flush();
+        r = cg_unified();
         if (r == -ENOMEDIUM) {
                 log_notice_errno(r, "Skipping cg hierarchy tests: %m");
                 return;
         }
-        assert_se(r == 0);
+        assert_se(r >= 0);
 
         all = cg_all_unified();
         assert_se(IN_SET(all, 0, 1));
@@ -477,9 +428,6 @@ int main(void) {
         TEST_REQ_RUNNING_SYSTEMD(test_mask_supported());
         TEST_REQ_RUNNING_SYSTEMD(test_is_cgroup_fs());
         TEST_REQ_RUNNING_SYSTEMD(test_fd_is_cgroup_fs());
-        test_is_wanted_print(true);
-        test_is_wanted_print(false); /* run twice to test caching */
-        test_is_wanted();
         test_cg_tests();
         test_cg_get_keyed_attribute();
 
index 5cdfd2dc54ebdb9f0dbf0bae15f3021b3ed20a88..1891df0eb9e53e28b8738a70a06027d911571f9b 100644 (file)
@@ -3,6 +3,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "path-util.h"
 #include "process-util.h"
index a79263a50bf94f4e78352c3ef51f19f90609fc58..fce9232dcfebc781139a658de60c050d5befeb11 100644 (file)
@@ -14,7 +14,7 @@
 #include "cgroup-util.h"
 #include "condition.h"
 #include "cpu-set-util.h"
-#include "efivars.h"
+#include "efi-loader.h"
 #include "hostname-util.h"
 #include "id128-util.h"
 #include "ima-util.h"
@@ -124,7 +124,7 @@ static void test_condition_test_control_group_controller(void) {
         _cleanup_free_ char *controller_name = NULL;
         int r;
 
-        r = cg_unified_flush();
+        r = cg_unified();
         if (r < 0) {
                 log_notice_errno(r, "Skipping ConditionControlGroupController tests: %m");
                 return;
index 633cc425345d8d8bc7e0da8ef5797d58480e0583..10648114971c0bd42b5de145b10fe6739ce40083 100644 (file)
@@ -106,9 +106,9 @@ int main(int argc, char *argv[]) {
 
         printf("Test11: (Start/stop job ordering, execution cycle)\n");
         assert_se(manager_add_job(m, JOB_START, i, JOB_FAIL, NULL, NULL, &j) == 0);
-        assert_se(a->job && a->job->type == JOB_STOP);
-        assert_se(d->job && d->job->type == JOB_STOP);
-        assert_se(b->job && b->job->type == JOB_START);
+        assert_se(unit_has_job_type(a, JOB_STOP));
+        assert_se(unit_has_job_type(d, JOB_STOP));
+        assert_se(unit_has_job_type(b, JOB_START));
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Load6:\n");
index 5b79d12f0785ecaabb3fc08d580b432f63d5ee25..dc8c80a14b7614953130b7dc38e6b0e41b84f916 100644 (file)
@@ -3,7 +3,7 @@
 #include "test-helper.h"
 #include "random-util.h"
 #include "alloc-util.h"
-#include "cgroup-util.h"
+#include "cgroup-setup.h"
 #include "string-util.h"
 
 int enter_cgroup_subroot(void) {
index d51e0d94fd36a1438e72e5f271ba4e63653b8aff..33a95c6b52ebfa104f706b97e2b0139793887918 100644 (file)
@@ -2,7 +2,6 @@
 
 #include <stdio.h>
 
-#include "job.h"
 #include "service.h"
 #include "unit.h"
 
index 6d25a6919ed257fb981e8007a50a9a54b6dce61f..3231e4a3e69e7e69b02d913c35cc1018c74e0d1f 100644 (file)
@@ -7,6 +7,7 @@
 #include "proc-cmdline.h"
 #include "special.h"
 #include "string-util.h"
+#include "tests.h"
 #include "util.h"
 
 static int obj;
@@ -29,8 +30,9 @@ static void test_proc_cmdline_override(void) {
         log_info("/* %s */", __func__);
 
         assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\"") == 0);
+        assert_se(putenv((char*) "SYSTEMD_EFI_OPTIONS=differnt") == 0);
 
-        /* Test if the override works */
+        /* First test if the overrides for /proc/cmdline still work */
         _cleanup_free_ char *line = NULL, *value = NULL;
         assert_se(proc_cmdline(&line) >= 0);
 
@@ -44,6 +46,19 @@ static void test_proc_cmdline_override(void) {
 
         assert_se(proc_cmdline_get_key("and_one_more", 0, &value) > 0 && streq_ptr(value, "zzz aaa"));
         value = mfree(value);
+
+        assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=") == 0);
+        assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\"") == 0);
+
+        assert_se(streq(line, "foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\""));
+        assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux"));
+        value = mfree(value);
+
+        assert_se(proc_cmdline_get_key("some_arg_with_space", 0, &value) > 0 && streq_ptr(value, "foo bar"));
+        value = mfree(value);
+
+        assert_se(proc_cmdline_get_key("and_one_more", 0, &value) > 0 && streq_ptr(value, "zzz aaa"));
+        value = mfree(value);
 }
 
 static int parse_item_given(const char *key, const char *value, void *data) {
@@ -139,6 +154,24 @@ static void test_proc_cmdline_get_bool(void) {
 
         log_info("/* %s */", __func__);
         assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar bar-waldo=1 x_y-z=0 quux=miep\nda=yes\nthe=1") == 0);
+        assert_se(putenv((char*) "SYSTEMD_EFI_OPTIONS=") == 0);
+
+        assert_se(proc_cmdline_get_bool("", &value) == -EINVAL);
+        assert_se(proc_cmdline_get_bool("abc", &value) == 0 && value == false);
+        assert_se(proc_cmdline_get_bool("foo_bar", &value) > 0 && value == true);
+        assert_se(proc_cmdline_get_bool("foo-bar", &value) > 0 && value == true);
+        assert_se(proc_cmdline_get_bool("bar-waldo", &value) > 0 && value == true);
+        assert_se(proc_cmdline_get_bool("bar_waldo", &value) > 0 && value == true);
+        assert_se(proc_cmdline_get_bool("x_y-z", &value) > 0 && value == false);
+        assert_se(proc_cmdline_get_bool("x-y-z", &value) > 0 && value == false);
+        assert_se(proc_cmdline_get_bool("x-y_z", &value) > 0 && value == false);
+        assert_se(proc_cmdline_get_bool("x_y_z", &value) > 0 && value == false);
+        assert_se(proc_cmdline_get_bool("quux", &value) == -EINVAL && value == false);
+        assert_se(proc_cmdline_get_bool("da", &value) > 0 && value == true);
+        assert_se(proc_cmdline_get_bool("the", &value) > 0 && value == true);
+
+        assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=") == 0);
+        assert_se(putenv((char*) "SYSTEMD_EFI_OPTIONS=foo_bar bar-waldo=1 x_y-z=0 quux=miep\nda=yes\nthe=1") == 0);
 
         assert_se(proc_cmdline_get_bool("", &value) == -EINVAL);
         assert_se(proc_cmdline_get_bool("abc", &value) == 0 && value == false);
@@ -212,27 +245,8 @@ static void test_proc_cmdline_key_startswith(void) {
         assert_se(!proc_cmdline_key_startswith("foo-bar", "foo_xx"));
 }
 
-static void test_runlevel_to_target(void) {
-        log_info("/* %s */", __func__);
-
-        in_initrd_force(false);
-        assert_se(streq_ptr(runlevel_to_target(NULL), NULL));
-        assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL));
-        assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL));
-        assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET));
-        assert_se(streq_ptr(runlevel_to_target("rd.rescue"), NULL));
-
-        in_initrd_force(true);
-        assert_se(streq_ptr(runlevel_to_target(NULL), NULL));
-        assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL));
-        assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL));
-        assert_se(streq_ptr(runlevel_to_target("3"), NULL));
-        assert_se(streq_ptr(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET));
-}
-
 int main(void) {
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_INFO);
 
         test_proc_cmdline_parse();
         test_proc_cmdline_override();
@@ -244,7 +258,6 @@ int main(void) {
         test_proc_cmdline_get_key();
         test_proc_cmdline_get_bool();
         test_proc_cmdline_get_key_many();
-        test_runlevel_to_target();
 
         return 0;
 }
index 8bc5bf60387aeb5d089d1ed124e57663ec6d0463..f0186b078f0cfac6af0a9123a93ca8cfefb74b15 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "path-lookup.h"
 #include "set.h"
+#include "special.h"
 #include "strv.h"
 #include "tests.h"
 #include "unit-file.h"
@@ -75,11 +76,30 @@ static void test_unit_file_build_name_map(char **ids) {
         }
 }
 
+static void test_runlevel_to_target(void) {
+        log_info("/* %s */", __func__);
+
+        in_initrd_force(false);
+        assert_se(streq_ptr(runlevel_to_target(NULL), NULL));
+        assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL));
+        assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL));
+        assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET));
+        assert_se(streq_ptr(runlevel_to_target("rd.rescue"), NULL));
+
+        in_initrd_force(true);
+        assert_se(streq_ptr(runlevel_to_target(NULL), NULL));
+        assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL));
+        assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL));
+        assert_se(streq_ptr(runlevel_to_target("3"), NULL));
+        assert_se(streq_ptr(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET));
+}
+
 int main(int argc, char **argv) {
         test_setup_logging(LOG_DEBUG);
 
         test_unit_validate_alias_symlink_and_warn();
         test_unit_file_build_name_map(strv_skip(argv, 1));
+        test_runlevel_to_target();
 
         return 0;
 }
index 7ef75e6f919fc05b04c652574d75478718991fd2..c6b0208b4b7528604b339521fc9d49b2203f5fae 100644 (file)
@@ -19,7 +19,7 @@
 #include "alloc-util.h"
 #include "blkid-util.h"
 #include "device-util.h"
-#include "efivars.h"
+#include "efi-loader.h"
 #include "errno-util.h"
 #include "fd-util.h"
 #include "gpt.h"
index 77d95e513fb3ae4ddef8ecefcd2494b237bb6e9f..11f2f1c98515d1c813ef923f595b0e8108dbe483 100644 (file)
@@ -45,9 +45,11 @@ static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_se
 
                 r = write_string_file(filename, action, WRITE_STRING_FILE_DISABLE_BUFFER);
                 if (r < 0) {
-                        log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_ERR, r,
+                        bool ignore = IN_SET(r, -ENOENT, -EACCES, -ENODEV);
+
+                        log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, r,
                                        "Failed to write '%s' to '%s': %m", action, filename);
-                        if (ret == 0 && r != -ENOENT)
+                        if (ret == 0 && !ignore)
                                 ret = r;
                         continue;
                 }
index 7ff148e1300d58147f9f28fc449fa74ae0ff3944..2753ed6e3a6e64f0c36c172a63508bdfffd07ecc 100644 (file)
@@ -54,6 +54,11 @@ TEST_NO_KVM=1
     Disable QEMU KVM autodetection (may be necessary when you're trying to run the
     *vanilla* QEMU and have both qemu and qemu-kvm installed)
 
+TEST_NESTED_KVM=1
+    Allow tests to run with nested KVM. By default, the testsuite disables
+    nested KVM if the host machine already runs under KVM. Setting this
+    variable disables such checks
+
 QEMU_MEM=512M
     Configure amount of memory for QEMU VMs (defaults to 512M)
 
index cc67cfa17d13b8897d37fad7d45aed0064a5ac87..f89bdca99ff85b06e0112d9932124750f515a83c 100755 (executable)
@@ -113,16 +113,16 @@ function run {
 
     local _root="/var/lib/machines/unified-$1-cgns-$2-api-vfs-writable-$3"
     /create-busybox-container "$_root"
-    UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" -b
-    UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" --private-network -b
+    SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" -b
+    SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" --private-network -b
 
-    if UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" -U -b; then
+    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" -U -b; then
        [[ "$is_user_ns_supported" = "yes" && "$3" = "network" ]] && return 1
     else
        [[ "$is_user_ns_supported" = "no" && "$3" = "network" ]] && return 1
     fi
 
-    if UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" --private-network -U -b; then
+    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" --private-network -U -b; then
        [[ "$is_user_ns_supported" = "yes" && "$3" = "yes" ]] && return 1
     else
        [[ "$is_user_ns_supported" = "no" && "$3" = "yes" ]] && return 1
@@ -131,42 +131,42 @@ function run {
     local _netns_opt="--network-namespace-path=/proc/self/ns/net"
 
     # --network-namespace-path and network-related options cannot be used together
-    if UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-interface=lo -b; then
+    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-interface=lo -b; then
        return 1
     fi
 
-    if UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-macvlan=lo -b; then
+    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-macvlan=lo -b; then
        return 1
     fi
 
-    if UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-ipvlan=lo -b; then
+    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-ipvlan=lo -b; then
        return 1
     fi
 
-    if UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-veth -b; then
+    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-veth -b; then
        return 1
     fi
 
-    if UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-veth-extra=lo -b; then
+    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-veth-extra=lo -b; then
        return 1
     fi
 
-    if UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-bridge=lo -b; then
+    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-bridge=lo -b; then
        return 1
     fi
 
-    if UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-zone=zone -b; then
+    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --network-zone=zone -b; then
        return 1
     fi
 
-    if UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --private-network -b; then
+    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" --private-network -b; then
        return 1
     fi
 
     # test --network-namespace-path works with a network namespace created by "ip netns"
     ip netns add nspawn_test
     _netns_opt="--network-namespace-path=/run/netns/nspawn_test"
-    UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" /bin/ip a | grep -v -E '^1: lo.*UP'
+    SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" /bin/ip a | grep -v -E '^1: lo.*UP'
     local r=$?
     ip netns del nspawn_test
 
index b161d97a7c5018c7cda33cc29155bc673fb59a10..50d6754b96b2550b4ae82fba963a25749560f45f 100755 (executable)
@@ -19,6 +19,14 @@ systemd-run --unit=four -p Type=exec /bin/sleep infinity
 ! systemd-run --unit=five -p Type=exec -p User=idontexist /bin/sleep infinity
 ! systemd-run --unit=six -p Type=exec /tmp/brokenbinary
 
+systemd-run --unit=seven -p KillSignal=SIGTERM -p RestartKillSignal=SIGINT -p Type=exec /bin/sleep infinity
+# Both TERM and SIGINT happen to have the same number on all architectures
+test $(systemctl show --value -p KillSignal seven.service) -eq 15
+test $(systemctl show --value -p RestartKillSignal seven.service) -eq 2
+
+systemctl restart seven.service
+systemctl stop seven.service
+
 systemd-analyze log-level info
 
 echo OK > /testok
index 3be643075a89d450affe3e9760465181d8d41e39..24d94033fc844a3cfe3931c22ac76bfe15ee0817 100644 (file)
@@ -93,11 +93,13 @@ BlackList=
 RequestOptions=
 SendRelease=
 MaxAttempts=
+IPServiceType=
 [DHCPv6]
 UseNTP=
 UseDNS=
 RapidCommit=
 ForceDHCPv6PDOtherInformation=
+PrefixDelegationHint=
 [Route]
 Destination=
 Protocol=
index fe9d451b41afdc19572cc6ed01eed74b3ede3b7e..068f4398b9bd6733336c32a7df1267cc564103e3 100644 (file)
@@ -185,6 +185,7 @@ RequiresMountsFor=
 Requisite=
 Restart=
 RestartForceExitStatus=
+RestartKillSignal=
 RestartPreventExitStatus=
 RestartSec=
 ReusePort=
index 2fb7b8660bb4c30df408b8635bcc4ccbdac2bcdc..ca40934de8f8fd0310a6195b0a8050bb11bf47df 100644 (file)
@@ -13,7 +13,7 @@ ExecStart=test -f /var/lib/private/quux/pief/yayyay
 ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/waldo:%S/quux/pief"'
 
 # Make sure that /var/lib/private/waldo is really the only writable directory besides the obvious candidates
-ExecStart=sh -x -c 'test $$(find / \( -path /var/tmp -o -path /tmp -o -path /proc -o -path /dev/mqueue -o -path /dev/shm -o -path /sys/fs/bpf \) -prune -o -type d -writable -print 2>/dev/null | sort -u | tr -d '\\\\n') = /var/lib/private/quux/pief/var/lib/private/waldo'
+ExecStart=sh -x -c 'test $$(find / \( -path /var/tmp -o -path /tmp -o -path /proc -o -path /dev/mqueue -o -path /dev/shm -o -path /sys/fs/bpf -o -path /dev/.lxc \) -prune -o -type d -writable -print 2>/dev/null | sort -u | tr -d '\\\\n') = /var/lib/private/quux/pief/var/lib/private/waldo'
 
 Type=oneshot
 DynamicUser=yes
index a8b527b5a6257eaeac6535b400f43f2744ffeecd..359fd4026e460b68c855e5fe53f370701824a5ed 100644 (file)
@@ -17,6 +17,17 @@ UNIFIED_CGROUP_HIERARCHY="${UNIFIED_CGROUP_HIERARCHY:-default}"
 EFI_MOUNT="$(bootctl -x 2>/dev/null || echo /boot)"
 QEMU_MEM="${QEMU_MEM:-512M}"
 
+# Decide if we can (and want to) run QEMU with KVM acceleration.
+# Check if nested KVM is explicitly enabled (TEST_NESTED_KVM). If not,
+# check if it's not explicitly disabled (TEST_NO_KVM) and we're not already
+# running under KVM. If these conditions are met, enable KVM (and possibly
+# nested KVM), otherwise disable it.
+if [[ -n "$TEST_NESTED_KVM" || ( -z "$TEST_NO_KVM" && $(systemd-detect-virt -v) != kvm ) ]]; then
+    QEMU_KVM=yes
+else
+    QEMU_KVM=no
+fi
+
 if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then
     echo "WARNING! Cannot determine rootlibdir from pkg-config, assuming /usr/lib/systemd" >&2
     ROOTLIBDIR=/usr/lib/systemd
@@ -86,9 +97,7 @@ fi
 
 function find_qemu_bin() {
     # SUSE and Red Hat call the binary qemu-kvm. Debian and Gentoo call it kvm.
-    # Either way, only use this version if we aren't running in KVM, because
-    # nested KVM is flaky still.
-    if [[ $(systemd-detect-virt -v) != kvm && -z $TEST_NO_KVM ]] ; then
+    if [[ $QEMU_KVM == "yes" ]]; then
         [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a kvm qemu-kvm 2>/dev/null | grep '^/' -m1)
     fi
 
@@ -220,8 +229,8 @@ $QEMU_OPTIONS \
         QEMU_OPTIONS="$QEMU_OPTIONS -initrd $INITRD"
     fi
 
-    # Let's use KVM if it is available, but let's avoid using nested KVM as that is still flaky
-    if [[ -c /dev/kvm && $(systemd-detect-virt -v) != kvm && -z $TEST_NO_KVM ]] ; then
+    # Let's use KVM if possible
+    if [[ -c /dev/kvm && $QEMU_KVM == "yes" ]]; then
         QEMU_OPTIONS="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host"
     fi
 
@@ -250,12 +259,12 @@ run_nspawn() {
     fi
 
     if [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
-        dwarn "nspawn doesn't support UNIFIED_CGROUP_HIERARCHY=hybrid, skipping"
+        dwarn "nspawn doesn't support SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=hybrid, skipping"
         exit
     elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" || "$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
-        _nspawn_cmd="env UNIFIED_CGROUP_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
+        _nspawn_cmd="env SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
     elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "default" ]]; then
-        _nspawn_cmd="env --unset=UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
+        _nspawn_cmd="env --unset=UNIFIED_CGROUP_HIERARCHY --unset=SYSTEMD_NSPAWN_UNIFIED_HIERARCHY $_nspawn_cmd"
     else
         dfatal "Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
         exit 1
index dfef25461126e5956c59c0f5c7ce5e3cc7ea1cb7..87a76a502c0f25511116e76ad0c6eadacc43350b 100755 (executable)
@@ -2578,16 +2578,20 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
         self.assertRegex(output, '192.168.5')
         self.assertRegex(output, '1492')
 
-        # issue #8726
         print('## ip route show table main dev veth99')
         output = check_output('ip route show table main dev veth99')
         print(output)
-        self.assertNotRegex(output, 'proto dhcp')
+        # See issue #8726
+        main_table_is_empty = output == ''
+        if not main_table_is_empty:
+            self.assertNotRegex(output, 'proto dhcp')
 
         print('## ip route show table 211 dev veth99')
         output = check_output('ip route show table 211 dev veth99')
         print(output)
         self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
+        if main_table_is_empty:
+            self.assertRegex(output, '192.168.5.0/24 proto dhcp')
         self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
         self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
 
diff --git a/tools/chromeos/gen_autosuspend_rules.py b/tools/chromeos/gen_autosuspend_rules.py
new file mode 100755 (executable)
index 0000000..e0243a4
--- /dev/null
@@ -0,0 +1,315 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Autosuspend udev rule generator
+
+This script is executed at build time to generate udev rules. The
+resulting rules file is installed on the device, the script itself
+is not.
+"""
+
+from __future__ import print_function
+
+# List of USB devices (vendorid:productid) for which it is safe to enable
+# autosuspend.
+USB_IDS = []
+
+# Host Controllers and internal hubs
+USB_IDS += [
+    # Linux Host Controller (UHCI) (most older x86 boards)
+    '1d6b:0001',
+    # Linux Host Controller (EHCI) (all boards)
+    '1d6b:0002',
+    # Linux Host Controller (XHCI) (most newer boards)
+    '1d6b:0003',
+    # SMSC (Internal HSIC Hub) (most Exynos boards)
+    '0424:3503',
+    # Intel (Rate Matching Hub) (all x86 boards)
+    '05e3:0610',
+    # Intel (Internal Hub?) (peppy, falco)
+    '8087:0024',
+    # Genesys Logic (Internal Hub) (rambi)
+    '8087:8000',
+]
+
+# Webcams
+USB_IDS += [
+    # Chicony (zgb)
+    '04f2:b1d8',
+    # Chicony (mario)
+    '04f2:b262',
+    # Chicony (stout)
+    '04f2:b2fe',
+    # Chicony (butterfly)
+    '04f2:b35f',
+    # Chicony (rambi)
+    '04f2:b443',
+    # Chicony (glados)
+    '04f2:b552',
+    # LiteOn (spring)
+    '058f:b001',
+    # Foxlink? (butterfly)
+    '05c8:0351',
+    # Foxlink? (butterfly)
+    '05c8:0355',
+    # Cheng Uei? (falco)
+    '05c8:036e',
+    # SuYin (parrot)
+    '064e:d251',
+    # Realtek (falco)
+    '0bda:571c',
+    # IMC Networks (squawks)
+    '13d3:5657',
+    # Sunplus (parrot)
+    '1bcf:2c17',
+    # (C-13HDO10B39N) (alex)
+    '2232:1013',
+    # (C-10HDP11538N) (lumpy)
+    '2232:1017',
+    # (Namuga) (link)
+    '2232:1033',
+    # (C-03FFM12339N) (daisy)
+    '2232:1037',
+    # (C-10HDO13531N) (peach)
+    '2232:1056',
+    # (NCM-G102) (samus)
+    '2232:6001',
+    # Acer (stout)
+    '5986:0299',
+]
+
+# Bluetooth Host Controller
+USB_IDS += [
+    # Hon-hai (parrot)
+    '0489:e04e',
+    # Hon-hai (peppy)
+    '0489:e056',
+    # Hon-hai (Kahlee)
+    '0489:e09f',
+    # QCA6174A (delan)
+    '0489:e0a2',
+    # LiteOn (parrot)
+    '04ca:3006',
+    # LiteOn (aleena)
+    '04ca:3016',
+    # LiteOn (scarlet)
+    '04ca:301a',
+    # Atheros (stumpy, stout)
+    '0cf3:3004',
+    # Atheros (AR3011) (mario, alex, zgb)
+    '0cf3:3005',
+    # Atheros (stumyp)
+    '0cf3:3007',
+    # Atheros (butterfly)
+    '0cf3:311e',
+    # Atheros (scarlet)
+    '0cf3:e300',
+    # Marvell (rambi)
+    '1286:2046',
+    # Marvell (gru)
+    '1286:204e',
+    # Intel (rambi, samus)
+    '8087:07dc',
+    # Intel (strago, glados)
+    '8087:0a2a',
+    # Intel (octopus)
+    '8087:0aaa',
+    # Intel (hatch)
+    '8087:0026',
+    # Intel (atlas)
+    '8087:0025',
+]
+
+# WWAN (LTE)
+USB_IDS += [
+    # Huawei (ME936) (kip)
+    '12d1:15bb',
+    # Fibocom (L850-GL) (coral, nautilus, sarien)
+    '2cb7:0007',
+]
+
+# Mass Storage
+USB_IDS += [
+    # Genesys (SD card reader) (lumpy, link, peppy)
+    '05e3:0727',
+    # Realtek (SD card reader) (mario, alex)
+    '0bda:0138',
+    # Realtek (SD card reader) (helios)
+    '0bda:0136',
+    # Realtek (SD card reader) (falco)
+    '0bda:0177',
+]
+
+# Security Key
+USB_IDS += [
+    # Yubico.com
+    '1050:0211',
+    # Yubico.com (HID firmware)
+    '1050:0200',
+    # Google Titan key
+    '18d1:5026',
+]
+
+# USB Audio devices
+USB_IDS += [
+    # Google USB-C to 3.5mm Digital Headphone Jack Adapter 'Mir'
+    '18d1:5025',
+    # Google USB-C to 3.5mm Digital Headphone Jack Adapter 'Mir' (HID only)
+    '18d1:5029',
+    # Google USB-C to 3.5mm Digital Headphone Jack Adapter 2018 'Condor'
+    '18d1:5034',
+    # Google Pixel USB-C Earbuds 'Blackbird'
+    '18d1:5033',
+    # Libratone Q Adapt In-Ear USB-C Earphones, Made for Google
+    '03eb:2433',
+    # Moshi USB-C to 3.5 mm Adapter/Charger, Made for Google
+    '282b:48f0',
+    # Moshi USB-C to 3.5 mm Adapter/Charger, Made for Google (HID only)
+    '282b:0026',
+    # AiAiAi TMA-2 C60 Cable, Made for Google
+    '0572:1a08',
+    # Apple USB-C to 3.5mm Headphone Jack Adapter
+    '05ac:110a',
+]
+
+# List of PCI devices (vendorid:deviceid) for which it is safe to enable
+# autosuspend.
+PCI_IDS = []
+
+# Intel
+PCI_IDS += [
+    # Host bridge
+    '8086:590c',
+    # i915
+    '8086:591e',
+    # proc_thermal
+    '8086:1903',
+    # xhci_hcd
+    '8086:9d2f',
+    # intel_pmc_core
+    '8086:9d21',
+    # i801_smbus
+    '8086:9d23',
+    # iwlwifi
+    '8086:095a',
+    # GMM
+    '8086:1911',
+    # Thermal
+    '8086:9d31',
+    # MME
+    '8086:9d3a',
+    # CrOS EC
+    '8086:9d4b',
+    # PCH SPI
+    '8086:9d24',
+    # SATA
+    '8086:02d3',
+    # RAM memory
+    '8086:02ef',
+    # ISA bridge
+    '8086:0284',
+    # Communication controller
+    '8086:02e0',
+    # Network controller
+    '8086:02f0',
+    # Serial bus controller
+    '8086:02a4',
+    # USB controller
+    '8086:02ed',
+    # Graphics
+    '8086:9b41',
+    # DSP
+    '8086:02f9',
+    # Host bridge
+    '8086:9b61',
+    # Host bridge
+    '8086:9b71',
+    # PCI Bridge
+    '8086:02b0',
+    # i915 (atlas)
+    '8086:591c',
+    # iwlwifi (atlas)
+    '8086:2526',
+]
+
+# Samsung
+PCI_IDS += [
+    # NVMe KUS030205M-B001
+    '144d:a806',
+    # NVMe MZVLB256HAHQ
+    '144d:a808',
+]
+
+# Lite-on
+PCI_IDS += [
+    # 3C07110288
+    '14a4:9100',
+]
+
+# Seagate
+PCI_IDS += [
+    # ZP256CM30011
+    '7089:5012',
+]
+
+# Kingston
+PCI_IDS += [
+    # RBUSNS8154P3128GJ3
+    '2646:5008',
+]
+
+################################################################################
+
+UDEV_RULE = """\
+ACTION!="add", GOTO="autosuspend_end"
+SUBSYSTEM!="i2c|pci|usb", GOTO="autosuspend_end"
+
+SUBSYSTEM=="i2c", GOTO="autosuspend_i2c"
+SUBSYSTEM=="pci", GOTO="autosuspend_pci"
+SUBSYSTEM=="usb", GOTO="autosuspend_usb"
+
+# I2C rules
+LABEL="autosuspend_i2c"
+ATTR{name}=="cyapa", ATTR{power/control}="on", GOTO="autosuspend_end"
+GOTO="autosuspend_end"
+
+# PCI rules
+LABEL="autosuspend_pci"
+%(pci_rules)s\
+GOTO="autosuspend_end"
+
+# USB rules
+LABEL="autosuspend_usb"
+%(usb_rules)s\
+GOTO="autosuspend_end"
+
+# Enable autosuspend
+LABEL="autosuspend_enable"
+TEST=="power/control", ATTR{power/control}="auto", GOTO="autosuspend_end"
+
+LABEL="autosuspend_end"
+"""
+
+
+def main():
+  pci_rules = ''
+  for dev_ids in PCI_IDS:
+    vendor, device = dev_ids.split(':')
+    pci_rules += ('ATTR{vendor}=="0x%s", ATTR{device}=="0x%s", '
+                  'GOTO="autosuspend_enable"\n' % (vendor, device))
+
+  usb_rules = ''
+  for dev_ids in USB_IDS:
+    vid, pid = dev_ids.split(':')
+    usb_rules += ('ATTR{idVendor}=="%s", ATTR{idProduct}=="%s", '
+                  'GOTO="autosuspend_enable"\n' % (vid, pid))
+
+  print(UDEV_RULE % {'pci_rules': pci_rules, 'usb_rules': usb_rules})
+
+
+if __name__ == '__main__':
+  main()
diff --git a/tools/make-autosuspend-rules.py b/tools/make-autosuspend-rules.py
new file mode 100755 (executable)
index 0000000..7327316
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: LGPL-2.1+
+
+# Generate autosuspend rules for devices that have been whitelisted (IE tested)
+# by the ChromeOS team. Please keep this script in sync with:
+# https://chromium.googlesource.com/chromiumos/platform2/+/master/power_manager/udev/gen_autosuspend_rules.py
+
+import sys
+import chromeos.gen_autosuspend_rules
+
+if __name__ == '__main__':
+    if len(sys.argv) > 1:
+        sys.stdout = open(sys.argv[1], 'w')
+    chromeos.gen_autosuspend_rules.main()
index 9ea3bb914efbd2a4470d084ece0766b9e2098873..5c6275e5b3043ee7be6e395fa449059f618ccfa7 100644 (file)
@@ -42,6 +42,7 @@ SystemCallArchitectures=native
 SystemCallErrorNumber=EPERM
 SystemCallFilter=@system-service
 Type=notify
+RestartKillSignal=SIGUSR2
 User=systemd-network
 WatchdogSec=3min