]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #16046 from bluca/dissect_squashfs_verity
authorLennart Poettering <lennart@poettering.net>
Tue, 9 Jun 2020 17:52:21 +0000 (19:52 +0200)
committerGitHub <noreply@github.com>
Tue, 9 Jun 2020 17:52:21 +0000 (19:52 +0200)
dissect: single-filesystem verity images with external hashdevice

52 files changed:
.gitignore
TODO
docs/USER_GROUP_API.md
hwdb.d/60-keyboard.hwdb
hwdb.d/60-sensor.hwdb
man/crypttab.xml
man/kernel-command-line.xml
man/systemd-udevd.service.xml
man/systemd.automount.xml
man/systemd.network.xml
man/systemd.service.xml
man/udevadm.xml
shell-completion/bash/homectl [new file with mode: 0644]
shell-completion/bash/loginctl
src/basic/hashmap.c
src/basic/hashmap.h
src/basic/mountpoint-util.c
src/basic/mountpoint-util.h
src/basic/ordered-set.h
src/basic/set.h
src/basic/strv.c
src/basic/strv.h
src/basic/unit-def.c
src/basic/unit-def.h
src/core/dbus-service.c
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/service.c
src/core/service.h
src/core/slice.c
src/cryptsetup/cryptsetup.c
src/kernel-install/kernel-install [changed mode: 0644->0755]
src/libsystemd/sd-network/sd-network.c
src/login/71-seat.rules.in
src/mount/mount-tool.c
src/network/networkctl.c
src/network/networkd-link.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/shared/bus-unit-util.c
src/systemd/sd-network.h
src/udev/udevd.c
test/fuzz/fuzz-network-parser/directives.network
test/test-network/conf/25-sysctl.network
test/test-network/systemd-networkd-tests.py
test/units/testsuite-38.sh
tools/gdb-sd_dump_hashmaps.py
units/initrd-udevadm-cleanup-db.service
units/systemd-udev-settle.service
units/systemd-udev-trigger.service

index 5d1870553150b93ae8316c638b0972ba5e560ce9..f47de39f3ddf11f060ffcdb532e6f49cc2896769 100644 (file)
@@ -12,6 +12,8 @@
 .config.args
 .gdb_history
 .deps/
+.mypy_cache/
+__pycache__/
 /*.gcda
 /*.gcno
 /*.tar.bz2
@@ -34,4 +36,3 @@
 /mkosi.builddir/
 /mkosi.output/
 /tags
-__pycache__/
diff --git a/TODO b/TODO
index dd9907b2c0dd829d7d99b66ed72a324f4026c7ec..c4275b48e0852348d4b6fd4d3f0998ff3bcd007c 100644 (file)
--- a/TODO
+++ b/TODO
@@ -19,6 +19,14 @@ Janitorial Clean-ups:
 
 Features:
 
+* add systemd.random_seed= on the kernel cmdline, taking some hex or base64
+  encoded data. During earliest boot, credit it to entropy. This is not useful
+  for general purpose systems, but certainly for testing environments in VMs
+  and such, as it allows us to boot up instantly with fully initialized entropy
+  pool even if RNG pass-thru is not available.
+
+* Support ProtectProc= or so, using: https://patchwork.kernel.org/cover/11310197/
+
 * if /usr/bin/swapoff fails due to OOM, log a friendly explanatory message about it
 
 * build short web pages out of each catalog entry, build them along with man
index 8ec1823149371a751327e004ba3d1684cb319847..ebff6e69034fb7baa0744acd8104376e10c1b2ed 100644 (file)
@@ -160,7 +160,7 @@ method GetUserRecord(
         service : string
 ) -> (
         record : object,
-        incomplete : boolean
+        incomplete : bool
 )
 
 method GetGroupRecord(
@@ -169,7 +169,7 @@ method GetGroupRecord(
         service : string
 ) -> (
         record : object,
-        incomplete : boolean
+        incomplete : bool
 )
 
 method GetMemberships(
index 875bf66bd82691125e1f549f748a65a13e6e4e5d..99fd78c36435f8fa83571989ce994f66e6002d66 100644 (file)
@@ -529,6 +529,10 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*[sS][pP][eE][cC][tT][rR][eE]*x360Convert
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*13*x360*:pvr*
  KEYBOARD_KEY_d7=unknown
 
+# Spectre x360 13
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPSpectrex360Convertible13*:pvr*
+ KEYBOARD_KEY_82=f20                                    # Fn+F12; Microphone mute button, should be micmute
+
 # Elitebook
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:pvr*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:pvr*
index f16724df9d609679cb8569aa05de99e8d227068e..52cd71b5347ab78dc974b70e7746857504e832ed 100644 (file)
@@ -312,6 +312,10 @@ sensor:modalias:platform:cros-ec-accel:dmi:*:svnGOOGLE*
 sensor:modalias:platform:cros-ec-accel:dmi:*:svnGoogle:pnCaroline*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
 
+# Dell Inspiron Chromebook 14 2-in-1
+sensor:modalias:platform:cros-ec-accel:dmi:*svnGoogle:pnVayne*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
+
 #########################################
 # GP-electronic
 #########################################
index 3170e5880fd7f4293e0dc38130ef1ef0aff0476f..2046911c7849517771c627b6ec39c08ee58d4420 100644 (file)
         <option>size=</option>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>bitlk</option></term>
+
+        <listitem><para>Decrypt Bitlocker drive. Encryption parameters
+        are deduced by cryptsetup from Bitlocker header.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>_netdev</option></term>
 
index 7e59a1aaede8514e9ab55e20ed7612a17b166593..52939deec0b15967d82a9e45816c2cee7ed5ec7b 100644 (file)
         <term><varname>rd.udev.event_timeout=</varname></term>
         <term><varname>udev.timeout_signal=</varname></term>
         <term><varname>rd.udev.timeout_signal=</varname></term>
-
+        <term><varname>udev.blockdev_read_only</varname></term>
+        <term><varname>rd.udev.blockdev_read_only</varname></term>
         <term><varname>net.ifnames=</varname></term>
         <term><varname>net.naming-scheme=</varname></term>
 
index 55edc17353f43f9721c545f1f51116650062a687..c6c1d9bcc626ac5197e2692b5665b1ed22b46126 100644 (file)
@@ -77,7 +77,7 @@
       </varlistentry>
 
       <varlistentry>
-        <term><option>-c=</option></term>
+        <term><option>-c</option></term>
         <term><option>--children-max=</option></term>
         <listitem>
           <para>Limit the number of events executed in parallel.</para>
@@ -85,7 +85,7 @@
       </varlistentry>
 
       <varlistentry>
-        <term><option>-e=</option></term>
+        <term><option>-e</option></term>
         <term><option>--exec-delay=</option></term>
         <listitem>
           <para>Delay the execution of <varname>RUN</varname>
@@ -97,7 +97,7 @@
       </varlistentry>
 
       <varlistentry>
-        <term><option>-t=</option></term>
+        <term><option>-t</option></term>
         <term><option>--event-timeout=</option></term>
         <listitem>
           <para>Set the number of seconds to wait for events to finish. After
       </varlistentry>
 
       <varlistentry>
-        <term><option>-N=</option></term>
+        <term><option>-N</option></term>
         <term><option>--resolve-names=</option></term>
         <listitem>
           <para>Specify when systemd-udevd should resolve names of users and groups.
 
   <refsect1><title>Kernel command line</title>
     <variablelist class='kernel-commandline-options'>
-      <para>Parameters starting with "rd." will be read when
-      <command>systemd-udevd</command> is used in an initrd.</para>
+      <para>Parameters prefixed with "rd." will be read when <command>systemd-udevd</command> is used in an
+      initrd, those without will be processed both in the initrd and on the host.</para>
       <varlistentry>
         <term><varname>udev.log_priority=</varname></term>
         <term><varname>rd.udev.log_priority=</varname></term>
           setting in the configuration file and the one on the program command line.</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>udev.blockdev_read_only</varname></term>
+        <term><varname>rd.udev.blockdev_read_only</varname></term>
+        <listitem>
+          <para>If specified, mark all physical block devices read-only as they appear. Synthetic block
+          devices (such as loopback block devices or device mapper devices) are left as they are. This is
+          useful to guarantee that the contents of physical block devices remains unmodified during runtime,
+          for example to implement fully stateless systems, for testing or for recovery situations where
+          corrupted file systems shall not be corrupted further through accidental modification.</para>
+
+          <para>A block device may be marked writable again by issuing the <command>blockdev
+          --setrw</command> command, see <citerefentry
+          project='man-pages'><refentrytitle>blockdev</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+          for details.</para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><varname>net.ifnames=</varname></term>
         <listitem>
index 35690fd22a7539527ffb69a01b0d0650c2098dee..fd65f5da798b1377d2047a3c923e23f074f1c381 100644 (file)
 
     <para>Automount units may be used to implement on-demand mounting
     as well as parallelized mounting of file systems.</para>
+
+    <para>Note that automount units are separate from the mount itself, so you
+    should not set <varname>After=</varname> or <varname>Requires=</varname>
+    for mount dependencies here. For example, you should not set
+    <varname>After=network-online.target</varname> or similar on network
+    filesystems. Doing so may result in an ordering cycle.</para>
   </refsect1>
 
   <refsect1>
index d23e8a548c1b972438dfb718bb723733639a62b7..ae93a39eb462dcb5b925dd9f281fed4763e025f3 100644 (file)
           When unset, the kernel's default will be used.
         </para></listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>IPv4AcceptLocal=</varname></term>
+          <listitem><para>Takes a boolean. Accept packets with local source addresses. In combination
+          with suitable routing, this can be used to direct packets between two local interfaces over
+          the wire and have them accepted properly. When unset, the kernel's default will be used.
+          </para></listitem>
+        </varlistentry>
         <varlistentry>
           <term><varname>IPv4ProxyARP=</varname></term>
           <listitem><para>Takes a boolean. Configures proxy ARP for IPv4. Proxy ARP is the technique in which one host,
index e8c869244a2b0b4b42059b83a72de20849e9cd35..a4a49f39af2ecf6e64d45ae91730bf3015fd2228 100644 (file)
 
       <varlistentry>
         <term><varname>TimeoutStartSec=</varname></term>
-        <listitem><para>Configures the time to wait for start-up. If a
-        daemon service does not signal start-up completion within the
-        configured time, the service will be considered failed and
-        will be shut down again. Takes a unit-less value in seconds,
-        or a time span value such as "5min 20s". Pass
-        <literal>infinity</literal> to disable the timeout logic. Defaults to
-        <varname>DefaultTimeoutStartSec=</varname> from the manager
-        configuration file, except when
-        <varname>Type=oneshot</varname> is used, in which case the
-        timeout is disabled by default (see
+        <listitem><para>Configures the time to wait for start-up. If a daemon service does not signal start-up
+        completion within the configured time, the service will be considered failed and will be shut down again. The
+        precise action depends on the <varname>TimeoutStartFailureMode=</varname> option. Takes a unit-less value in
+        seconds, or a time span value such as "5min 20s". Pass <literal>infinity</literal> to disable the timeout logic.
+        Defaults to <varname>DefaultTimeoutStartSec=</varname> from the manager configuration file, except when
+        <varname>Type=oneshot</varname> is used, in which case the timeout is disabled by default (see
         <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
         </para>
 
         <listitem><para>This option serves two purposes. First, it configures the time to wait for each
         <varname>ExecStop=</varname> command. If any of them times out, subsequent <varname>ExecStop=</varname> commands
         are skipped and the service will be terminated by <constant>SIGTERM</constant>. If no <varname>ExecStop=</varname>
-        commands are specified, the service gets the <constant>SIGTERM</constant> immediately. Second, it configures the time
+        commands are specified, the service gets the <constant>SIGTERM</constant> immediately. This default behavior
+        can be changed by the <varname>TimeoutStopFailureMode=</varname> option. Second, it configures the time
         to wait for the service itself to stop. If it doesn't terminate in the specified time, it will be forcibly terminated
         by <constant>SIGKILL</constant> (see <varname>KillMode=</varname> in
         <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
         </para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>TimeoutStartFailureMode=</varname></term>
+        <term><varname>TimeoutStopFailureMode=</varname></term>
+
+        <listitem><para>These options configure the action that is taken in case a daemon service does not signal
+        start-up within its configured <varname>TimeoutStartSec=</varname>, respectively if it does not stop within
+        <varname>TimeoutStopSec=</varname>. Takes one of <option>terminate</option>, <option>abort</option> and
+        <option>kill</option>. Both options default to <option>terminate</option>.</para>
+
+        <para>If <option>terminate</option> is set the service will be gracefully terminated by sending the signal
+        specified in <varname>KillSignal=</varname> (defaults to <constant>SIGTERM</constant>, see
+        <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If the
+        service does not terminate the <varname>FinalKillSignal=</varname> is sent after
+        <varname>TimeoutStopSec=</varname>. If <option>abort</option> is set, <varname>WatchdogSignal=</varname> is sent
+        instead and <varname>TimeoutAbortSec=</varname> applies before sending <varname>FinalKillSignal=</varname>.
+        This setting may be used to analyze services that fail to start-up or shut-down intermittently.
+        By using <option>kill</option> the service is immediately terminated by sending
+        <varname>FinalKillSignal=</varname> without any further timeout. This setting can be used to expedite the
+        shutdown of failing services.
+        </para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>RuntimeMaxSec=</varname></term>
 
index c2f2bc95d217dcb0a43e5ff0554ff769e6f9703f..a716b1819d783cdc8a67e788c89c23d20523b288 100644 (file)
             <para>Maximum number of seconds to wait for the event
             queue to become empty. The default value is 120 seconds. A
             value of 0 will check if the queue is empty and always
-            return immediately.</para>
+            return immediately. A non-zero value will return an exit
+            code of 0 if queue became empty before timeout was reached,
+            non-zero otherwise.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
diff --git a/shell-completion/bash/homectl b/shell-completion/bash/homectl
new file mode 100644 (file)
index 0000000..c2a9e61
--- /dev/null
@@ -0,0 +1,189 @@
+# hostctl(1) completion                               -*- shell-script -*-
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# systemd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+__contains_word () {
+    local w word=$1; shift
+    for w in "$@"; do
+        [[ $w = "$word" ]] && return
+    done
+}
+
+__get_machines() {
+    local a b
+    machinectl list --full --no-legend --no-pager 2>/dev/null |
+        { while read a b; do echo " $a"; done; };
+}
+
+__get_homes() {
+    homectl --no-pager --no-legend list 2>/dev/null
+}
+
+_homectl() {
+    local i verb comps
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+
+    local -A OPTS=(
+        [STANDALONE]='-h --help --version
+                     --no-pager --no-legend --no-ask-password
+                     -j -E -P'
+        [ARG]='      -H --host
+                     -M --machine
+                        --identity
+                        --json
+                        --export-format
+                     -c --real-name
+                        --realm
+                        --email-address
+                        --location
+                        --icon-name
+                     -d --home-dir
+                        --uid
+                     -G --member-of
+                        --skel
+                        --shell
+                        --setenv
+                        --timezone
+                        --language
+                        --ssh-authorized-keys
+                        --pkcs11-token-uri
+                        --locked
+                        --not-before
+                        --not-after
+                        --rate-limit-interval
+                        --rate-limit-burst
+                        --password-hint
+                        --enforce-password-policy
+                        --password-change-now
+                        --password-change-min
+                        --password-change-max
+                        --password-change-warn
+                        --password-change-inactive
+                        --disk-size
+                        --access-mode
+                        --umask
+                        --nice
+                        --rlimit
+                        --tasks-max
+                        --memory-high
+                        --memory-max
+                        --cpu-weight
+                        --io-weight
+                        --storage
+                        --image-path
+                        --fs-type
+                        --luks-discard
+                        --luks-offline-discard
+                        --luks-cipher
+                        --luks-cipher-mode
+                        --luks-volume-key-size
+                        --luks-pbkdf-type
+                        --luks-pbkdf-hash-algorithm
+                        --luks-pbkdf-time-cost
+                        --luks-pbkdf-memory-cost
+                        --luks-pbkdf-parallel-threads
+                        --nosuid
+                        --nodev
+                        --noexec
+                        --cifs-domain
+                        --cifs-user-name
+                        --cifs-service
+                        --stop-delay
+                        --kill-processes
+                        --auto-login'
+    )
+
+    if __contains_word "$prev" ${OPTS[ARG]}; then
+        case $prev in
+            --host|-H)
+                comps=$(compgen -A hostname)
+                ;;
+            --machine|-M)
+                comps=$( __get_machines )
+                ;;
+            --identity|--image-path)
+                comps=$(compgen -A file -- "$cur" )
+                compopt -o filenames
+                ;;
+            --json)
+                comps='pretty short off'
+                ;;
+            --export-format)
+                comps='full stripped minimal'
+                ;;
+            --locked|--enforce-password-policy|--password-change-now|--luks-discard|--luks-offline-discard|--nosuid|--nodev|--noexec|--kill-processes|--auto-login)
+                comps='yes no'
+                ;;
+            -d|--home-dir|--skel)
+                comps=$(compgen -A directory -- "$cur" )
+                compopt -o dirnames
+                ;;
+            -G|--member-of)
+                comps=$(compgen -A group -- "$cur" )
+                ;;
+            --shell)
+                comps=$(cat /etc/shells)
+                ;;
+            --fs-type)
+                comps='ext4 xfs btrsf'
+                ;;
+            --cifs-user-name)
+                comps=$(compgen -A user -- "$cur" )
+                ;;
+        esac
+        COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
+        return 0
+    fi
+
+    if [[ "$cur" = -* ]]; then
+        COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
+        return 0
+    fi
+
+    local -A VERBS=(
+        [STANDALONE]='list lock-all'
+        [CREATE]='create'
+        [NAMES]='activate deactivate inspect authenticate remove lock unlock'
+        [NAME]='update passwd'
+        [RESIZE]='resize'
+        [WITH]='with'
+    )
+
+    for ((i=0; i < COMP_CWORD; i++)); do
+        if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]}; then
+            verb=${COMP_WORDS[i]}
+            break
+        fi
+    done
+
+    if [[ -z $verb ]]; then
+        comps=${VERBS[*]}
+    elif __contains_word "$verb" ${VERBS[NAME]}; then
+        comps=$(__get_homes)
+    elif __contains_word "$verb" ${VERBS[NAMES]}; then
+        comps=$(__get_homes)
+    elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[CREATE]} ${VERBS[RESIZE]}; then
+        comps=$(__get_homes)
+    elif __contains_word "$verb" ${VERBS[WITH]}; then
+        comps=$(__get_homes)
+    fi
+
+    COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
+    return 0
+}
+
+complete -F _homectl homectl
index 35a71de32e812c2e97fd2e7daefabfe059740ac9..69b999c05d5e065115bd1605f9cccda976c6723c 100644 (file)
@@ -72,7 +72,6 @@ _loginctl () {
         return 0
     fi
 
-
     if [[ "$cur" = -* ]]; then
         COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
         return 0
index efbe95bb9e33f90e087fdad9e45b95da5e87a315..3172865e3e2a4725bd8598a8a9c3e8d87f78c0dd 100644 (file)
@@ -145,12 +145,7 @@ struct hashmap_debug_info {
 /* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */
 static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list);
 static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-#define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug;
-
-#else /* !ENABLE_DEBUG_HASHMAP */
-#define HASHMAP_DEBUG_FIELDS
-#endif /* ENABLE_DEBUG_HASHMAP */
+#endif
 
 enum HashmapType {
         HASHMAP_TYPE_PLAIN,
@@ -212,7 +207,10 @@ struct HashmapBase {
         bool from_pool:1;            /* whether was allocated from mempool */
         bool dirty:1;                /* whether dirtied since last iterated_cache_get() */
         bool cached:1;               /* whether this hashmap is being cached */
-        HASHMAP_DEBUG_FIELDS         /* optional hashmap_debug_info */
+
+#if ENABLE_DEBUG_HASHMAP
+        struct hashmap_debug_info debug;
+#endif
 };
 
 /* Specific hash types
@@ -254,7 +252,7 @@ struct hashmap_type_info {
         unsigned n_direct_buckets;
 };
 
-static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
+static _used_ const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
         [HASHMAP_TYPE_PLAIN] = {
                 .head_size        = sizeof(Hashmap),
                 .entry_size       = sizeof(struct plain_hashmap_entry),
@@ -707,7 +705,7 @@ static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
                                                : hashmap_iterate_in_internal_order(h, i);
 }
 
-bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
+bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
         struct hashmap_base_entry *e;
         void *data;
         unsigned idx;
@@ -733,7 +731,7 @@ bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const v
 }
 
 bool set_iterate(const Set *s, Iterator *i, void **value) {
-        return internal_hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL);
+        return _hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL);
 }
 
 #define HASHMAP_FOREACH_IDX(idx, h, i) \
@@ -741,7 +739,7 @@ bool set_iterate(const Set *s, Iterator *i, void **value) {
              (idx != IDX_NIL); \
              (idx) = hashmap_iterate_entry((h), &(i)))
 
-IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h) {
+IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h) {
         IteratedCache *cache;
 
         assert(h);
@@ -809,15 +807,15 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
         return h;
 }
 
-Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
+Hashmap *_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
         return (Hashmap*)        hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
 }
 
-OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
+OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
         return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
 }
 
-Set *internal_set_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
+Set *_set_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
         return (Set*)            hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
 }
 
@@ -838,15 +836,15 @@ static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops
         return 0;
 }
 
-int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
+int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
         return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
 }
 
-int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
+int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
         return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
 }
 
-int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
+int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
         return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
 }
 
@@ -868,16 +866,16 @@ static void hashmap_free_no_clear(HashmapBase *h) {
                 free(h);
 }
 
-HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
+HashmapBase *_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
         if (h) {
-                internal_hashmap_clear(h, default_free_key, default_free_value);
+                _hashmap_clear(h, default_free_key, default_free_value);
                 hashmap_free_no_clear(h);
         }
 
         return NULL;
 }
 
-void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
+void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
         free_func_t free_key, free_value;
         if (!h)
                 return;
@@ -891,11 +889,11 @@ void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_f
                  * hash table, and only then call the destructor functions. If these destructors then try to unregister
                  * themselves from our hash table a second time, the entry is already gone. */
 
-                while (internal_hashmap_size(h) > 0) {
+                while (_hashmap_size(h) > 0) {
                         void *k = NULL;
                         void *v;
 
-                        v = internal_hashmap_first_key_and_value(h, true, &k);
+                        v = _hashmap_first_key_and_value(h, true, &k);
 
                         if (free_key)
                                 free_key(k);
@@ -1301,7 +1299,7 @@ int hashmap_update(Hashmap *h, const void *key, void *value) {
         return 0;
 }
 
-void *internal_hashmap_get(HashmapBase *h, const void *key) {
+void *_hashmap_get(HashmapBase *h, const void *key) {
         struct hashmap_base_entry *e;
         unsigned hash, idx;
 
@@ -1336,7 +1334,7 @@ void *hashmap_get2(Hashmap *h, const void *key, void **key2) {
         return e->value;
 }
 
-bool internal_hashmap_contains(HashmapBase *h, const void *key) {
+bool _hashmap_contains(HashmapBase *h, const void *key) {
         unsigned hash;
 
         if (!h)
@@ -1346,7 +1344,7 @@ bool internal_hashmap_contains(HashmapBase *h, const void *key) {
         return bucket_scan(h, hash, key) != IDX_NIL;
 }
 
-void *internal_hashmap_remove(HashmapBase *h, const void *key) {
+void *_hashmap_remove(HashmapBase *h, const void *key) {
         struct hashmap_base_entry *e;
         unsigned hash, idx;
         void *data;
@@ -1484,7 +1482,7 @@ int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_
         return 0;
 }
 
-void *internal_hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
+void *_hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
         struct hashmap_base_entry *e;
         unsigned hash, idx;
 
@@ -1514,7 +1512,7 @@ static unsigned find_first_entry(HashmapBase *h) {
         return hashmap_iterate_entry(h, &i);
 }
 
-void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
+void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
         struct hashmap_base_entry *e;
         void *key, *data;
         unsigned idx;
@@ -1539,21 +1537,21 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r
         return data;
 }
 
-unsigned internal_hashmap_size(HashmapBase *h) {
+unsigned _hashmap_size(HashmapBase *h) {
         if (!h)
                 return 0;
 
         return n_entries(h);
 }
 
-unsigned internal_hashmap_buckets(HashmapBase *h) {
+unsigned _hashmap_buckets(HashmapBase *h) {
         if (!h)
                 return 0;
 
         return n_buckets(h);
 }
 
-int internal_hashmap_merge(Hashmap *h, Hashmap *other) {
+int _hashmap_merge(Hashmap *h, Hashmap *other) {
         Iterator i;
         unsigned idx;
 
@@ -1589,7 +1587,7 @@ int set_merge(Set *s, Set *other) {
         return 0;
 }
 
-int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) {
+int _hashmap_reserve(HashmapBase *h, unsigned entries_add) {
         int r;
 
         assert(h);
@@ -1607,7 +1605,7 @@ int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) {
  * Returns: 0 on success.
  *          -ENOMEM on alloc failure, in which case no move has been done.
  */
-int internal_hashmap_move(HashmapBase *h, HashmapBase *other) {
+int _hashmap_move(HashmapBase *h, HashmapBase *other) {
         struct swap_entries swap;
         struct hashmap_base_entry *e, *n;
         Iterator i;
@@ -1652,7 +1650,7 @@ int internal_hashmap_move(HashmapBase *h, HashmapBase *other) {
         return 0;
 }
 
-int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
+int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
         struct swap_entries swap;
         unsigned h_hash, other_hash, idx;
         struct hashmap_base_entry *e, *n;
@@ -1689,7 +1687,7 @@ int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *ke
         return 0;
 }
 
-HashmapBase *internal_hashmap_copy(HashmapBase *h) {
+HashmapBase *_hashmap_copy(HashmapBase *h) {
         HashmapBase *copy;
         int r;
 
@@ -1712,14 +1710,14 @@ HashmapBase *internal_hashmap_copy(HashmapBase *h) {
         }
 
         if (r < 0) {
-                internal_hashmap_free(copy, false, false);
+                _hashmap_free(copy, false, false);
                 return NULL;
         }
 
         return copy;
 }
 
-char **internal_hashmap_get_strv(HashmapBase *h) {
+char **_hashmap_get_strv(HashmapBase *h) {
         char **sv;
         Iterator i;
         unsigned idx, n;
index a3bc32814213a403b184e600409862ebe38148c8..230d322213bae8e610e1716401a9637c96a7f9a1 100644 (file)
@@ -14,7 +14,7 @@
  * will be treated as empty hashmap for all read operations. That way it is not
  * necessary to instantiate an object for each Hashmap use.
  *
- * If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap),
+ * If ENABLE_DEBUG_HASHMAP is defined (by configuring with -Ddebug-extra=hashmap),
  * the implementation will:
  * - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
  * - perform extra checks for invalid use of iterators
 
 typedef void* (*hashmap_destroy_t)(void *p);
 
-/* The base type for all hashmap and set types. Many functions in the
- * implementation take (HashmapBase*) parameters and are run-time polymorphic,
- * though the API is not meant to be polymorphic (do not call functions
- * internal_*() directly). */
+/* The base type for all hashmap and set types. Many functions in the implementation take (HashmapBase*)
+ * parameters and are run-time polymorphic, though the API is not meant to be polymorphic (do not call
+ * underscore-prefixed functions directly). */
 typedef struct HashmapBase HashmapBase;
 
 /* Specific hashmap/set types */
@@ -84,10 +83,10 @@ typedef struct {
 # define HASHMAP_DEBUG_PASS_ARGS
 #endif
 
-Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
-OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
-#define hashmap_new(ops) internal_hashmap_new(ops  HASHMAP_DEBUG_SRC_ARGS)
-#define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops  HASHMAP_DEBUG_SRC_ARGS)
+Hashmap *_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
+OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
+#define hashmap_new(ops) _hashmap_new(ops  HASHMAP_DEBUG_SRC_ARGS)
+#define ordered_hashmap_new(ops) _ordered_hashmap_new(ops  HASHMAP_DEBUG_SRC_ARGS)
 
 #define hashmap_free_and_replace(a, b)          \
         ({                                      \
@@ -97,57 +96,57 @@ OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops  HA
                 0;                              \
         })
 
-HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
+HashmapBase *_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
 static inline Hashmap *hashmap_free(Hashmap *h) {
-        return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, NULL);
+        return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
 }
 static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) {
-        return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, NULL);
+        return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
 }
 
 static inline Hashmap *hashmap_free_free(Hashmap *h) {
-        return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, free);
+        return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free);
 }
 static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) {
-        return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, free);
+        return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free);
 }
 
 static inline Hashmap *hashmap_free_free_key(Hashmap *h) {
-        return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, NULL);
+        return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL);
 }
 static inline OrderedHashmap *ordered_hashmap_free_free_key(OrderedHashmap *h) {
-        return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, NULL);
+        return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL);
 }
 
 static inline Hashmap *hashmap_free_free_free(Hashmap *h) {
-        return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, free);
+        return (void*) _hashmap_free(HASHMAP_BASE(h), free, free);
 }
 static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) {
-        return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, free);
+        return (void*) _hashmap_free(HASHMAP_BASE(h), free, free);
 }
 
 IteratedCache *iterated_cache_free(IteratedCache *cache);
 int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries);
 
-HashmapBase *internal_hashmap_copy(HashmapBase *h);
+HashmapBase *_hashmap_copy(HashmapBase *h);
 static inline Hashmap *hashmap_copy(Hashmap *h) {
-        return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
+        return (Hashmap*) _hashmap_copy(HASHMAP_BASE(h));
 }
 static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
-        return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
+        return (OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h));
 }
 
-int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
-int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
-#define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops  HASHMAP_DEBUG_SRC_ARGS)
-#define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops  HASHMAP_DEBUG_SRC_ARGS)
+int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
+int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
+#define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops  HASHMAP_DEBUG_SRC_ARGS)
+#define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops  HASHMAP_DEBUG_SRC_ARGS)
 
-IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h);
+IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h);
 static inline IteratedCache *hashmap_iterated_cache_new(Hashmap *h) {
-        return (IteratedCache*) internal_hashmap_iterated_cache_new(HASHMAP_BASE(h));
+        return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
 }
 static inline IteratedCache *ordered_hashmap_iterated_cache_new(OrderedHashmap *h) {
-        return (IteratedCache*) internal_hashmap_iterated_cache_new(HASHMAP_BASE(h));
+        return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
 }
 
 int hashmap_put(Hashmap *h, const void *key, void *value);
@@ -167,12 +166,12 @@ static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, vo
         return hashmap_replace(PLAIN_HASHMAP(h), key, value);
 }
 
-void *internal_hashmap_get(HashmapBase *h, const void *key);
+void *_hashmap_get(HashmapBase *h, const void *key);
 static inline void *hashmap_get(Hashmap *h, const void *key) {
-        return internal_hashmap_get(HASHMAP_BASE(h), key);
+        return _hashmap_get(HASHMAP_BASE(h), key);
 }
 static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) {
-        return internal_hashmap_get(HASHMAP_BASE(h), key);
+        return _hashmap_get(HASHMAP_BASE(h), key);
 }
 
 void *hashmap_get2(Hashmap *h, const void *key, void **rkey);
@@ -180,20 +179,20 @@ static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, voi
         return hashmap_get2(PLAIN_HASHMAP(h), key, rkey);
 }
 
-bool internal_hashmap_contains(HashmapBase *h, const void *key);
+bool _hashmap_contains(HashmapBase *h, const void *key);
 static inline bool hashmap_contains(Hashmap *h, const void *key) {
-        return internal_hashmap_contains(HASHMAP_BASE(h), key);
+        return _hashmap_contains(HASHMAP_BASE(h), key);
 }
 static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) {
-        return internal_hashmap_contains(HASHMAP_BASE(h), key);
+        return _hashmap_contains(HASHMAP_BASE(h), key);
 }
 
-void *internal_hashmap_remove(HashmapBase *h, const void *key);
+void *_hashmap_remove(HashmapBase *h, const void *key);
 static inline void *hashmap_remove(Hashmap *h, const void *key) {
-        return internal_hashmap_remove(HASHMAP_BASE(h), key);
+        return _hashmap_remove(HASHMAP_BASE(h), key);
 }
 static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) {
-        return internal_hashmap_remove(HASHMAP_BASE(h), key);
+        return _hashmap_remove(HASHMAP_BASE(h), key);
 }
 
 void *hashmap_remove2(Hashmap *h, const void *key, void **rkey);
@@ -201,9 +200,9 @@ static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key,
         return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey);
 }
 
-void *internal_hashmap_remove_value(HashmapBase *h, const void *key, void *value);
+void *_hashmap_remove_value(HashmapBase *h, const void *key, void *value);
 static inline void *hashmap_remove_value(Hashmap *h, const void *key, void *value) {
-        return internal_hashmap_remove_value(HASHMAP_BASE(h), key, value);
+        return _hashmap_remove_value(HASHMAP_BASE(h), key, value);
 }
 
 static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
@@ -222,41 +221,41 @@ static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const vo
 
 /* Since merging data from a OrderedHashmap into a Hashmap or vice-versa
  * should just work, allow this by having looser type-checking here. */
-int internal_hashmap_merge(Hashmap *h, Hashmap *other);
-#define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
+int _hashmap_merge(Hashmap *h, Hashmap *other);
+#define hashmap_merge(h, other) _hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
 #define ordered_hashmap_merge(h, other) hashmap_merge(h, other)
 
-int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add);
+int _hashmap_reserve(HashmapBase *h, unsigned entries_add);
 static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) {
-        return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+        return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
 }
 static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) {
-        return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+        return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
 }
 
-int internal_hashmap_move(HashmapBase *h, HashmapBase *other);
+int _hashmap_move(HashmapBase *h, HashmapBase *other);
 /* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */
 static inline int hashmap_move(Hashmap *h, Hashmap *other) {
-        return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
+        return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
 }
 static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) {
-        return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
+        return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
 }
 
-int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
+int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
 static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
-        return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
+        return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
 }
 static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) {
-        return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
+        return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
 }
 
-unsigned internal_hashmap_size(HashmapBase *h) _pure_;
+unsigned _hashmap_size(HashmapBase *h) _pure_;
 static inline unsigned hashmap_size(Hashmap *h) {
-        return internal_hashmap_size(HASHMAP_BASE(h));
+        return _hashmap_size(HASHMAP_BASE(h));
 }
 static inline unsigned ordered_hashmap_size(OrderedHashmap *h) {
-        return internal_hashmap_size(HASHMAP_BASE(h));
+        return _hashmap_size(HASHMAP_BASE(h));
 }
 
 static inline bool hashmap_isempty(Hashmap *h) {
@@ -266,49 +265,49 @@ static inline bool ordered_hashmap_isempty(OrderedHashmap *h) {
         return ordered_hashmap_size(h) == 0;
 }
 
-unsigned internal_hashmap_buckets(HashmapBase *h) _pure_;
+unsigned _hashmap_buckets(HashmapBase *h) _pure_;
 static inline unsigned hashmap_buckets(Hashmap *h) {
-        return internal_hashmap_buckets(HASHMAP_BASE(h));
+        return _hashmap_buckets(HASHMAP_BASE(h));
 }
 static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) {
-        return internal_hashmap_buckets(HASHMAP_BASE(h));
+        return _hashmap_buckets(HASHMAP_BASE(h));
 }
 
-bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key);
+bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key);
 static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) {
-        return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
+        return _hashmap_iterate(HASHMAP_BASE(h), i, value, key);
 }
 static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) {
-        return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
+        return _hashmap_iterate(HASHMAP_BASE(h), i, value, key);
 }
 
-void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
+void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
 static inline void hashmap_clear(Hashmap *h) {
-        internal_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
+        _hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
 }
 static inline void ordered_hashmap_clear(OrderedHashmap *h) {
-        internal_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
+        _hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
 }
 
 static inline void hashmap_clear_free(Hashmap *h) {
-        internal_hashmap_clear(HASHMAP_BASE(h), NULL, free);
+        _hashmap_clear(HASHMAP_BASE(h), NULL, free);
 }
 static inline void ordered_hashmap_clear_free(OrderedHashmap *h) {
-        internal_hashmap_clear(HASHMAP_BASE(h), NULL, free);
+        _hashmap_clear(HASHMAP_BASE(h), NULL, free);
 }
 
 static inline void hashmap_clear_free_key(Hashmap *h) {
-        internal_hashmap_clear(HASHMAP_BASE(h), free, NULL);
+        _hashmap_clear(HASHMAP_BASE(h), free, NULL);
 }
 static inline void ordered_hashmap_clear_free_key(OrderedHashmap *h) {
-        internal_hashmap_clear(HASHMAP_BASE(h), free, NULL);
+        _hashmap_clear(HASHMAP_BASE(h), free, NULL);
 }
 
 static inline void hashmap_clear_free_free(Hashmap *h) {
-        internal_hashmap_clear(HASHMAP_BASE(h), free, free);
+        _hashmap_clear(HASHMAP_BASE(h), free, free);
 }
 static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
-        internal_hashmap_clear(HASHMAP_BASE(h), free, free);
+        _hashmap_clear(HASHMAP_BASE(h), free, free);
 }
 
 /*
@@ -322,50 +321,50 @@ static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
  * the first entry is O(1).
  */
 
-void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key);
+void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key);
 static inline void *hashmap_steal_first_key_and_value(Hashmap *h, void **ret) {
-        return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
+        return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
 }
 static inline void *ordered_hashmap_steal_first_key_and_value(OrderedHashmap *h, void **ret) {
-        return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
+        return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
 }
 static inline void *hashmap_first_key_and_value(Hashmap *h, void **ret) {
-        return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
+        return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
 }
 static inline void *ordered_hashmap_first_key_and_value(OrderedHashmap *h, void **ret) {
-        return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
+        return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
 }
 
 static inline void *hashmap_steal_first(Hashmap *h) {
-        return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
+        return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
 }
 static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) {
-        return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
+        return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
 }
 static inline void *hashmap_first(Hashmap *h) {
-        return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
+        return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
 }
 static inline void *ordered_hashmap_first(OrderedHashmap *h) {
-        return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
+        return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
 }
 
-static inline void *internal_hashmap_first_key(HashmapBase *h, bool remove) {
+static inline void *_hashmap_first_key(HashmapBase *h, bool remove) {
         void *key = NULL;
 
-        (void) internal_hashmap_first_key_and_value(HASHMAP_BASE(h), remove, &key);
+        (void) _hashmap_first_key_and_value(HASHMAP_BASE(h), remove, &key);
         return key;
 }
 static inline void *hashmap_steal_first_key(Hashmap *h) {
-        return internal_hashmap_first_key(HASHMAP_BASE(h), true);
+        return _hashmap_first_key(HASHMAP_BASE(h), true);
 }
 static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) {
-        return internal_hashmap_first_key(HASHMAP_BASE(h), true);
+        return _hashmap_first_key(HASHMAP_BASE(h), true);
 }
 static inline void *hashmap_first_key(Hashmap *h) {
-        return internal_hashmap_first_key(HASHMAP_BASE(h), false);
+        return _hashmap_first_key(HASHMAP_BASE(h), false);
 }
 static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
-        return internal_hashmap_first_key(HASHMAP_BASE(h), false);
+        return _hashmap_first_key(HASHMAP_BASE(h), false);
 }
 
 #define hashmap_clear_with_destructor(_s, _f)                   \
@@ -394,12 +393,12 @@ static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
 /* no hashmap_next */
 void *ordered_hashmap_next(OrderedHashmap *h, const void *key);
 
-char **internal_hashmap_get_strv(HashmapBase *h);
+char **_hashmap_get_strv(HashmapBase *h);
 static inline char **hashmap_get_strv(Hashmap *h) {
-        return internal_hashmap_get_strv(HASHMAP_BASE(h));
+        return _hashmap_get_strv(HASHMAP_BASE(h));
 }
 static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
-        return internal_hashmap_get_strv(HASHMAP_BASE(h));
+        return _hashmap_get_strv(HASHMAP_BASE(h));
 }
 
 /*
index 0b3587ff5535037c0283feee909542988305fcf4..d4a621c7ae81be32e5a103b976163c7ee61da4e6 100644 (file)
@@ -338,6 +338,16 @@ bool fstype_is_api_vfs(const char *fstype) {
                           "tracefs");
 }
 
+bool fstype_is_blockdev_backed(const char *fstype) {
+        const char *x;
+
+        x = startswith(fstype, "fuse.");
+        if (x)
+                fstype = x;
+
+        return !streq(fstype, "9p") && !fstype_is_network(fstype) && !fstype_is_api_vfs(fstype);
+}
+
 bool fstype_is_ro(const char *fstype) {
         /* All Linux file systems that are necessarily read-only */
         return STR_IN_SET(fstype,
index 5398836fed4642f0d49095723075397d4c7a776f..ab4ed193945c74ecad9d55559e75744db71647ee 100644 (file)
@@ -14,6 +14,7 @@ int path_is_mount_point(const char *path, const char *root, int flags);
 
 bool fstype_is_network(const char *fstype);
 bool fstype_is_api_vfs(const char *fstype);
+bool fstype_is_blockdev_backed(const char *fstype);
 bool fstype_is_ro(const char *fsype);
 bool fstype_can_discard(const char *fstype);
 bool fstype_can_uid_gid(const char *fstype);
index 383a729cab869c834b409656d140d8447d97dfc8..a42a57eb49232c66172637798aa856806aa0a0ef 100644 (file)
@@ -59,7 +59,7 @@ static inline void* ordered_set_steal_first(OrderedSet *s) {
 }
 
 static inline char **ordered_set_get_strv(OrderedSet *s) {
-        return internal_hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s));
+        return _hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s));
 }
 
 int ordered_set_consume(OrderedSet *s, void *p);
index 8a95fec05f8f2647a2f910508edd1643ad14b553..621e83bf2773a6b1d40e03d6fb8d173b9f8f0e4a 100644 (file)
                 0;                              \
         })
 
-Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
+Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define set_new(ops) _set_new(ops HASHMAP_DEBUG_SRC_ARGS)
 
 static inline Set *set_free(Set *s) {
-        return (Set*) internal_hashmap_free(HASHMAP_BASE(s), NULL, NULL);
+        return (Set*) _hashmap_free(HASHMAP_BASE(s), NULL, NULL);
 }
 
 static inline Set *set_free_free(Set *s) {
-        return (Set*) internal_hashmap_free(HASHMAP_BASE(s), free, NULL);
+        return (Set*) _hashmap_free(HASHMAP_BASE(s), free, NULL);
 }
 
 /* no set_free_free_free */
 
 static inline Set *set_copy(Set *s) {
-        return (Set*) internal_hashmap_copy(HASHMAP_BASE(s));
+        return (Set*) _hashmap_copy(HASHMAP_BASE(s));
 }
 
-int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define set_ensure_allocated(h, ops) _set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
 
 int set_put(Set *s, const void *key);
 /* no set_update */
 /* no set_replace */
 static inline void *set_get(const Set *s, void *key) {
-        return internal_hashmap_get(HASHMAP_BASE((Set *) s), key);
+        return _hashmap_get(HASHMAP_BASE((Set *) s), key);
 }
 /* no set_get2 */
 
 static inline bool set_contains(const Set *s, const void *key) {
-        return internal_hashmap_contains(HASHMAP_BASE((Set *) s), key);
+        return _hashmap_contains(HASHMAP_BASE((Set *) s), key);
 }
 
 static inline void *set_remove(Set *s, const void *key) {
-        return internal_hashmap_remove(HASHMAP_BASE(s), key);
+        return _hashmap_remove(HASHMAP_BASE(s), key);
 }
 
 /* no set_remove2 */
@@ -56,19 +56,19 @@ int set_remove_and_put(Set *s, const void *old_key, const void *new_key);
 int set_merge(Set *s, Set *other);
 
 static inline int set_reserve(Set *h, unsigned entries_add) {
-        return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+        return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
 }
 
 static inline int set_move(Set *s, Set *other) {
-        return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other));
+        return _hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other));
 }
 
 static inline int set_move_one(Set *s, Set *other, const void *key) {
-        return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key);
+        return _hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key);
 }
 
 static inline unsigned set_size(const Set *s) {
-        return internal_hashmap_size(HASHMAP_BASE((Set *) s));
+        return _hashmap_size(HASHMAP_BASE((Set *) s));
 }
 
 static inline bool set_isempty(const Set *s) {
@@ -76,23 +76,23 @@ static inline bool set_isempty(const Set *s) {
 }
 
 static inline unsigned set_buckets(const Set *s) {
-        return internal_hashmap_buckets(HASHMAP_BASE((Set *) s));
+        return _hashmap_buckets(HASHMAP_BASE((Set *) s));
 }
 
 bool set_iterate(const Set *s, Iterator *i, void **value);
 
 static inline void set_clear(Set *s) {
-        internal_hashmap_clear(HASHMAP_BASE(s), NULL, NULL);
+        _hashmap_clear(HASHMAP_BASE(s), NULL, NULL);
 }
 
 static inline void set_clear_free(Set *s) {
-        internal_hashmap_clear(HASHMAP_BASE(s), free, NULL);
+        _hashmap_clear(HASHMAP_BASE(s), free, NULL);
 }
 
 /* no set_clear_free_free */
 
 static inline void *set_steal_first(Set *s) {
-        return internal_hashmap_first_key_and_value(HASHMAP_BASE(s), true, NULL);
+        return _hashmap_first_key_and_value(HASHMAP_BASE(s), true, NULL);
 }
 
 #define set_clear_with_destructor(_s, _f)               \
@@ -111,13 +111,13 @@ static inline void *set_steal_first(Set *s) {
 /* no set_first_key */
 
 static inline void *set_first(const Set *s) {
-        return internal_hashmap_first_key_and_value(HASHMAP_BASE((Set *) s), false, NULL);
+        return _hashmap_first_key_and_value(HASHMAP_BASE((Set *) s), false, NULL);
 }
 
 /* no set_next */
 
 static inline char **set_get_strv(Set *s) {
-        return internal_hashmap_get_strv(HASHMAP_BASE(s));
+        return _hashmap_get_strv(HASHMAP_BASE(s));
 }
 
 int set_consume(Set *s, void *value);
index f1d2bb5190b037bc57412b93284194c98aa2cc43..858e1e62ecc3bc5ed6c585d5f8ab1795174e7a2f 100644 (file)
@@ -946,20 +946,20 @@ static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const c
         return 1;
 }
 
-int string_strv_hashmap_put(Hashmap **h, const char *key, const char *value) {
+int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS) {
         int r;
 
-        r = hashmap_ensure_allocated(h, &string_strv_hash_ops);
+        r = _hashmap_ensure_allocated(h, &string_strv_hash_ops  HASHMAP_DEBUG_PASS_ARGS);
         if (r < 0)
                 return r;
 
         return string_strv_hashmap_put_internal(*h, key, value);
 }
 
-int string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value) {
+int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS) {
         int r;
 
-        r = ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops);
+        r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops  HASHMAP_DEBUG_PASS_ARGS);
         if (r < 0)
                 return r;
 
index 0f81e345800dbb2c2a05f0060a2a8444402330de..2ad927bce5163df4e0beebc11d96c0e14ac68411 100644 (file)
@@ -226,5 +226,7 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
         })
 
 extern const struct hash_ops string_strv_hash_ops;
-int string_strv_hashmap_put(Hashmap **h, const char *key, const char *value);
-int string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value);
+int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS);
+int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS);
+#define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v  HASHMAP_DEBUG_SRC_ARGS)
+#define string_strv_ordered_hashmap_put(h, k, v) _string_strv_ordered_hashmap_put(h, k, v  HASHMAP_DEBUG_SRC_ARGS)
index 64b2b2dd7e115ab98a6d5632a42eb06a3d08a23a..94ec1f3d19846307442a2c453ff653c7b00ce730 100644 (file)
@@ -185,6 +185,7 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = {
         [SERVICE_STOP_SIGTERM] = "stop-sigterm",
         [SERVICE_STOP_SIGKILL] = "stop-sigkill",
         [SERVICE_STOP_POST] = "stop-post",
+        [SERVICE_FINAL_WATCHDOG] = "final-watchdog",
         [SERVICE_FINAL_SIGTERM] = "final-sigterm",
         [SERVICE_FINAL_SIGKILL] = "final-sigkill",
         [SERVICE_FAILED] = "failed",
index a7d67819884f3785ad883b935ab5634fde88326d..53419ecd8a187f9b5f962648ac356bfc84c1f5b7 100644 (file)
@@ -127,6 +127,7 @@ typedef enum ServiceState {
         SERVICE_STOP_SIGTERM,
         SERVICE_STOP_SIGKILL,
         SERVICE_STOP_POST,
+        SERVICE_FINAL_WATCHDOG,    /* In case the STOP_POST executable needs to be aborted. */
         SERVICE_FINAL_SIGTERM,     /* In case the STOP_POST executable hangs, we shoot that down, too */
         SERVICE_FINAL_SIGKILL,
         SERVICE_FAILED,
index 11680f0d69c1c904e32493636425133115c532d4..5d4f4ef50684b00b65535f0df5b88123107ae685 100644 (file)
@@ -29,6 +29,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, N
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
 static BUS_DEFINE_PROPERTY_GET(property_get_timeout_abort_usec, "t", Service, service_timeout_abort_usec);
 static BUS_DEFINE_PROPERTY_GET(property_get_watchdog_usec, "t", Service, service_get_watchdog_usec);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode);
 
 static int property_get_exit_status_set(
                 sd_bus *bus,
@@ -101,6 +102,8 @@ const sd_bus_vtable bus_service_vtable[] = {
         SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TimeoutAbortUSec", "t", property_get_timeout_abort_usec, 0, 0),
+        SD_BUS_PROPERTY("TimeoutStartFailureMode", "s", property_get_timeout_failure_mode, offsetof(Service, timeout_start_failure_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("TimeoutStopFailureMode", "s", property_get_timeout_failure_mode, offsetof(Service, timeout_stop_failure_mode), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("WatchdogUSec", "t", property_get_watchdog_usec, 0, 0),
         BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
@@ -259,6 +262,7 @@ static BUS_DEFINE_SET_TRANSIENT_PARSE(service_type, ServiceType, service_type_fr
 static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart, ServiceRestart, service_restart_from_string);
 static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
 static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(bus_name, sd_bus_service_name_is_valid);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(timeout_failure_mode, ServiceTimeoutFailureMode, service_timeout_failure_mode_from_string);
 
 static int bus_service_set_transient_property(
                 Service *s,
@@ -316,6 +320,12 @@ static int bus_service_set_transient_property(
                 return r;
         }
 
+        if (streq(name, "TimeoutStartFailureMode"))
+                return bus_set_transient_timeout_failure_mode(u, name, &s->timeout_start_failure_mode, message, flags, error);
+
+        if (streq(name, "TimeoutStopFailureMode"))
+                return bus_set_transient_timeout_failure_mode(u, name, &s->timeout_stop_failure_mode, message, flags, error);
+
         if (streq(name, "RuntimeMaxUSec"))
                 return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error);
 
index c76d08b3a6dd1ed253b1c02085029f220792bfa6..69598e8430c1a00906ea003458eb61d7988527dc 100644 (file)
@@ -322,6 +322,8 @@ Service.TimeoutSec,              config_parse_service_timeout,       0,
 Service.TimeoutStartSec,         config_parse_service_timeout,       0,                             0
 Service.TimeoutStopSec,          config_parse_sec_fix_0,             0,                             offsetof(Service, timeout_stop_usec)
 Service.TimeoutAbortSec,         config_parse_service_timeout_abort, 0,                             0
+Service.TimeoutStartFailureMode, config_parse_service_timeout_failure_mode,  0,                     offsetof(Service, timeout_start_failure_mode)
+Service.TimeoutStopFailureMode,  config_parse_service_timeout_failure_mode,  0,                     offsetof(Service, timeout_stop_failure_mode)
 Service.RuntimeMaxSec,           config_parse_sec,                   0,                             offsetof(Service, runtime_max_usec)
 Service.WatchdogSec,             config_parse_sec,                   0,                             offsetof(Service, watchdog_usec)
 m4_dnl The following five only exist for compatibility, they moved into Unit, see above
index 517813986b9210c30a86312650c6615571e18605..a2eede4ccea597bf9c149e95823e70206e10e39f 100644 (file)
@@ -123,6 +123,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_system, protect_system, ProtectSys
 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_service_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode, "Failed to parse timeout failure mode");
 DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
 DEFINE_CONFIG_PARSE_ENUM(config_parse_oom_policy, oom_policy, OOMPolicy, "Failed to parse OOM policy");
 DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value");
@@ -4941,6 +4942,7 @@ void unit_dump_config_items(FILE *f) {
                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
                 { config_parse_service_type,          "SERVICETYPE" },
                 { config_parse_service_restart,       "SERVICERESTART" },
+                { config_parse_service_timeout_failure_mode, "TIMEOUTMODE" },
                 { config_parse_kill_mode,             "KILLMODE" },
                 { config_parse_signal,                "SIGNAL" },
                 { config_parse_socket_listen,         "SOCKET [...]" },
index bc72ef77451fe65864170ecace32ac805d599723..9c30b6f882b30fb85672c93160d8a9a04b61baf7 100644 (file)
@@ -30,6 +30,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_coredump_filter);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec);
 CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout);
 CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_abort);
+CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_failure_mode);
 CONFIG_PARSER_PROTOTYPE(config_parse_service_type);
 CONFIG_PARSER_PROTOTYPE(config_parse_service_restart);
 CONFIG_PARSER_PROTOTYPE(config_parse_socket_bindtodevice);
index 340b655059196d139db1e57470064689198de23f..8b3fd2e5a44273c3a9d1344c3fdf0544c789c41a 100644 (file)
@@ -56,6 +56,7 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
         [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
+        [SERVICE_FINAL_WATCHDOG] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_FAILED] = UNIT_FAILED,
@@ -79,6 +80,7 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
         [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
+        [SERVICE_FINAL_WATCHDOG] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_FAILED] = UNIT_FAILED,
@@ -857,10 +859,14 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
         fprintf(f,
                 "%sRestartSec: %s\n"
                 "%sTimeoutStartSec: %s\n"
-                "%sTimeoutStopSec: %s\n",
+                "%sTimeoutStopSec: %s\n"
+                "%sTimeoutStartFailureMode: %s\n"
+                "%sTimeoutStopFailureMode: %s\n",
                 prefix, format_timespan(buf_restart, sizeof(buf_restart), s->restart_usec, USEC_PER_SEC),
                 prefix, format_timespan(buf_start, sizeof(buf_start), s->timeout_start_usec, USEC_PER_SEC),
-                prefix, format_timespan(buf_stop, sizeof(buf_stop), s->timeout_stop_usec, USEC_PER_SEC));
+                prefix, format_timespan(buf_stop, sizeof(buf_stop), s->timeout_stop_usec, USEC_PER_SEC),
+                prefix, service_timeout_failure_mode_to_string(s->timeout_start_failure_mode),
+                prefix, service_timeout_failure_mode_to_string(s->timeout_stop_failure_mode));
 
         if (s->timeout_abort_set)
                 fprintf(f,
@@ -1072,7 +1078,7 @@ static void service_set_state(Service *s, ServiceState state) {
                     SERVICE_RUNNING,
                     SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
                     SERVICE_AUTO_RESTART,
                     SERVICE_CLEANING))
                 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
@@ -1081,7 +1087,7 @@ static void service_set_state(Service *s, ServiceState state) {
                     SERVICE_START, SERVICE_START_POST,
                     SERVICE_RUNNING, SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
+                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
                 service_unwatch_main_pid(s);
                 s->main_command = NULL;
         }
@@ -1090,7 +1096,7 @@ static void service_set_state(Service *s, ServiceState state) {
                     SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
                     SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
                     SERVICE_CLEANING)) {
                 service_unwatch_control_pid(s);
                 s->control_command = NULL;
@@ -1106,7 +1112,7 @@ static void service_set_state(Service *s, ServiceState state) {
                     SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
                     SERVICE_RUNNING, SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
+                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
             !(state == SERVICE_DEAD && UNIT(s)->job))
                 service_close_socket_fd(s);
 
@@ -1154,6 +1160,7 @@ static usec_t service_coldplug_timeout(Service *s) {
                 return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_stop_usec);
 
         case SERVICE_STOP_WATCHDOG:
+        case SERVICE_FINAL_WATCHDOG:
                 return usec_add(UNIT(s)->state_change_timestamp.monotonic, service_timeout_abort_usec(s));
 
         case SERVICE_AUTO_RESTART:
@@ -1187,7 +1194,7 @@ static int service_coldplug(Unit *u) {
                     SERVICE_START, SERVICE_START_POST,
                     SERVICE_RUNNING, SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
+                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
                 r = unit_watch_pid(UNIT(s), s->main_pid, false);
                 if (r < 0)
                         return r;
@@ -1199,7 +1206,7 @@ static int service_coldplug(Unit *u) {
                    SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
                    SERVICE_RELOAD,
                    SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                   SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+                   SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
                    SERVICE_CLEANING)) {
                 r = unit_watch_pid(UNIT(s), s->control_pid, false);
                 if (r < 0)
@@ -1859,6 +1866,7 @@ static int state_to_kill_operation(Service *s, ServiceState state) {
         switch (state) {
 
         case SERVICE_STOP_WATCHDOG:
+        case SERVICE_FINAL_WATCHDOG:
                 return KILL_WATCHDOG;
 
         case SERVICE_STOP_SIGTERM:
@@ -1879,7 +1887,7 @@ static int state_to_kill_operation(Service *s, ServiceState state) {
 }
 
 static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) {
-        int r;
+        int kill_operation, r;
 
         assert(s);
 
@@ -1893,10 +1901,11 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
          * died now */
         (void) unit_enqueue_rewatch_pids(UNIT(s));
 
+        kill_operation = state_to_kill_operation(s, state);
         r = unit_kill_context(
                         UNIT(s),
                         &s->kill_context,
-                        state_to_kill_operation(s, state),
+                        kill_operation,
                         s->main_pid,
                         s->control_pid,
                         s->main_pid_alien);
@@ -1905,7 +1914,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
 
         if (r > 0) {
                 r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC),
-                                      state == SERVICE_STOP_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec));
+                                      kill_operation == KILL_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec));
                 if (r < 0)
                         goto fail;
 
@@ -1914,7 +1923,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
                 service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_SUCCESS);
         else if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
                 service_enter_stop_post(s, SERVICE_SUCCESS);
-        else if (state == SERVICE_FINAL_SIGTERM && s->kill_context.send_sigkill)
+        else if (IN_SET(state, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM) && s->kill_context.send_sigkill)
                 service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
         else
                 service_enter_dead(s, SERVICE_SUCCESS, true);
@@ -2444,7 +2453,7 @@ static int service_start(Unit *u) {
          * please! */
         if (IN_SET(s->state,
                    SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                   SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_CLEANING))
+                   SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_CLEANING))
                 return -EAGAIN;
 
         /* Already on it! */
@@ -2515,7 +2524,7 @@ static int service_stop(Unit *u) {
         /* Already on it */
         if (IN_SET(s->state,
                    SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                   SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
+                   SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
                 return 0;
 
         /* A restart will be scheduled or is in progress. */
@@ -3321,6 +3330,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
                 break;
 
         case SERVICE_STOP_POST:
+        case SERVICE_FINAL_WATCHDOG:
         case SERVICE_FINAL_SIGTERM:
         case SERVICE_FINAL_SIGKILL:
                 if (main_pid_good(s) <= 0 && control_pid_good(s) <= 0)
@@ -3521,6 +3531,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
                                 break;
 
+                        case SERVICE_FINAL_WATCHDOG:
                         case SERVICE_FINAL_SIGTERM:
                         case SERVICE_FINAL_SIGKILL:
 
@@ -3674,6 +3685,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                         service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
                                 break;
 
+                        case SERVICE_FINAL_WATCHDOG:
                         case SERVICE_FINAL_SIGTERM:
                         case SERVICE_FINAL_SIGKILL:
                                 if (main_pid_good(s) <= 0)
@@ -3720,13 +3732,32 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
         case SERVICE_CONDITION:
         case SERVICE_START_PRE:
         case SERVICE_START:
-                log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", service_state_to_string(s->state));
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
-                break;
-
         case SERVICE_START_POST:
-                log_unit_warning(UNIT(s), "Start-post operation timed out. Stopping.");
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                switch (s->timeout_start_failure_mode) {
+
+                case SERVICE_TIMEOUT_TERMINATE:
+                        log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", service_state_to_string(s->state));
+                        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_ABORT:
+                        log_unit_warning(UNIT(s), "%s operation timed out. Aborting.", service_state_to_string(s->state));
+                        service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_KILL:
+                        if (s->kill_context.send_sigkill) {
+                                log_unit_warning(UNIT(s), "%s operation timed out. Killing.", service_state_to_string(s->state));
+                                service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                        } else {
+                                log_unit_warning(UNIT(s), "%s operation timed out. Skipping SIGKILL.", service_state_to_string(s->state));
+                                service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+                        }
+                        break;
+
+                default:
+                        assert_not_reached("unknown timeout mode");
+                }
                 break;
 
         case SERVICE_RUNNING:
@@ -3742,17 +3773,48 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
                 break;
 
         case SERVICE_STOP:
-                log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                switch (s->timeout_stop_failure_mode) {
+
+                case SERVICE_TIMEOUT_TERMINATE:
+                        log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
+                        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_ABORT:
+                        log_unit_warning(UNIT(s), "Stopping timed out. Aborting.");
+                        service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_KILL:
+                        if (s->kill_context.send_sigkill) {
+                                log_unit_warning(UNIT(s), "Stopping timed out. Killing.");
+                                service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                        } else {
+                                log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL.");
+                                service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+                        }
+                        break;
+
+                default:
+                        assert_not_reached("unknown timeout mode");
+                }
                 break;
 
         case SERVICE_STOP_WATCHDOG:
-                log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Terminating.");
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                if (s->kill_context.send_sigkill) {
+                        log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Killing.");
+                        service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                } else {
+                        log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Skipping SIGKILL.");
+                        service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+                }
                 break;
 
         case SERVICE_STOP_SIGTERM:
-                if (s->kill_context.send_sigkill) {
+                if (s->timeout_stop_failure_mode == SERVICE_TIMEOUT_ABORT) {
+                        log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Aborting.");
+                        service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+                } else if (s->kill_context.send_sigkill) {
                         log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Killing.");
                         service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
                 } else {
@@ -3772,16 +3834,52 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
                 break;
 
         case SERVICE_STOP_POST:
-                log_unit_warning(UNIT(s), "State 'stop-post' timed out. Terminating.");
-                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                switch (s->timeout_stop_failure_mode) {
+
+                case SERVICE_TIMEOUT_TERMINATE:
+                        log_unit_warning(UNIT(s), "State 'stop-post' timed out. Terminating.");
+                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_ABORT:
+                        log_unit_warning(UNIT(s), "State 'stop-post' timed out. Aborting.");
+                        service_enter_signal(s, SERVICE_FINAL_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_KILL:
+                        if (s->kill_context.send_sigkill) {
+                                log_unit_warning(UNIT(s), "State 'stop-post' timed out. Killing.");
+                                service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                        } else {
+                                log_unit_warning(UNIT(s), "State 'stop-post' timed out. Skipping SIGKILL. Entering failed mode.");
+                                service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
+                        }
+                        break;
+
+                default:
+                        assert_not_reached("unknown timeout mode");
+                }
                 break;
 
-        case SERVICE_FINAL_SIGTERM:
+        case SERVICE_FINAL_WATCHDOG:
                 if (s->kill_context.send_sigkill) {
-                        log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Killing.");
+                        log_unit_warning(UNIT(s), "State 'final-watchdog' timed out. Killing.");
                         service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
                 } else {
-                        log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Skipping SIGKILL. Entering failed mode.");
+                        log_unit_warning(UNIT(s), "State 'final-watchdog' timed out. Skipping SIGKILL. Entering failed mode.");
+                        service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
+                }
+                break;
+
+        case SERVICE_FINAL_SIGTERM:
+                if (s->timeout_stop_failure_mode == SERVICE_TIMEOUT_ABORT) {
+                        log_unit_warning(UNIT(s), "State 'final-sigterm' timed out. Aborting.");
+                        service_enter_signal(s, SERVICE_FINAL_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+                } else if (s->kill_context.send_sigkill) {
+                        log_unit_warning(UNIT(s), "State 'final-sigterm' timed out. Killing.");
+                        service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                } else {
+                        log_unit_warning(UNIT(s), "State 'final-sigterm' timed out. Skipping SIGKILL. Entering failed mode.");
                         service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
                 }
 
@@ -4263,6 +4361,7 @@ static bool service_needs_console(Unit *u) {
                       SERVICE_STOP_SIGTERM,
                       SERVICE_STOP_SIGKILL,
                       SERVICE_STOP_POST,
+                      SERVICE_FINAL_WATCHDOG,
                       SERVICE_FINAL_SIGTERM,
                       SERVICE_FINAL_SIGKILL);
 }
@@ -4417,6 +4516,14 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
 
+static const char* const service_timeout_failure_mode_table[_SERVICE_TIMEOUT_FAILURE_MODE_MAX] = {
+        [SERVICE_TIMEOUT_TERMINATE] = "terminate",
+        [SERVICE_TIMEOUT_ABORT] = "abort",
+        [SERVICE_TIMEOUT_KILL] = "kill",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_timeout_failure_mode, ServiceTimeoutFailureMode);
+
 const UnitVTable service_vtable = {
         .object_size = sizeof(Service),
         .exec_context_offset = offsetof(Service, exec_context),
index 3a84db14c47a337526753a6d6250200e8847cefc..4423f893bb743394379b25fc0d0047372cb660d3 100644 (file)
@@ -74,6 +74,14 @@ typedef enum ServiceResult {
         _SERVICE_RESULT_INVALID = -1
 } ServiceResult;
 
+typedef enum ServiceTimeoutFailureMode {
+        SERVICE_TIMEOUT_TERMINATE,
+        SERVICE_TIMEOUT_ABORT,
+        SERVICE_TIMEOUT_KILL,
+        _SERVICE_TIMEOUT_FAILURE_MODE_MAX,
+        _SERVICE_TIMEOUT_FAILURE_MODE_INVALID = -1
+} ServiceTimeoutFailureMode;
+
 struct ServiceFDStore {
         Service *service;
 
@@ -103,6 +111,8 @@ struct Service {
         usec_t timeout_abort_usec;
         bool timeout_abort_set;
         usec_t runtime_max_usec;
+        ServiceTimeoutFailureMode timeout_start_failure_mode;
+        ServiceTimeoutFailureMode timeout_stop_failure_mode;
 
         dual_timestamp watchdog_timestamp;
         usec_t watchdog_usec;            /* the requested watchdog timeout in the unit file */
@@ -228,6 +238,9 @@ NotifyState notify_state_from_string(const char *s) _pure_;
 const char* service_result_to_string(ServiceResult i) _const_;
 ServiceResult service_result_from_string(const char *s) _pure_;
 
+const char* service_timeout_failure_mode_to_string(ServiceTimeoutFailureMode i) _const_;
+ServiceTimeoutFailureMode service_timeout_failure_mode_from_string(const char *s) _pure_;
+
 DEFINE_CAST(SERVICE, Service);
 
 #define STATUS_TEXT_MAX (16U*1024U)
index 38a2805200b3eb42c74be172215f07fb5c13667d..f4f63fcb5b1a23e33c9c879202fc05830cd3a75f 100644 (file)
@@ -403,7 +403,7 @@ static int slice_freezer_action(Unit *s, FreezerAction action) {
         if (r < 0)
                 return r;
 
-        return 0;
+        return 1;
 }
 
 static int slice_freeze(Unit *s) {
index 5886f86db63f56d9c93aefe5dc09ac92137ff2e3..c05e2d1351aefeaf3abcde8a35cfb707a49bb2fb 100644 (file)
@@ -38,7 +38,7 @@
 #define CRYPT_SECTOR_SIZE 512
 #define CRYPT_MAX_SECTOR_SIZE 4096
 
-static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT or CRYPT_PLAIN */
+static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT, CRYPT_BITLK or CRYPT_PLAIN */
 static char *arg_cipher = NULL;
 static unsigned arg_key_size = 0;
 static unsigned arg_sector_size = CRYPT_SECTOR_SIZE;
@@ -220,6 +220,11 @@ static int parse_one_option(const char *option) {
                 arg_submit_from_crypt_cpus = true;
         else if (streq(option, "luks"))
                 arg_type = ANY_LUKS;
+/* since cryptsetup 2.3.0 (Feb 2020) */
+#ifdef CRYPT_BITLK
+        else if (streq(option, "bitlk"))
+                arg_type = CRYPT_BITLK;
+#endif
         else if (streq(option, "tcrypt"))
                 arg_type = CRYPT_TCRYPT;
         else if (STR_IN_SET(option, "tcrypt-hidden", "tcrypthidden")) {
@@ -545,7 +550,7 @@ static int attach_tcrypt(
         return 0;
 }
 
-static int attach_luks_or_plain(
+static int attach_luks_or_plain_or_bitlk(
                 struct crypt_device *cd,
                 const char *name,
                 const char *key_file,
@@ -950,6 +955,15 @@ static int run(int argc, char *argv[]) {
                         }
                 }
 
+/* since cryptsetup 2.3.0 (Feb 2020) */
+#ifdef CRYPT_BITLK
+                if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_BITLK)) {
+                        r = crypt_load(cd, CRYPT_BITLK, NULL);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to load Bitlocker superblock on device %s: %m", crypt_get_device_name(cd));
+                }
+#endif
+
                 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
                         _cleanup_strv_free_erase_ char **passwords = NULL;
 
@@ -988,7 +1002,7 @@ static int run(int argc, char *argv[]) {
                         if (streq_ptr(arg_type, CRYPT_TCRYPT))
                                 r = attach_tcrypt(cd, argv[2], key_file, key_data, key_data_size, passwords, flags);
                         else
-                                r = attach_luks_or_plain(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until);
+                                r = attach_luks_or_plain_or_bitlk(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until);
                         if (r >= 0)
                                 break;
                         if (r != -EAGAIN)
old mode 100644 (file)
new mode 100755 (executable)
index 4812464..e2590c4
@@ -23,8 +23,11 @@ SKIP_REMAINING=77
 usage()
 {
     echo "Usage:"
-    echo "        $0 add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]"
-    echo "        $0 remove KERNEL-VERSION"
+    echo "  $0 [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]"
+    echo "  $0 [OPTIONS...] remove KERNEL-VERSION"
+    echo "Options:"
+    echo "  -h,--help     Print this help"
+    echo "  -v,--verbose  Increase verbosity"
 }
 
 dropindirs_sort()
index 7e03817f82f44212adb60a05b2a6682d0ec9aa68..5195a5850fcc98e2e0f8fbda35f4be2dc57b9207 100644 (file)
@@ -168,6 +168,10 @@ _public_ int sd_network_link_get_address_state(int ifindex, char **state) {
         return network_link_get_string(ifindex, "ADDRESS_STATE", state);
 }
 
+_public_ int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id) {
+        return network_link_get_string(ifindex, "DHCP4_CLIENT_ID", client_id);
+}
+
 _public_ int sd_network_link_get_required_for_online(int ifindex) {
         _cleanup_free_ char *s = NULL;
         int r;
index 2bbd18363e69a817dd0c769c489b53fbacbb1f08..60dd6add60da1cb0bbb863d430d9333db7ca5f3a 100644 (file)
@@ -30,6 +30,11 @@ SUBSYSTEM=="pci", ENV{ID_PCI_CLASS_FROM_DATABASE}=="Display controller", \
                   ENV{DRIVER}=="", IMPORT{cmdline}="nomodeset", TAG+="seat", TAG+="master-of-seat"
 
 SUBSYSTEM=="drm", KERNEL=="card[0-9]*", TAG+="seat", TAG+="master-of-seat"
+
+# Allow individual USB ports to be assigned to a seat
+SUBSYSTEM=="usb", ATTR{bDeviceClass}=="00", TAG+="seat"
+
+# Allow USB hubs (and all downstream ports) to be assigned to a seat
 SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat"
 
 # 'Plugable' USB hub, sound, network, graphics adapter
index 469c14271c2201920a5371e6d3daba62558e6724..ea86a6e06a9e5100b8e57a6ed7b1b277b312da65 100644 (file)
@@ -364,7 +364,7 @@ static int parse_argv(int argc, char *argv[]) {
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                "At most two arguments required.");
 
-                if (arg_mount_type && (fstype_is_api_vfs(arg_mount_type) || fstype_is_network(arg_mount_type))) {
+                if (arg_mount_type && !fstype_is_blockdev_backed(arg_mount_type)) {
                         arg_mount_what = strdup(argv[optind]);
                         if (!arg_mount_what)
                                 return log_oom();
@@ -1463,7 +1463,7 @@ static int run(int argc, char* argv[]) {
         if (arg_action == ACTION_UMOUNT)
                 return action_umount(bus, argc, argv);
 
-        if ((!arg_mount_type || !fstype_is_network(arg_mount_type))
+        if ((!arg_mount_type || fstype_is_blockdev_backed(arg_mount_type))
             && !path_is_normalized(arg_mount_what)) {
                 log_error("Path contains non-normalized components: %s", arg_mount_what);
                 return -EINVAL;
index 59c2ed278b4ab9ea05c33a9723c51d9ab433a3d5..dea190eb0d10372e1c0726e4b114df9e09aa9566 100644 (file)
@@ -1381,7 +1381,7 @@ static int link_status_one(
         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL,
                 **pop3_server = NULL, **smtp_server = NULL, **lpr_server = NULL;
         _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
-        _cleanup_free_ char *t = NULL, *network = NULL;
+        _cleanup_free_ char *t = NULL, *network = NULL, *client_id = NULL;
         const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
         const char *on_color_operational, *off_color_operational,
                 *on_color_setup, *off_color_setup;
@@ -2073,6 +2073,16 @@ static int link_status_one(
                         return table_log_add_error(r);
         }
 
+        r = sd_network_link_get_dhcp4_client_id_string(info->ifindex, &client_id);
+        if (r >= 0) {
+                r = table_add_many(table,
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "DHCP4 Client ID:",
+                                   TABLE_STRING, client_id);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
+
         r = dump_lldp_neighbors(table, "Connected To:", info->ifindex);
         if (r < 0)
                 return r;
index 805aff3ab1d5dd3181db9b27c8daa43c53eb7869..20c5c1c4c8f821ce1bd1f313e6d0ad9e736d1bce 100644 (file)
@@ -2532,6 +2532,22 @@ static int link_set_ipv6_mtu(Link *link) {
         return 0;
 }
 
+static int link_set_ipv4_accept_local(Link *link) {
+        int r;
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        if (link->network->ipv4_accept_local < 0)
+                return 0;
+
+        r = sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface: %m");
+
+        return 0;
+}
+
 static bool link_is_static_address_configured(Link *link, Address *address) {
         Address *net_address;
 
@@ -2871,6 +2887,10 @@ static int link_configure(Link *link) {
         if (r < 0)
                 return r;
 
+        r = link_set_ipv4_accept_local(link);
+        if (r < 0)
+                return r;
+
         r = link_set_flags(link);
         if (r < 0)
                 return r;
@@ -4354,6 +4374,8 @@ int link_save(Link *link) {
         if (link->dhcp_lease) {
                 struct in_addr address;
                 const char *tz = NULL;
+                size_t client_id_len;
+                const void *client_id;
 
                 assert(link->network);
 
@@ -4368,6 +4390,15 @@ int link_save(Link *link) {
                         fputc('\n', f);
                 }
 
+                r = sd_dhcp_lease_get_client_id(link->dhcp_lease, &client_id, &client_id_len);
+                if (r >= 0) {
+                        _cleanup_free_ char *id = NULL;
+
+                        r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id);
+                        if (r >= 0)
+                                fprintf(f, "DHCP4_CLIENT_ID=%s\n", id);
+                }
+
                 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
                 if (r < 0)
                         goto fail;
index 39188906648f68e03cc632e6074150b0b993ed3b..5c2a4d36a11bbe6e731816f4c1bb65af1ca07cc1 100644 (file)
@@ -96,6 +96,7 @@ Network.IPv6DuplicateAddressDetection,       config_parse_int,
 Network.IPv6HopLimit,                        config_parse_int,                                         0,                             offsetof(Network, ipv6_hop_limit)
 Network.IPv6ProxyNDP,                        config_parse_tristate,                                    0,                             offsetof(Network, ipv6_proxy_ndp)
 Network.IPv6MTUBytes,                        config_parse_mtu,                                         AF_INET6,                      offsetof(Network, ipv6_mtu)
+Network.IPv4AcceptLocal,                     config_parse_tristate,                                    0,                             offsetof(Network, ipv4_accept_local)
 Network.ActiveSlave,                         config_parse_bool,                                        0,                             offsetof(Network, active_slave)
 Network.PrimarySlave,                        config_parse_bool,                                        0,                             offsetof(Network, primary_slave)
 Network.IPv4ProxyARP,                        config_parse_tristate,                                    0,                             offsetof(Network, proxy_arp)
index 124c570b0e48ed12e83288009ad13e8020f853a0..bbecd706ce99c60e51dc3c411ad0e02f22aca391 100644 (file)
@@ -450,6 +450,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
                 .link_local = _ADDRESS_FAMILY_INVALID,
 
+                .ipv4_accept_local = -1,
+
                 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
                 .ipv6_accept_ra = -1,
                 .ipv6_dad_transmits = -1,
index 934a33ac94357ab840de3ad8cbae0e9473657e94..590162286221609f35bbefcc52fdff3a35daa952 100644 (file)
@@ -237,6 +237,7 @@ struct Network {
 
         AddressFamily ip_forward;
         bool ip_masquerade;
+        int ipv4_accept_local;
 
         int ipv6_accept_ra;
         int ipv6_dad_transmits;
index 9a5730f3eae6145092d9a2d202d44b81ffc0dd16..69f79ea1761c8d832429b3c7b0237ad64de775f4 100644 (file)
@@ -1490,7 +1490,9 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
                               "NotifyAccess",
                               "USBFunctionDescriptors",
                               "USBFunctionStrings",
-                              "OOMPolicy"))
+                              "OOMPolicy",
+                              "TimeoutStartFailureMode",
+                              "TimeoutStopFailureMode"))
                 return bus_append_string(m, field, eq);
 
         if (STR_IN_SET(field, "PermissionsStartOnly",
index 2637a0f8bb176318c4978e264ab536c0cd1d5d3b..876f010c95d9feec70b67fa5e7bf047b15e9197c 100644 (file)
@@ -188,6 +188,9 @@ int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes);
 /* Get the timezone that was learnt on a specific link. */
 int sd_network_link_get_timezone(int ifindex, char **timezone);
 
+/* Get DHCPv4 client id for a given link. */
+int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id);
+
 /* Monitor object */
 typedef struct sd_network_monitor sd_network_monitor;
 
index a2b8c6162c16d17a9d12bab98cc89010e0c60659..6e0ce725534cac2859f03d0e346cf951f0cd78d5 100644 (file)
@@ -76,6 +76,7 @@ static unsigned arg_children_max = 0;
 static usec_t arg_exec_delay_usec = 0;
 static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
 static int arg_timeout_signal = SIGKILL;
+static bool arg_blockdev_read_only = false;
 
 typedef struct Manager {
         sd_event *event;
@@ -383,6 +384,56 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) {
         return 1;
 }
 
+static int worker_mark_block_device_read_only(sd_device *dev) {
+        _cleanup_close_ int fd = -1;
+        const char *val;
+        int state = 1, r;
+
+        assert(dev);
+
+        if (!arg_blockdev_read_only)
+                return 0;
+
+        /* Do this only once, when the block device is new. If the device is later retriggered let's not
+         * toggle the bit again, so that people can boot up with full read-only mode and then unset the bit
+         * for specific devices only. */
+        if (!device_for_action(dev, DEVICE_ACTION_ADD))
+                return 0;
+
+        r = sd_device_get_subsystem(dev, &val);
+        if (r < 0)
+                return log_device_debug_errno(dev, r, "Failed to get subsystem: %m");
+
+        if (!streq(val, "block"))
+                return 0;
+
+        r = sd_device_get_sysname(dev, &val);
+        if (r < 0)
+                return log_device_debug_errno(dev, r, "Failed to get sysname: %m");
+
+        /* Exclude synthetic devices for now, this is supposed to be a safety feature to avoid modification
+         * of physical devices, and what sits on top of those doesn't really matter if we don't allow the
+         * underlying block devices to recieve changes. */
+        if (STARTSWITH_SET(val, "dm-", "md", "drbd", "loop", "nbd", "zram"))
+                return 0;
+
+        r = sd_device_get_devname(dev, &val);
+        if (r == -ENOENT)
+                return 0;
+        if (r < 0)
+                return log_device_debug_errno(dev, r, "Failed to get devname: %m");
+
+        fd = open(val, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
+        if (fd < 0)
+                return log_device_debug_errno(dev, errno, "Failed to open '%s', ignoring: %m", val);
+
+        if (ioctl(fd, BLKROSET, &state) < 0)
+                return log_device_warning_errno(dev, errno, "Failed to mark block device '%s' read-only: %m", val);
+
+        log_device_info(dev, "Successfully marked block device '%s' read-only.", val);
+        return 0;
+}
+
 static int worker_process_device(Manager *manager, sd_device *dev) {
         _cleanup_(udev_event_freep) UdevEvent *udev_event = NULL;
         _cleanup_close_ int fd_lock = -1;
@@ -412,6 +463,8 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
         if (r < 0)
                 return r;
 
+        (void) worker_mark_block_device_read_only(dev);
+
         /* apply rules, create node, symlinks */
         r = udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_timeout_signal, manager->properties, manager->rules);
         if (r < 0)
@@ -1417,15 +1470,13 @@ static int listen_fds(int *ret_ctrl, int *ret_netlink) {
  *   udev.children_max=<number of workers>     events are fully serialized if set to 1
  *   udev.exec_delay=<number of seconds>       delay execution of every executed program
  *   udev.event_timeout=<number of seconds>    seconds to wait before terminating an event
+ *   udev.blockdev_read_only<=bool>            mark all block devices read-only when they appear
  */
 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
-        int r = 0;
+        int r;
 
         assert(key);
 
-        if (!value)
-                return 0;
-
         if (proc_cmdline_key_streq(key, "udev.log_priority")) {
 
                 if (proc_cmdline_value_missing(key, value))
@@ -1457,14 +1508,37 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 r = parse_sec(value, &arg_exec_delay_usec);
 
         } else if (proc_cmdline_key_streq(key, "udev.timeout_signal")) {
+
                 if (proc_cmdline_value_missing(key, value))
                         return 0;
 
                 r = signal_from_string(value);
                 if (r > 0)
                         arg_timeout_signal = r;
-        } else if (startswith(key, "udev."))
-                log_warning("Unknown udev kernel command line option \"%s\", ignoring", key);
+
+        } else if (proc_cmdline_key_streq(key, "udev.blockdev_read_only")) {
+
+                if (!value)
+                        arg_blockdev_read_only = true;
+                else {
+                        r = parse_boolean(value);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to parse udev.blockdev-read-only argument, ignoring: %s", value);
+                        else
+                                arg_blockdev_read_only = r;
+                }
+
+                if (arg_blockdev_read_only)
+                        log_notice("All physical block devices will be marked read-only.");
+
+                return 0;
+
+        } else {
+                if (startswith(key, "udev."))
+                        log_warning("Unknown udev kernel command line option \"%s\", ignoring.", key);
+
+                return 0;
+        }
 
         if (r < 0)
                 log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);
index 7cade0e9edc297132c4ff42de6da06f76d338d6a..478b574418efbc1206c8651e28f5229c7cf78afc 100644 (file)
@@ -153,6 +153,7 @@ Address=
 IPv6ProxyNDPAddress=
 IPv6AcceptRA=
 IPv6AcceptRouterAdvertisements=
+IPv4AcceptLocal=
 DNSSECNegativeTrustAnchors=
 MACVTAP=
 IPv6PrivacyExtensions=
index 68be305477049341edeccf108d66320396ffca8b..dc1d6542c0e2c5b099b42c279b20cd8bfce862a4 100644 (file)
@@ -9,3 +9,4 @@ IPv6HopLimit=5
 IPv4ProxyARP=true
 IPv6ProxyNDP=true
 IPv6AcceptRA=no
+IPv4AcceptLocal=yes
index 43730d9f853252b7f101b7fa583b506a26687ea0..66dc46a6b4cea5ca1b8dac50b35bd922903b2ecc 100755 (executable)
@@ -2203,6 +2203,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
         self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
         self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
+        self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
 
     def test_sysctl_disable_ipv6(self):
         copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
@@ -2796,7 +2797,8 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
             with self.subTest(test=test):
                 if test == 'no-slave':
                     # bridge has no slaves; it's up but *might* not have carrier
-                    self.wait_online(['bridge99:no-carrier'])
+                    # It may take very long time that the interface become configured state.
+                    self.wait_online(['bridge99:no-carrier'], timeout='2m')
                     # due to a bug in the kernel, newly-created bridges are brought up
                     # *with* carrier, unless they have had any setting changed; e.g.
                     # their mac set, priority set, etc.  Then, they will lose carrier
index 6fcadb8f8e1d3ccb932fc709c426b556bc322098..18b7bd6dcee27b0b8f3c8564f20c1747cf927461 100755 (executable)
@@ -246,6 +246,8 @@ test_preserve_state() {
 
     echo -n "  - freeze from outside: "
     echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+    # Give kernel some time to freeze the slice
+    sleep 1
 
     # Our state should not be affected
     check_freezer_state "${slice}" "running"
@@ -258,6 +260,8 @@ test_preserve_state() {
 
     echo -n "  - thaw from outside: "
     echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+    sleep 1
+
     check_freezer_state "${unit}" "running"
     check_freezer_state "${slice}" "running"
     grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events
index 4e8593f320099b96c568baee3eff57ad762f0e77..66018a54fd4b6fe9d4ae35bd012023948e4bd8e0 100644 (file)
@@ -1,79 +1,77 @@
 #!/usr/bin/env python3
 # SPDX-License-Identifier: LGPL-2.1+
 
-from __future__ import print_function
-
 import gdb
 
 class sd_dump_hashmaps(gdb.Command):
-        "dump systemd's hashmaps"
-
-        def __init__(self):
-                super(sd_dump_hashmaps, self).__init__("sd_dump_hashmaps", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
-
-        def invoke(self, arg, from_tty):
-                d = gdb.parse_and_eval("hashmap_debug_list")
-                all_entry_sizes = gdb.parse_and_eval("all_entry_sizes")
-                all_direct_buckets = gdb.parse_and_eval("all_direct_buckets")
-                uchar_t = gdb.lookup_type("unsigned char")
-                ulong_t = gdb.lookup_type("unsigned long")
-                debug_offset = gdb.parse_and_eval("(unsigned long)&((HashmapBase*)0)->debug")
-
-                print("type, hash, indirect, entries, max_entries, buckets, creator")
-                while d:
-                        h = gdb.parse_and_eval("(HashmapBase*)((char*)%d - %d)" % (int(d.cast(ulong_t)), debug_offset))
-
-                        if h["has_indirect"]:
-                                storage_ptr = h["indirect"]["storage"].cast(uchar_t.pointer())
-                                n_entries = h["indirect"]["n_entries"]
-                                n_buckets = h["indirect"]["n_buckets"]
-                        else:
-                                storage_ptr = h["direct"]["storage"].cast(uchar_t.pointer())
-                                n_entries = h["n_direct_entries"]
-                                n_buckets = all_direct_buckets[int(h["type"])];
-
-                        t = ["plain", "ordered", "set"][int(h["type"])]
-
-                        print("{}, {}, {}, {}, {}, {}, {} ({}:{})".format(t, h["hash_ops"], bool(h["has_indirect"]), n_entries, d["max_entries"], n_buckets, d["func"], d["file"], d["line"]))
-
-                        if arg != "" and n_entries > 0:
-                                dib_raw_addr = storage_ptr + (all_entry_sizes[h["type"]] * n_buckets)
-
-                                histogram = {}
-                                for i in xrange(0, n_buckets):
-                                        dib = int(dib_raw_addr[i])
-                                        histogram[dib] = histogram.get(dib, 0) + 1
-
-                                for dib in sorted(iter(histogram)):
-                                        if dib != 255:
-                                                print("{:>3} {:>8} {} of entries".format(dib, histogram[dib], 100.0*histogram[dib]/n_entries))
-                                        else:
-                                                print("{:>3} {:>8} {} of slots".format(dib, histogram[dib], 100.0*histogram[dib]/n_buckets))
-                                print("mean DIB of entries: {}".format(sum([dib*histogram[dib] for dib in iter(histogram) if dib != 255])*1.0/n_entries))
-
-                                blocks = []
-                                current_len = 1
-                                prev = int(dib_raw_addr[0])
-                                for i in xrange(1, n_buckets):
-                                        dib = int(dib_raw_addr[i])
-                                        if (dib == 255) != (prev == 255):
-                                                if prev != 255:
-                                                        blocks += [[i, current_len]]
-                                                current_len = 1
-                                        else:
-                                                current_len += 1
-
-                                        prev = dib
-                                if prev != 255:
-                                        blocks += [[i, current_len]]
-                                # a block may be wrapped around
-                                if len(blocks) > 1 and blocks[0][0] == blocks[0][1] and blocks[-1][0] == n_buckets - 1:
-                                        blocks[0][1] += blocks[-1][1]
-                                        blocks = blocks[0:-1]
-                                print("max block: {}".format(max(blocks, key=lambda a: a[1])))
-                                print("sum block lens: {}".format(sum(b[1] for b in blocks)))
-                                print("mean block len: {}".format((1.0 * sum(b[1] for b in blocks) / len(blocks))))
-
-                        d = d["debug_list_next"]
+    "dump systemd's hashmaps"
+
+    def __init__(self):
+        super().__init__("sd_dump_hashmaps", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
+
+    def invoke(self, arg, from_tty):
+        d = gdb.parse_and_eval("hashmap_debug_list")
+        hashmap_type_info = gdb.parse_and_eval("hashmap_type_info")
+        uchar_t = gdb.lookup_type("unsigned char")
+        ulong_t = gdb.lookup_type("unsigned long")
+        debug_offset = gdb.parse_and_eval("(unsigned long)&((HashmapBase*)0)->debug")
+
+        print("type, hash, indirect, entries, max_entries, buckets, creator")
+        while d:
+            h = gdb.parse_and_eval(f"(HashmapBase*)((char*){int(d.cast(ulong_t))} - {debug_offset})")
+
+            if h["has_indirect"]:
+                storage_ptr = h["indirect"]["storage"].cast(uchar_t.pointer())
+                n_entries = h["indirect"]["n_entries"]
+                n_buckets = h["indirect"]["n_buckets"]
+            else:
+                storage_ptr = h["direct"]["storage"].cast(uchar_t.pointer())
+                n_entries = h["n_direct_entries"]
+                n_buckets = hashmap_type_info[h["type"]]["n_direct_buckets"]
+
+            t = ["plain", "ordered", "set"][int(h["type"])]
+
+            print(f'{t}, {h["hash_ops"]}, {bool(h["has_indirect"])}, {n_entries}, {d["max_entries"]}, {n_buckets}, {d["func"].string()}, {d["file"].string()}:{d["line"]}')
+
+            if arg != "" and n_entries > 0:
+                dib_raw_addr = storage_ptr + hashmap_type_info[h["type"]]["entry_size"] * n_buckets
+
+                histogram = {}
+                for i in range(0, n_buckets):
+                    dib = int(dib_raw_addr[i])
+                    histogram[dib] = histogram.get(dib, 0) + 1
+
+                for dib in sorted(histogram):
+                    if dib != 255:
+                        print(f"{dib:>3} {histogram[dib]:>8} {float(histogram[dib]/n_entries):.0%} of entries")
+                    else:
+                        print(f"{dib:>3} {histogram[dib]:>8} {float(histogram[dib]/n_buckets):.0%} of slots")
+                        s = sum(dib*count for (dib, count) in histogram.items() if dib != 255) / n_entries
+                        print(f"mean DIB of entries: {s}")
+
+                blocks = []
+                current_len = 1
+                prev = int(dib_raw_addr[0])
+                for i in range(1, n_buckets):
+                    dib = int(dib_raw_addr[i])
+                    if (dib == 255) != (prev == 255):
+                        if prev != 255:
+                            blocks += [[i, current_len]]
+                            current_len = 1
+                    else:
+                        current_len += 1
+
+                    prev = dib
+                if prev != 255:
+                    blocks += [[i, current_len]]
+                    # a block may be wrapped around
+                if len(blocks) > 1 and blocks[0][0] == blocks[0][1] and blocks[-1][0] == n_buckets - 1:
+                    blocks[0][1] += blocks[-1][1]
+                    blocks = blocks[0:-1]
+                    print("max block: {}".format(max(blocks, key=lambda a: a[1])))
+                    print("sum block lens: {}".format(sum(b[1] for b in blocks)))
+                    print("mean block len: {}".format(sum(b[1] for b in blocks) / len(blocks)))
+
+            d = d["debug_list_next"]
 
 sd_dump_hashmaps()
index ad2f2a5b35b74d277ed0f1a2666705f7ba4f38b5..810cf5775e497e6d03df5909c5718c09669f5ea2 100644 (file)
@@ -8,7 +8,7 @@
 #  (at your option) any later version.
 
 [Unit]
-Description=Cleanup udevd DB
+Description=Cleanup udev Database
 DefaultDependencies=no
 ConditionPathExists=/etc/initrd-release
 Conflicts=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udev-trigger.service systemd-udev-settle.service
index ed6a68b864f2850b4134269f1a09cca9f2c412c1..9352c6f59890388669fbc7a84ea11048fce49025 100644 (file)
@@ -12,7 +12,7 @@
 # expect a populated /dev during bootup.
 
 [Unit]
-Description=udev Wait for Complete Device Initialization
+Description=Wait for udev To Complete Device Initialization
 Documentation=man:systemd-udev-settle.service(8)
 DefaultDependencies=no
 Wants=systemd-udevd.service
index 8a625b630599286874e658cb34409bb6bf2210ee..cfe8d61c2aff83162e5fb7a911f4d453cfe985a4 100644 (file)
@@ -8,7 +8,7 @@
 #  (at your option) any later version.
 
 [Unit]
-Description=udev Coldplug all Devices
+Description=Coldplug All udev Devices
 Documentation=man:udev(7) man:systemd-udevd.service(8)
 DefaultDependencies=no
 Wants=systemd-udevd.service