Compare commits

...

33 Commits

Author SHA1 Message Date
Lennart Poettering 57b611a5bf
Merge pull request #16074 from msekletar/freezer-test-flakes
Freezer test flakes
2020-06-09 14:38:40 +02:00
Yegor Vialov 8b8ae7959d
hwbd entry for Dell Inspiron Chromebook 14 2-in-1 sensor (#16109) 2020-06-09 13:31:58 +02:00
Adam Nielsen f01994380e login: allow individual USB ports to be assigned to seats
Assigning seats to specific USB ports lets the devices plugged into them
inherit the port's seat assignment.
2020-06-09 13:30:59 +02:00
Lennart Poettering ed66590d15
Merge pull request #16080 from YmrDtnJu/9p
9p is a network filesystem
2020-06-09 10:51:20 +02:00
Jan Klötzke bf76080180 core: let user define start-/stop-timeout behaviour
The usual behaviour when a timeout expires is to terminate/kill the
service. This is what user usually want in production systems. To debug
services that fail to start/stop (especially sporadic failures) it
might be necessary to trigger the watchdog machinery and write core
dumps, though. Likewise, it is usually just a waste of time to
gracefully stop a stuck service. Instead it might save time to go
directly into kill mode.

This commit adds two new options to services: TimeoutStartFailureMode=
and TimeoutStopFailureMode=. Both take the same values and tweak the
behavior of systemd when a start/stop timeout expires:

 * 'terminate': is the default behaviour as it has always been,
 * 'abort': triggers the watchdog machinery and will send SIGABRT
   (unless WatchdogSignal was changed) and
 * 'kill' will directly send SIGKILL.

To handle the stop failure mode in stop-post state too a new
final-watchdog state needs to be introduced.
2020-06-09 10:04:57 +02:00
Lennart Poettering 8b5616fa91
Merge pull request #16073 from keszybz/shell-completion
Bash completion for homectl and help improvement for kernel-install
2020-06-09 09:33:41 +02:00
Lennart Poettering d3d0b763b4
Merge pull request #15953 from keszybz/gdb-script
Update gdb script to match current sources and other hashmap improvements
2020-06-09 09:31:49 +02:00
Lennart Poettering 5a36324962
Merge pull request #16047 from poettering/udev-ro-block
udev: optionally mark all block devices popping up read-only by default
2020-06-09 09:09:32 +02:00
Lennart Poettering 707dc7949c update TODO 2020-06-09 08:54:48 +02:00
Yu Watanabe a4d1bef73f
Merge pull request #16085 from ssahani/network-client-id
networkctl: add support to display DHCPv4 client ID
2020-06-09 15:30:23 +09:00
Maxim Fomin 6cc27c29ad Add 'bitlk' option to mount Bitlocker drives with cryptsetup. 2020-06-09 08:12:55 +02:00
YmrDtnJu c15ab81ed9
mount-tool: Replace fstype_is_{network,api_vfs} with fstype_is_blockdev_backed
Not every filesystem that is not a network filesystem and also not an API VFS
filesystem has a corresponding block device.
2020-06-08 19:36:42 +02:00
YmrDtnJu ac2474e4ff
basic: New function fstype_is_blockdev_backed for fstypes that need a blockdev
The function returns true if the specified filesystem requires a block device.
2020-06-08 19:36:42 +02:00
Lennart Poettering a34a2933e9 man: single-char parameters take no '='
The suggested syntax is simply not valid and results in an error.
2020-06-08 16:53:37 +02:00
Lennart Poettering 048b4dc2e1 units: tweak udev unit descriptions 2020-06-08 16:53:37 +02:00
Lennart Poettering 95ac523030 udev: optionally mark all block devices read-only as they pop up 2020-06-08 16:53:37 +02:00
Susant Sahani 2153bbc81a networkctl: Display DHCP4 client ID 2020-06-08 07:09:32 +02:00
Susant Sahani daec96821d sd-network: Introduce API to access DHCP4 client ID 2020-06-08 07:09:24 +02:00
Susant Sahani 5dfaf89b5b network: DHCP4 client ID save in state file 2020-06-08 07:08:04 +02:00
Zbigniew Jędrzejewski-Szmek 3a9692dd05 shell-completion: add homectl for bash
The difference between verbs that take one user and multiple users is not
handled. I don't know how to do this.
2020-06-05 16:34:18 +02:00
Zbigniew Jędrzejewski-Szmek 3ac33bc966 kernel-install: extend --help 2020-06-05 16:34:05 +02:00
Michal Sekletár 2884836e3c core: fix the return value in order to make sure we don't dipatch method return too early
Actually, it is the same kind of problem as in d910f4c . Basically, we
need to return 1 on success code path in slice_freezer_action().
Otherwise we dispatch DBus return message too soon.

Fixes: #16050
2020-06-05 16:10:40 +02:00
Michal Sekletár a0d79df8e5 tests: sleep a bit and give kernel time to perform the action after manual freeze/thaw
Fixes: #16050
2020-06-05 16:10:28 +02:00
Zbigniew Jędrzejewski-Szmek 856e51957a strv: propagate location info from the call site too 2020-05-30 11:40:53 +02:00
Zbigniew Jędrzejewski-Szmek 138f49e452 basic/hashmap,set: change "internal_" to "_" as the prefix
"internal" is a lot of characters. Let's take a leaf out of the Python's book
and simply use _ to mean private. Much less verbose, but the meaning is just as
clear, or even more.
2020-05-30 11:40:53 +02:00
Zbigniew Jędrzejewski-Szmek ea806175cd gdb: make output a bit nicer
Now: set, 0x7f19be8f7c20 <string_hash_ops>, False, 1, 1, 4, unit_new, src/core/unit.c:96
2020-05-30 11:40:53 +02:00
Zbigniew Jędrzejewski-Szmek 68b0ab5891 gitignore: ignore mypy cache
mypy is occasionally useful for checking python scripts.
2020-05-30 11:40:53 +02:00
Zbigniew Jędrzejewski-Szmek 55825de59b basic/hashmap: drop unneeded macro 2020-05-30 11:40:53 +02:00
Zbigniew Jędrzejewski-Szmek 3aff6c7917 gdb: update accessors for bucket counts and entry sizes
Afaict, this code never worked, since even when this code was added in
2ea8c08306, neither all_entry_sizes nor
all_direct_buckets were defined.
2020-05-30 11:40:53 +02:00
Zbigniew Jędrzejewski-Szmek 31ca609f8a gdb: drop python2 support 2020-05-30 11:40:53 +02:00
Zbigniew Jędrzejewski-Szmek 43874aa7bb hashmap: don't allow hashmap_type_info table to be optimized away
This makes debugging hashmaps harder, because we can't query the size.  Make
sure that table is always present.
2020-05-30 11:40:37 +02:00
Zbigniew Jędrzejewski-Szmek c544fc319c tools/gdb: decrese indentation to 4 spaces
This follows PEP 8 and matces other python code in systemd.
2020-05-30 11:24:58 +02:00
Zbigniew Jędrzejewski-Szmek 06134457d2 basic/hashmap: update comment 2020-05-30 11:24:57 +02:00
41 changed files with 796 additions and 277 deletions

3
.gitignore vendored
View File

@ -12,6 +12,8 @@
.config.args .config.args
.gdb_history .gdb_history
.deps/ .deps/
.mypy_cache/
__pycache__/
/*.gcda /*.gcda
/*.gcno /*.gcno
/*.tar.bz2 /*.tar.bz2
@ -34,4 +36,3 @@
/mkosi.builddir/ /mkosi.builddir/
/mkosi.output/ /mkosi.output/
/tags /tags
__pycache__/

8
TODO
View File

@ -19,6 +19,14 @@ Janitorial Clean-ups:
Features: 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 * 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 * build short web pages out of each catalog entry, build them along with man

View File

@ -312,6 +312,10 @@ sensor:modalias:platform:cros-ec-accel:dmi:*:svnGOOGLE*
sensor:modalias:platform:cros-ec-accel:dmi:*:svnGoogle:pnCaroline* sensor:modalias:platform:cros-ec-accel:dmi:*:svnGoogle:pnCaroline*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1 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 # GP-electronic
######################################### #########################################

View File

@ -177,6 +177,13 @@
<option>size=</option>.</para></listitem> <option>size=</option>.</para></listitem>
</varlistentry> </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> <varlistentry>
<term><option>_netdev</option></term> <term><option>_netdev</option></term>

View File

@ -273,7 +273,8 @@
<term><varname>rd.udev.event_timeout=</varname></term> <term><varname>rd.udev.event_timeout=</varname></term>
<term><varname>udev.timeout_signal=</varname></term> <term><varname>udev.timeout_signal=</varname></term>
<term><varname>rd.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.ifnames=</varname></term>
<term><varname>net.naming-scheme=</varname></term> <term><varname>net.naming-scheme=</varname></term>

View File

@ -77,7 +77,7 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>-c=</option></term> <term><option>-c</option></term>
<term><option>--children-max=</option></term> <term><option>--children-max=</option></term>
<listitem> <listitem>
<para>Limit the number of events executed in parallel.</para> <para>Limit the number of events executed in parallel.</para>
@ -85,7 +85,7 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>-e=</option></term> <term><option>-e</option></term>
<term><option>--exec-delay=</option></term> <term><option>--exec-delay=</option></term>
<listitem> <listitem>
<para>Delay the execution of <varname>RUN</varname> <para>Delay the execution of <varname>RUN</varname>
@ -97,7 +97,7 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>-t=</option></term> <term><option>-t</option></term>
<term><option>--event-timeout=</option></term> <term><option>--event-timeout=</option></term>
<listitem> <listitem>
<para>Set the number of seconds to wait for events to finish. After <para>Set the number of seconds to wait for events to finish. After
@ -121,7 +121,7 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>-N=</option></term> <term><option>-N</option></term>
<term><option>--resolve-names=</option></term> <term><option>--resolve-names=</option></term>
<listitem> <listitem>
<para>Specify when systemd-udevd should resolve names of users and groups. <para>Specify when systemd-udevd should resolve names of users and groups.
@ -140,8 +140,8 @@
<refsect1><title>Kernel command line</title> <refsect1><title>Kernel command line</title>
<variablelist class='kernel-commandline-options'> <variablelist class='kernel-commandline-options'>
<para>Parameters starting with "rd." will be read when <para>Parameters prefixed with "rd." will be read when <command>systemd-udevd</command> is used in an
<command>systemd-udevd</command> is used in an initrd.</para> initrd, those without will be processed both in the initrd and on the host.</para>
<varlistentry> <varlistentry>
<term><varname>udev.log_priority=</varname></term> <term><varname>udev.log_priority=</varname></term>
<term><varname>rd.udev.log_priority=</varname></term> <term><varname>rd.udev.log_priority=</varname></term>
@ -184,6 +184,22 @@
setting in the configuration file and the one on the program command line.</para> setting in the configuration file and the one on the program command line.</para>
</listitem> </listitem>
</varlistentry> </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> <varlistentry>
<term><varname>net.ifnames=</varname></term> <term><varname>net.ifnames=</varname></term>
<listitem> <listitem>

View File

@ -560,16 +560,12 @@
<varlistentry> <varlistentry>
<term><varname>TimeoutStartSec=</varname></term> <term><varname>TimeoutStartSec=</varname></term>
<listitem><para>Configures the time to wait for start-up. If a <listitem><para>Configures the time to wait for start-up. If a daemon service does not signal start-up
daemon service does not signal start-up completion within the completion within the configured time, the service will be considered failed and will be shut down again. The
configured time, the service will be considered failed and precise action depends on the <varname>TimeoutStartFailureMode=</varname> option. Takes a unit-less value in
will be shut down again. Takes a unit-less value in seconds, seconds, or a time span value such as "5min 20s". Pass <literal>infinity</literal> to disable the timeout logic.
or a time span value such as "5min 20s". Pass Defaults to <varname>DefaultTimeoutStartSec=</varname> from the manager configuration file, except when
<literal>infinity</literal> to disable the timeout logic. Defaults to <varname>Type=oneshot</varname> is used, in which case the timeout is disabled by default (see
<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>). <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para> </para>
@ -588,7 +584,8 @@
<listitem><para>This option serves two purposes. First, it configures the time to wait for each <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 <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> 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 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 by <constant>SIGKILL</constant> (see <varname>KillMode=</varname> in
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>). <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
@ -646,6 +643,28 @@
</para></listitem> </para></listitem>
</varlistentry> </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> <varlistentry>
<term><varname>RuntimeMaxSec=</varname></term> <term><varname>RuntimeMaxSec=</varname></term>

View File

@ -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

View File

@ -72,7 +72,6 @@ _loginctl () {
return 0 return 0
fi fi
if [[ "$cur" = -* ]]; then if [[ "$cur" = -* ]]; then
COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
return 0 return 0

View File

@ -145,12 +145,7 @@ struct hashmap_debug_info {
/* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */ /* 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 LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list);
static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
#define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug;
#else /* !ENABLE_DEBUG_HASHMAP */
#define HASHMAP_DEBUG_FIELDS
#endif /* ENABLE_DEBUG_HASHMAP */
enum HashmapType { enum HashmapType {
HASHMAP_TYPE_PLAIN, HASHMAP_TYPE_PLAIN,
@ -212,7 +207,10 @@ struct HashmapBase {
bool from_pool:1; /* whether was allocated from mempool */ bool from_pool:1; /* whether was allocated from mempool */
bool dirty:1; /* whether dirtied since last iterated_cache_get() */ bool dirty:1; /* whether dirtied since last iterated_cache_get() */
bool cached:1; /* whether this hashmap is being cached */ 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 /* Specific hash types
@ -254,7 +252,7 @@ struct hashmap_type_info {
unsigned n_direct_buckets; 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] = { [HASHMAP_TYPE_PLAIN] = {
.head_size = sizeof(Hashmap), .head_size = sizeof(Hashmap),
.entry_size = sizeof(struct plain_hashmap_entry), .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); : 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; struct hashmap_base_entry *e;
void *data; void *data;
unsigned idx; 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) { 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) \ #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 != IDX_NIL); \
(idx) = hashmap_iterate_entry((h), &(i))) (idx) = hashmap_iterate_entry((h), &(i)))
IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h) { IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h) {
IteratedCache *cache; IteratedCache *cache;
assert(h); assert(h);
@ -809,15 +807,15 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
return h; 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); 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); 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); 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; 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); 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); 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); 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); 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) { 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); hashmap_free_no_clear(h);
} }
return NULL; 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; free_func_t free_key, free_value;
if (!h) if (!h)
return; 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 * 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. */ * 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 *k = NULL;
void *v; void *v;
v = internal_hashmap_first_key_and_value(h, true, &k); v = _hashmap_first_key_and_value(h, true, &k);
if (free_key) if (free_key)
free_key(k); free_key(k);
@ -1301,7 +1299,7 @@ int hashmap_update(Hashmap *h, const void *key, void *value) {
return 0; return 0;
} }
void *internal_hashmap_get(HashmapBase *h, const void *key) { void *_hashmap_get(HashmapBase *h, const void *key) {
struct hashmap_base_entry *e; struct hashmap_base_entry *e;
unsigned hash, idx; unsigned hash, idx;
@ -1336,7 +1334,7 @@ void *hashmap_get2(Hashmap *h, const void *key, void **key2) {
return e->value; return e->value;
} }
bool internal_hashmap_contains(HashmapBase *h, const void *key) { bool _hashmap_contains(HashmapBase *h, const void *key) {
unsigned hash; unsigned hash;
if (!h) if (!h)
@ -1346,7 +1344,7 @@ bool internal_hashmap_contains(HashmapBase *h, const void *key) {
return bucket_scan(h, hash, key) != IDX_NIL; 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; struct hashmap_base_entry *e;
unsigned hash, idx; unsigned hash, idx;
void *data; void *data;
@ -1484,7 +1482,7 @@ int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_
return 0; 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; struct hashmap_base_entry *e;
unsigned hash, idx; unsigned hash, idx;
@ -1514,7 +1512,7 @@ static unsigned find_first_entry(HashmapBase *h) {
return hashmap_iterate_entry(h, &i); 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; struct hashmap_base_entry *e;
void *key, *data; void *key, *data;
unsigned idx; unsigned idx;
@ -1539,21 +1537,21 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r
return data; return data;
} }
unsigned internal_hashmap_size(HashmapBase *h) { unsigned _hashmap_size(HashmapBase *h) {
if (!h) if (!h)
return 0; return 0;
return n_entries(h); return n_entries(h);
} }
unsigned internal_hashmap_buckets(HashmapBase *h) { unsigned _hashmap_buckets(HashmapBase *h) {
if (!h) if (!h)
return 0; return 0;
return n_buckets(h); return n_buckets(h);
} }
int internal_hashmap_merge(Hashmap *h, Hashmap *other) { int _hashmap_merge(Hashmap *h, Hashmap *other) {
Iterator i; Iterator i;
unsigned idx; unsigned idx;
@ -1589,7 +1587,7 @@ int set_merge(Set *s, Set *other) {
return 0; return 0;
} }
int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) { int _hashmap_reserve(HashmapBase *h, unsigned entries_add) {
int r; int r;
assert(h); assert(h);
@ -1607,7 +1605,7 @@ int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) {
* Returns: 0 on success. * Returns: 0 on success.
* -ENOMEM on alloc failure, in which case no move has been done. * -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 swap_entries swap;
struct hashmap_base_entry *e, *n; struct hashmap_base_entry *e, *n;
Iterator i; Iterator i;
@ -1652,7 +1650,7 @@ int internal_hashmap_move(HashmapBase *h, HashmapBase *other) {
return 0; 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; struct swap_entries swap;
unsigned h_hash, other_hash, idx; unsigned h_hash, other_hash, idx;
struct hashmap_base_entry *e, *n; struct hashmap_base_entry *e, *n;
@ -1689,7 +1687,7 @@ int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *ke
return 0; return 0;
} }
HashmapBase *internal_hashmap_copy(HashmapBase *h) { HashmapBase *_hashmap_copy(HashmapBase *h) {
HashmapBase *copy; HashmapBase *copy;
int r; int r;
@ -1712,14 +1710,14 @@ HashmapBase *internal_hashmap_copy(HashmapBase *h) {
} }
if (r < 0) { if (r < 0) {
internal_hashmap_free(copy, false, false); _hashmap_free(copy, false, false);
return NULL; return NULL;
} }
return copy; return copy;
} }
char **internal_hashmap_get_strv(HashmapBase *h) { char **_hashmap_get_strv(HashmapBase *h) {
char **sv; char **sv;
Iterator i; Iterator i;
unsigned idx, n; unsigned idx, n;

View File

@ -14,7 +14,7 @@
* will be treated as empty hashmap for all read operations. That way it is not * will be treated as empty hashmap for all read operations. That way it is not
* necessary to instantiate an object for each Hashmap use. * 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: * the implementation will:
* - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py) * - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
* - perform extra checks for invalid use of iterators * - perform extra checks for invalid use of iterators
@ -24,10 +24,9 @@
typedef void* (*hashmap_destroy_t)(void *p); typedef void* (*hashmap_destroy_t)(void *p);
/* The base type for all hashmap and set types. Many functions in the /* The base type for all hashmap and set types. Many functions in the implementation take (HashmapBase*)
* implementation take (HashmapBase*) parameters and are run-time polymorphic, * parameters and are run-time polymorphic, though the API is not meant to be polymorphic (do not call
* though the API is not meant to be polymorphic (do not call functions * underscore-prefixed functions directly). */
* internal_*() directly). */
typedef struct HashmapBase HashmapBase; typedef struct HashmapBase HashmapBase;
/* Specific hashmap/set types */ /* Specific hashmap/set types */
@ -84,10 +83,10 @@ typedef struct {
# define HASHMAP_DEBUG_PASS_ARGS # define HASHMAP_DEBUG_PASS_ARGS
#endif #endif
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);
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);
#define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) #define hashmap_new(ops) _hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
#define ordered_hashmap_new(ops) internal_ordered_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) \ #define hashmap_free_and_replace(a, b) \
({ \ ({ \
@ -97,57 +96,57 @@ OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HA
0; \ 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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); IteratedCache *iterated_cache_free(IteratedCache *cache);
int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries); 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) { 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) { 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 _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); int _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 hashmap_ensure_allocated(h, ops) _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) #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) { 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) { 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); 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); 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) { 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) { 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); 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); 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) { 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) { 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) { 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) { 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); 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); 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) { 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) { 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 /* Since merging data from a OrderedHashmap into a Hashmap or vice-versa
* should just work, allow this by having looser type-checking here. */ * should just work, allow this by having looser type-checking here. */
int internal_hashmap_merge(Hashmap *h, Hashmap *other); int _hashmap_merge(Hashmap *h, Hashmap *other);
#define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_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) #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) { 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) { 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. */ /* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */
static inline int hashmap_move(Hashmap *h, Hashmap *other) { 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) { 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) { 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) { 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) { 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) { 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) { 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; 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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). * 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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 *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; return key;
} }
static inline void *hashmap_steal_first_key(Hashmap *h) { 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) { 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) { 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) { 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) \ #define hashmap_clear_with_destructor(_s, _f) \
@ -394,12 +393,12 @@ static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
/* no hashmap_next */ /* no hashmap_next */
void *ordered_hashmap_next(OrderedHashmap *h, const void *key); 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) { 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) { static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
return internal_hashmap_get_strv(HASHMAP_BASE(h)); return _hashmap_get_strv(HASHMAP_BASE(h));
} }
/* /*

View File

@ -338,6 +338,16 @@ bool fstype_is_api_vfs(const char *fstype) {
"tracefs"); "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) { bool fstype_is_ro(const char *fstype) {
/* All Linux file systems that are necessarily read-only */ /* All Linux file systems that are necessarily read-only */
return STR_IN_SET(fstype, return STR_IN_SET(fstype,

View 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_network(const char *fstype);
bool fstype_is_api_vfs(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_is_ro(const char *fsype);
bool fstype_can_discard(const char *fstype); bool fstype_can_discard(const char *fstype);
bool fstype_can_uid_gid(const char *fstype); bool fstype_can_uid_gid(const char *fstype);

View File

@ -59,7 +59,7 @@ static inline void* ordered_set_steal_first(OrderedSet *s) {
} }
static inline char **ordered_set_get_strv(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); int ordered_set_consume(OrderedSet *s, void *p);

View File

@ -13,40 +13,40 @@
0; \ 0; \
}) })
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);
#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS) #define set_new(ops) _set_new(ops HASHMAP_DEBUG_SRC_ARGS)
static inline Set *set_free(Set *s) { 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) { 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 */ /* no set_free_free_free */
static inline Set *set_copy(Set *s) { 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); int _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) #define set_ensure_allocated(h, ops) _set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
int set_put(Set *s, const void *key); int set_put(Set *s, const void *key);
/* no set_update */ /* no set_update */
/* no set_replace */ /* no set_replace */
static inline void *set_get(const Set *s, void *key) { 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 */ /* no set_get2 */
static inline bool set_contains(const Set *s, const void *key) { 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) { 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 */ /* 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); int set_merge(Set *s, Set *other);
static inline int set_reserve(Set *h, unsigned entries_add) { 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) { 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) { 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) { 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) { 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) { 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); bool set_iterate(const Set *s, Iterator *i, void **value);
static inline void set_clear(Set *s) { 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) { 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 */ /* no set_clear_free_free */
static inline void *set_steal_first(Set *s) { 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) \ #define set_clear_with_destructor(_s, _f) \
@ -111,13 +111,13 @@ static inline void *set_steal_first(Set *s) {
/* no set_first_key */ /* no set_first_key */
static inline void *set_first(const Set *s) { 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 */ /* no set_next */
static inline char **set_get_strv(Set *s) { 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); int set_consume(Set *s, void *value);

View File

@ -946,20 +946,20 @@ static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const c
return 1; 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; 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) if (r < 0)
return r; return r;
return string_strv_hashmap_put_internal(*h, key, value); 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; 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) if (r < 0)
return r; return r;

View 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; 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_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); 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)

View File

@ -185,6 +185,7 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = {
[SERVICE_STOP_SIGTERM] = "stop-sigterm", [SERVICE_STOP_SIGTERM] = "stop-sigterm",
[SERVICE_STOP_SIGKILL] = "stop-sigkill", [SERVICE_STOP_SIGKILL] = "stop-sigkill",
[SERVICE_STOP_POST] = "stop-post", [SERVICE_STOP_POST] = "stop-post",
[SERVICE_FINAL_WATCHDOG] = "final-watchdog",
[SERVICE_FINAL_SIGTERM] = "final-sigterm", [SERVICE_FINAL_SIGTERM] = "final-sigterm",
[SERVICE_FINAL_SIGKILL] = "final-sigkill", [SERVICE_FINAL_SIGKILL] = "final-sigkill",
[SERVICE_FAILED] = "failed", [SERVICE_FAILED] = "failed",

View File

@ -127,6 +127,7 @@ typedef enum ServiceState {
SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGTERM,
SERVICE_STOP_SIGKILL, SERVICE_STOP_SIGKILL,
SERVICE_STOP_POST, 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_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */
SERVICE_FINAL_SIGKILL, SERVICE_FINAL_SIGKILL,
SERVICE_FAILED, SERVICE_FAILED,

View 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_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_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(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( static int property_get_exit_status_set(
sd_bus *bus, 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("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("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("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("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), SD_BUS_PROPERTY("WatchdogUSec", "t", property_get_watchdog_usec, 0, 0),
BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 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(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_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_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( static int bus_service_set_transient_property(
Service *s, Service *s,
@ -316,6 +320,12 @@ static int bus_service_set_transient_property(
return r; 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")) if (streq(name, "RuntimeMaxUSec"))
return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error); return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error);

View File

@ -322,6 +322,8 @@ Service.TimeoutSec, config_parse_service_timeout, 0,
Service.TimeoutStartSec, config_parse_service_timeout, 0, 0 Service.TimeoutStartSec, config_parse_service_timeout, 0, 0
Service.TimeoutStopSec, config_parse_sec_fix_0, 0, offsetof(Service, timeout_stop_usec) Service.TimeoutStopSec, config_parse_sec_fix_0, 0, offsetof(Service, timeout_stop_usec)
Service.TimeoutAbortSec, config_parse_service_timeout_abort, 0, 0 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.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_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 m4_dnl The following five only exist for compatibility, they moved into Unit, see above

View 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_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_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_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_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(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"); 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_exec, "PATH [ARGUMENT [...]]" },
{ config_parse_service_type, "SERVICETYPE" }, { config_parse_service_type, "SERVICETYPE" },
{ config_parse_service_restart, "SERVICERESTART" }, { config_parse_service_restart, "SERVICERESTART" },
{ config_parse_service_timeout_failure_mode, "TIMEOUTMODE" },
{ config_parse_kill_mode, "KILLMODE" }, { config_parse_kill_mode, "KILLMODE" },
{ config_parse_signal, "SIGNAL" }, { config_parse_signal, "SIGNAL" },
{ config_parse_socket_listen, "SOCKET [...]" }, { config_parse_socket_listen, "SOCKET [...]" },

View File

@ -30,6 +30,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_coredump_filter);
CONFIG_PARSER_PROTOTYPE(config_parse_exec); CONFIG_PARSER_PROTOTYPE(config_parse_exec);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout); CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_abort); 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_type);
CONFIG_PARSER_PROTOTYPE(config_parse_service_restart); CONFIG_PARSER_PROTOTYPE(config_parse_service_restart);
CONFIG_PARSER_PROTOTYPE(config_parse_socket_bindtodevice); CONFIG_PARSER_PROTOTYPE(config_parse_socket_bindtodevice);

View File

@ -56,6 +56,7 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING, [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING, [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
[SERVICE_STOP_POST] = UNIT_DEACTIVATING, [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
[SERVICE_FINAL_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING, [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
[SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING, [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
[SERVICE_FAILED] = UNIT_FAILED, [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_SIGTERM] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING, [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
[SERVICE_STOP_POST] = UNIT_DEACTIVATING, [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
[SERVICE_FINAL_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING, [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
[SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING, [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
[SERVICE_FAILED] = UNIT_FAILED, [SERVICE_FAILED] = UNIT_FAILED,
@ -857,10 +859,14 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
fprintf(f, fprintf(f,
"%sRestartSec: %s\n" "%sRestartSec: %s\n"
"%sTimeoutStartSec: %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_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_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) if (s->timeout_abort_set)
fprintf(f, fprintf(f,
@ -1072,7 +1078,7 @@ static void service_set_state(Service *s, ServiceState state) {
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_RELOAD, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_AUTO_RESTART, SERVICE_AUTO_RESTART,
SERVICE_CLEANING)) SERVICE_CLEANING))
s->timer_event_source = sd_event_source_unref(s->timer_event_source); 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_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RUNNING, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
service_unwatch_main_pid(s); service_unwatch_main_pid(s);
s->main_command = NULL; 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_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) { SERVICE_CLEANING)) {
service_unwatch_control_pid(s); service_unwatch_control_pid(s);
s->control_command = NULL; 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_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RUNNING, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) && SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
!(state == SERVICE_DEAD && UNIT(s)->job)) !(state == SERVICE_DEAD && UNIT(s)->job))
service_close_socket_fd(s); 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); return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_stop_usec);
case SERVICE_STOP_WATCHDOG: case SERVICE_STOP_WATCHDOG:
case SERVICE_FINAL_WATCHDOG:
return usec_add(UNIT(s)->state_change_timestamp.monotonic, service_timeout_abort_usec(s)); return usec_add(UNIT(s)->state_change_timestamp.monotonic, service_timeout_abort_usec(s));
case SERVICE_AUTO_RESTART: case SERVICE_AUTO_RESTART:
@ -1187,7 +1194,7 @@ static int service_coldplug(Unit *u) {
SERVICE_START, SERVICE_START_POST, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RUNNING, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) { SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
r = unit_watch_pid(UNIT(s), s->main_pid, false); r = unit_watch_pid(UNIT(s), s->main_pid, false);
if (r < 0) if (r < 0)
return r; return r;
@ -1199,7 +1206,7 @@ static int service_coldplug(Unit *u) {
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) { SERVICE_CLEANING)) {
r = unit_watch_pid(UNIT(s), s->control_pid, false); r = unit_watch_pid(UNIT(s), s->control_pid, false);
if (r < 0) if (r < 0)
@ -1859,6 +1866,7 @@ static int state_to_kill_operation(Service *s, ServiceState state) {
switch (state) { switch (state) {
case SERVICE_STOP_WATCHDOG: case SERVICE_STOP_WATCHDOG:
case SERVICE_FINAL_WATCHDOG:
return KILL_WATCHDOG; return KILL_WATCHDOG;
case SERVICE_STOP_SIGTERM: 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) { static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) {
int r; int kill_operation, r;
assert(s); assert(s);
@ -1893,10 +1901,11 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
* died now */ * died now */
(void) unit_enqueue_rewatch_pids(UNIT(s)); (void) unit_enqueue_rewatch_pids(UNIT(s));
kill_operation = state_to_kill_operation(s, state);
r = unit_kill_context( r = unit_kill_context(
UNIT(s), UNIT(s),
&s->kill_context, &s->kill_context,
state_to_kill_operation(s, state), kill_operation,
s->main_pid, s->main_pid,
s->control_pid, s->control_pid,
s->main_pid_alien); s->main_pid_alien);
@ -1905,7 +1914,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
if (r > 0) { if (r > 0) {
r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), 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) if (r < 0)
goto fail; 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); service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_SUCCESS);
else if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL)) else if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
service_enter_stop_post(s, SERVICE_SUCCESS); 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); service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
else else
service_enter_dead(s, SERVICE_SUCCESS, true); service_enter_dead(s, SERVICE_SUCCESS, true);
@ -2444,7 +2453,7 @@ static int service_start(Unit *u) {
* please! */ * please! */
if (IN_SET(s->state, if (IN_SET(s->state,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_CLEANING)) SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_CLEANING))
return -EAGAIN; return -EAGAIN;
/* Already on it! */ /* Already on it! */
@ -2515,7 +2524,7 @@ static int service_stop(Unit *u) {
/* Already on it */ /* Already on it */
if (IN_SET(s->state, if (IN_SET(s->state,
SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, 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; return 0;
/* A restart will be scheduled or is in progress. */ /* A restart will be scheduled or is in progress. */
@ -3321,6 +3330,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
break; break;
case SERVICE_STOP_POST: case SERVICE_STOP_POST:
case SERVICE_FINAL_WATCHDOG:
case SERVICE_FINAL_SIGTERM: case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL: case SERVICE_FINAL_SIGKILL:
if (main_pid_good(s) <= 0 && control_pid_good(s) <= 0) 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; break;
case SERVICE_FINAL_WATCHDOG:
case SERVICE_FINAL_SIGTERM: case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL: 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); service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
break; break;
case SERVICE_FINAL_WATCHDOG:
case SERVICE_FINAL_SIGTERM: case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL: case SERVICE_FINAL_SIGKILL:
if (main_pid_good(s) <= 0) 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_CONDITION:
case SERVICE_START_PRE: case SERVICE_START_PRE:
case SERVICE_START: case SERVICE_START:
case SERVICE_START_POST:
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)); 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); service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break; break;
case SERVICE_START_POST: case SERVICE_TIMEOUT_ABORT:
log_unit_warning(UNIT(s), "Start-post operation timed out. Stopping."); log_unit_warning(UNIT(s), "%s operation timed out. Aborting.", service_state_to_string(s->state));
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT); 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; break;
case SERVICE_RUNNING: case SERVICE_RUNNING:
@ -3742,17 +3773,48 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
break; break;
case SERVICE_STOP: case SERVICE_STOP:
switch (s->timeout_stop_failure_mode) {
case SERVICE_TIMEOUT_TERMINATE:
log_unit_warning(UNIT(s), "Stopping timed out. Terminating."); log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT); service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break; 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: case SERVICE_STOP_WATCHDOG:
log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Terminating."); if (s->kill_context.send_sigkill) {
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT); 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; break;
case SERVICE_STOP_SIGTERM: 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."); log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Killing.");
service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT); service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
} else { } else {
@ -3772,16 +3834,52 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
break; break;
case SERVICE_STOP_POST: case SERVICE_STOP_POST:
switch (s->timeout_stop_failure_mode) {
case SERVICE_TIMEOUT_TERMINATE:
log_unit_warning(UNIT(s), "State 'stop-post' timed out. Terminating."); log_unit_warning(UNIT(s), "State 'stop-post' timed out. Terminating.");
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT); service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break; break;
case SERVICE_FINAL_SIGTERM: 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) { if (s->kill_context.send_sigkill) {
log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Killing."); log_unit_warning(UNIT(s), "State 'stop-post' timed out. Killing.");
service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT); service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
} else { } else {
log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Skipping SIGKILL. Entering failed mode."); 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_WATCHDOG:
if (s->kill_context.send_sigkill) {
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 '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); service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
} }
@ -4263,6 +4361,7 @@ static bool service_needs_console(Unit *u) {
SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGTERM,
SERVICE_STOP_SIGKILL, SERVICE_STOP_SIGKILL,
SERVICE_STOP_POST, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGTERM,
SERVICE_FINAL_SIGKILL); SERVICE_FINAL_SIGKILL);
} }
@ -4417,6 +4516,14 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult); 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 = { const UnitVTable service_vtable = {
.object_size = sizeof(Service), .object_size = sizeof(Service),
.exec_context_offset = offsetof(Service, exec_context), .exec_context_offset = offsetof(Service, exec_context),

View File

@ -74,6 +74,14 @@ typedef enum ServiceResult {
_SERVICE_RESULT_INVALID = -1 _SERVICE_RESULT_INVALID = -1
} ServiceResult; } 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 { struct ServiceFDStore {
Service *service; Service *service;
@ -103,6 +111,8 @@ struct Service {
usec_t timeout_abort_usec; usec_t timeout_abort_usec;
bool timeout_abort_set; bool timeout_abort_set;
usec_t runtime_max_usec; usec_t runtime_max_usec;
ServiceTimeoutFailureMode timeout_start_failure_mode;
ServiceTimeoutFailureMode timeout_stop_failure_mode;
dual_timestamp watchdog_timestamp; dual_timestamp watchdog_timestamp;
usec_t watchdog_usec; /* the requested watchdog timeout in the unit file */ 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_; const char* service_result_to_string(ServiceResult i) _const_;
ServiceResult service_result_from_string(const char *s) _pure_; 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_CAST(SERVICE, Service);
#define STATUS_TEXT_MAX (16U*1024U) #define STATUS_TEXT_MAX (16U*1024U)

View File

@ -403,7 +403,7 @@ static int slice_freezer_action(Unit *s, FreezerAction action) {
if (r < 0) if (r < 0)
return r; return r;
return 0; return 1;
} }
static int slice_freeze(Unit *s) { static int slice_freeze(Unit *s) {

View File

@ -38,7 +38,7 @@
#define CRYPT_SECTOR_SIZE 512 #define CRYPT_SECTOR_SIZE 512
#define CRYPT_MAX_SECTOR_SIZE 4096 #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 char *arg_cipher = NULL;
static unsigned arg_key_size = 0; static unsigned arg_key_size = 0;
static unsigned arg_sector_size = CRYPT_SECTOR_SIZE; 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; arg_submit_from_crypt_cpus = true;
else if (streq(option, "luks")) else if (streq(option, "luks"))
arg_type = ANY_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")) else if (streq(option, "tcrypt"))
arg_type = CRYPT_TCRYPT; arg_type = CRYPT_TCRYPT;
else if (STR_IN_SET(option, "tcrypt-hidden", "tcrypthidden")) { else if (STR_IN_SET(option, "tcrypt-hidden", "tcrypthidden")) {
@ -545,7 +550,7 @@ static int attach_tcrypt(
return 0; return 0;
} }
static int attach_luks_or_plain( static int attach_luks_or_plain_or_bitlk(
struct crypt_device *cd, struct crypt_device *cd,
const char *name, const char *name,
const char *key_file, 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++) { for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
_cleanup_strv_free_erase_ char **passwords = NULL; _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)) if (streq_ptr(arg_type, CRYPT_TCRYPT))
r = attach_tcrypt(cd, argv[2], key_file, key_data, key_data_size, passwords, flags); r = attach_tcrypt(cd, argv[2], key_file, key_data, key_data_size, passwords, flags);
else 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) if (r >= 0)
break; break;
if (r != -EAGAIN) if (r != -EAGAIN)

7
src/kernel-install/kernel-install Normal file → Executable file
View File

@ -23,8 +23,11 @@ SKIP_REMAINING=77
usage() usage()
{ {
echo "Usage:" echo "Usage:"
echo " $0 add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]" echo " $0 [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]"
echo " $0 remove KERNEL-VERSION" echo " $0 [OPTIONS...] remove KERNEL-VERSION"
echo "Options:"
echo " -h,--help Print this help"
echo " -v,--verbose Increase verbosity"
} }
dropindirs_sort() dropindirs_sort()

View 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); 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) { _public_ int sd_network_link_get_required_for_online(int ifindex) {
_cleanup_free_ char *s = NULL; _cleanup_free_ char *s = NULL;
int r; int r;

View 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" ENV{DRIVER}=="", IMPORT{cmdline}="nomodeset", TAG+="seat", TAG+="master-of-seat"
SUBSYSTEM=="drm", KERNEL=="card[0-9]*", 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" SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat"
# 'Plugable' USB hub, sound, network, graphics adapter # 'Plugable' USB hub, sound, network, graphics adapter

View File

@ -364,7 +364,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"At most two arguments required."); "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]); arg_mount_what = strdup(argv[optind]);
if (!arg_mount_what) if (!arg_mount_what)
return log_oom(); return log_oom();
@ -1463,7 +1463,7 @@ static int run(int argc, char* argv[]) {
if (arg_action == ACTION_UMOUNT) if (arg_action == ACTION_UMOUNT)
return action_umount(bus, argc, argv); 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)) { && !path_is_normalized(arg_mount_what)) {
log_error("Path contains non-normalized components: %s", arg_mount_what); log_error("Path contains non-normalized components: %s", arg_mount_what);
return -EINVAL; return -EINVAL;

View 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, _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; **pop3_server = NULL, **smtp_server = NULL, **lpr_server = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = 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 *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
const char *on_color_operational, *off_color_operational, const char *on_color_operational, *off_color_operational,
*on_color_setup, *off_color_setup; *on_color_setup, *off_color_setup;
@ -2073,6 +2073,16 @@ static int link_status_one(
return table_log_add_error(r); 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); r = dump_lldp_neighbors(table, "Connected To:", info->ifindex);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -4374,6 +4374,8 @@ int link_save(Link *link) {
if (link->dhcp_lease) { if (link->dhcp_lease) {
struct in_addr address; struct in_addr address;
const char *tz = NULL; const char *tz = NULL;
size_t client_id_len;
const void *client_id;
assert(link->network); assert(link->network);
@ -4388,6 +4390,15 @@ int link_save(Link *link) {
fputc('\n', f); 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); r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
if (r < 0) if (r < 0)
goto fail; goto fail;

View File

@ -1490,7 +1490,9 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
"NotifyAccess", "NotifyAccess",
"USBFunctionDescriptors", "USBFunctionDescriptors",
"USBFunctionStrings", "USBFunctionStrings",
"OOMPolicy")) "OOMPolicy",
"TimeoutStartFailureMode",
"TimeoutStopFailureMode"))
return bus_append_string(m, field, eq); return bus_append_string(m, field, eq);
if (STR_IN_SET(field, "PermissionsStartOnly", if (STR_IN_SET(field, "PermissionsStartOnly",

View 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. */ /* Get the timezone that was learnt on a specific link. */
int sd_network_link_get_timezone(int ifindex, char **timezone); 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 */ /* Monitor object */
typedef struct sd_network_monitor sd_network_monitor; typedef struct sd_network_monitor sd_network_monitor;

View File

@ -76,6 +76,7 @@ static unsigned arg_children_max = 0;
static usec_t arg_exec_delay_usec = 0; static usec_t arg_exec_delay_usec = 0;
static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC; static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
static int arg_timeout_signal = SIGKILL; static int arg_timeout_signal = SIGKILL;
static bool arg_blockdev_read_only = false;
typedef struct Manager { typedef struct Manager {
sd_event *event; sd_event *event;
@ -383,6 +384,56 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) {
return 1; 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) { static int worker_process_device(Manager *manager, sd_device *dev) {
_cleanup_(udev_event_freep) UdevEvent *udev_event = NULL; _cleanup_(udev_event_freep) UdevEvent *udev_event = NULL;
_cleanup_close_ int fd_lock = -1; _cleanup_close_ int fd_lock = -1;
@ -412,6 +463,8 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
if (r < 0) if (r < 0)
return r; return r;
(void) worker_mark_block_device_read_only(dev);
/* apply rules, create node, symlinks */ /* apply rules, create node, symlinks */
r = udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_timeout_signal, manager->properties, manager->rules); r = udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_timeout_signal, manager->properties, manager->rules);
if (r < 0) 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.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.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.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) { static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
int r = 0; int r;
assert(key); assert(key);
if (!value)
return 0;
if (proc_cmdline_key_streq(key, "udev.log_priority")) { if (proc_cmdline_key_streq(key, "udev.log_priority")) {
if (proc_cmdline_value_missing(key, value)) 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); r = parse_sec(value, &arg_exec_delay_usec);
} else if (proc_cmdline_key_streq(key, "udev.timeout_signal")) { } else if (proc_cmdline_key_streq(key, "udev.timeout_signal")) {
if (proc_cmdline_value_missing(key, value)) if (proc_cmdline_value_missing(key, value))
return 0; return 0;
r = signal_from_string(value); r = signal_from_string(value);
if (r > 0) if (r > 0)
arg_timeout_signal = r; 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) if (r < 0)
log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value); log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);

View File

@ -246,6 +246,8 @@ test_preserve_state() {
echo -n " - freeze from outside: " echo -n " - freeze from outside: "
echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
# Give kernel some time to freeze the slice
sleep 1
# Our state should not be affected # Our state should not be affected
check_freezer_state "${slice}" "running" check_freezer_state "${slice}" "running"
@ -258,6 +260,8 @@ test_preserve_state() {
echo -n " - thaw from outside: " echo -n " - thaw from outside: "
echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
sleep 1
check_freezer_state "${unit}" "running" check_freezer_state "${unit}" "running"
check_freezer_state "${slice}" "running" check_freezer_state "${slice}" "running"
grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events

View File

@ -1,27 +1,24 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1+ # SPDX-License-Identifier: LGPL-2.1+
from __future__ import print_function
import gdb import gdb
class sd_dump_hashmaps(gdb.Command): class sd_dump_hashmaps(gdb.Command):
"dump systemd's hashmaps" "dump systemd's hashmaps"
def __init__(self): def __init__(self):
super(sd_dump_hashmaps, self).__init__("sd_dump_hashmaps", gdb.COMMAND_DATA, gdb.COMPLETE_NONE) super().__init__("sd_dump_hashmaps", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
def invoke(self, arg, from_tty): def invoke(self, arg, from_tty):
d = gdb.parse_and_eval("hashmap_debug_list") d = gdb.parse_and_eval("hashmap_debug_list")
all_entry_sizes = gdb.parse_and_eval("all_entry_sizes") hashmap_type_info = gdb.parse_and_eval("hashmap_type_info")
all_direct_buckets = gdb.parse_and_eval("all_direct_buckets")
uchar_t = gdb.lookup_type("unsigned char") uchar_t = gdb.lookup_type("unsigned char")
ulong_t = gdb.lookup_type("unsigned long") ulong_t = gdb.lookup_type("unsigned long")
debug_offset = gdb.parse_and_eval("(unsigned long)&((HashmapBase*)0)->debug") debug_offset = gdb.parse_and_eval("(unsigned long)&((HashmapBase*)0)->debug")
print("type, hash, indirect, entries, max_entries, buckets, creator") print("type, hash, indirect, entries, max_entries, buckets, creator")
while d: while d:
h = gdb.parse_and_eval("(HashmapBase*)((char*)%d - %d)" % (int(d.cast(ulong_t)), debug_offset)) h = gdb.parse_and_eval(f"(HashmapBase*)((char*){int(d.cast(ulong_t))} - {debug_offset})")
if h["has_indirect"]: if h["has_indirect"]:
storage_ptr = h["indirect"]["storage"].cast(uchar_t.pointer()) storage_ptr = h["indirect"]["storage"].cast(uchar_t.pointer())
@ -30,31 +27,32 @@ class sd_dump_hashmaps(gdb.Command):
else: else:
storage_ptr = h["direct"]["storage"].cast(uchar_t.pointer()) storage_ptr = h["direct"]["storage"].cast(uchar_t.pointer())
n_entries = h["n_direct_entries"] n_entries = h["n_direct_entries"]
n_buckets = all_direct_buckets[int(h["type"])]; n_buckets = hashmap_type_info[h["type"]]["n_direct_buckets"]
t = ["plain", "ordered", "set"][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"])) 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: if arg != "" and n_entries > 0:
dib_raw_addr = storage_ptr + (all_entry_sizes[h["type"]] * n_buckets) dib_raw_addr = storage_ptr + hashmap_type_info[h["type"]]["entry_size"] * n_buckets
histogram = {} histogram = {}
for i in xrange(0, n_buckets): for i in range(0, n_buckets):
dib = int(dib_raw_addr[i]) dib = int(dib_raw_addr[i])
histogram[dib] = histogram.get(dib, 0) + 1 histogram[dib] = histogram.get(dib, 0) + 1
for dib in sorted(iter(histogram)): for dib in sorted(histogram):
if dib != 255: if dib != 255:
print("{:>3} {:>8} {} of entries".format(dib, histogram[dib], 100.0*histogram[dib]/n_entries)) print(f"{dib:>3} {histogram[dib]:>8} {float(histogram[dib]/n_entries):.0%} of entries")
else: else:
print("{:>3} {:>8} {} of slots".format(dib, histogram[dib], 100.0*histogram[dib]/n_buckets)) print(f"{dib:>3} {histogram[dib]:>8} {float(histogram[dib]/n_buckets):.0%} of slots")
print("mean DIB of entries: {}".format(sum([dib*histogram[dib] for dib in iter(histogram) if dib != 255])*1.0/n_entries)) s = sum(dib*count for (dib, count) in histogram.items() if dib != 255) / n_entries
print(f"mean DIB of entries: {s}")
blocks = [] blocks = []
current_len = 1 current_len = 1
prev = int(dib_raw_addr[0]) prev = int(dib_raw_addr[0])
for i in xrange(1, n_buckets): for i in range(1, n_buckets):
dib = int(dib_raw_addr[i]) dib = int(dib_raw_addr[i])
if (dib == 255) != (prev == 255): if (dib == 255) != (prev == 255):
if prev != 255: if prev != 255:
@ -72,7 +70,7 @@ class sd_dump_hashmaps(gdb.Command):
blocks = blocks[0:-1] blocks = blocks[0:-1]
print("max block: {}".format(max(blocks, key=lambda a: a[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("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)))) print("mean block len: {}".format(sum(b[1] for b in blocks) / len(blocks)))
d = d["debug_list_next"] d = d["debug_list_next"]

View File

@ -8,7 +8,7 @@
# (at your option) any later version. # (at your option) any later version.
[Unit] [Unit]
Description=Cleanup udevd DB Description=Cleanup udev Database
DefaultDependencies=no DefaultDependencies=no
ConditionPathExists=/etc/initrd-release ConditionPathExists=/etc/initrd-release
Conflicts=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udev-trigger.service systemd-udev-settle.service Conflicts=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udev-trigger.service systemd-udev-settle.service

View File

@ -12,7 +12,7 @@
# expect a populated /dev during bootup. # expect a populated /dev during bootup.
[Unit] [Unit]
Description=udev Wait for Complete Device Initialization Description=Wait for udev To Complete Device Initialization
Documentation=man:systemd-udev-settle.service(8) Documentation=man:systemd-udev-settle.service(8)
DefaultDependencies=no DefaultDependencies=no
Wants=systemd-udevd.service Wants=systemd-udevd.service

View File

@ -8,7 +8,7 @@
# (at your option) any later version. # (at your option) any later version.
[Unit] [Unit]
Description=udev Coldplug all Devices Description=Coldplug All udev Devices
Documentation=man:udev(7) man:systemd-udevd.service(8) Documentation=man:udev(7) man:systemd-udevd.service(8)
DefaultDependencies=no DefaultDependencies=no
Wants=systemd-udevd.service Wants=systemd-udevd.service