.config.args
.gdb_history
.deps/
+.mypy_cache/
+__pycache__/
/*.gcda
/*.gcno
/*.tar.bz2
/mkosi.builddir/
/mkosi.output/
/tags
-__pycache__/
Features:
+* add systemd.random_seed= on the kernel cmdline, taking some hex or base64
+ encoded data. During earliest boot, credit it to entropy. This is not useful
+ for general purpose systems, but certainly for testing environments in VMs
+ and such, as it allows us to boot up instantly with fully initialized entropy
+ pool even if RNG pass-thru is not available.
+
+* Support ProtectProc= or so, using: https://patchwork.kernel.org/cover/11310197/
+
* if /usr/bin/swapoff fails due to OOM, log a friendly explanatory message about it
* build short web pages out of each catalog entry, build them along with man
service : string
) -> (
record : object,
- incomplete : boolean
+ incomplete : bool
)
method GetGroupRecord(
service : string
) -> (
record : object,
- incomplete : boolean
+ incomplete : bool
)
method GetMemberships(
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*13*x360*:pvr*
KEYBOARD_KEY_d7=unknown
+# Spectre x360 13
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPSpectrex360Convertible13*:pvr*
+ KEYBOARD_KEY_82=f20 # Fn+F12; Microphone mute button, should be micmute
+
# Elitebook
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:pvr*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:pvr*
sensor:modalias:platform:cros-ec-accel:dmi:*:svnGoogle:pnCaroline*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
+# Dell Inspiron Chromebook 14 2-in-1
+sensor:modalias:platform:cros-ec-accel:dmi:*svnGoogle:pnVayne*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
+
#########################################
# GP-electronic
#########################################
<option>size=</option>.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>bitlk</option></term>
+
+ <listitem><para>Decrypt Bitlocker drive. Encryption parameters
+ are deduced by cryptsetup from Bitlocker header.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>_netdev</option></term>
<term><varname>rd.udev.event_timeout=</varname></term>
<term><varname>udev.timeout_signal=</varname></term>
<term><varname>rd.udev.timeout_signal=</varname></term>
-
+ <term><varname>udev.blockdev_read_only</varname></term>
+ <term><varname>rd.udev.blockdev_read_only</varname></term>
<term><varname>net.ifnames=</varname></term>
<term><varname>net.naming-scheme=</varname></term>
</varlistentry>
<varlistentry>
- <term><option>-c=</option></term>
+ <term><option>-c</option></term>
<term><option>--children-max=</option></term>
<listitem>
<para>Limit the number of events executed in parallel.</para>
</varlistentry>
<varlistentry>
- <term><option>-e=</option></term>
+ <term><option>-e</option></term>
<term><option>--exec-delay=</option></term>
<listitem>
<para>Delay the execution of <varname>RUN</varname>
</varlistentry>
<varlistentry>
- <term><option>-t=</option></term>
+ <term><option>-t</option></term>
<term><option>--event-timeout=</option></term>
<listitem>
<para>Set the number of seconds to wait for events to finish. After
</varlistentry>
<varlistentry>
- <term><option>-N=</option></term>
+ <term><option>-N</option></term>
<term><option>--resolve-names=</option></term>
<listitem>
<para>Specify when systemd-udevd should resolve names of users and groups.
<refsect1><title>Kernel command line</title>
<variablelist class='kernel-commandline-options'>
- <para>Parameters starting with "rd." will be read when
- <command>systemd-udevd</command> is used in an initrd.</para>
+ <para>Parameters prefixed with "rd." will be read when <command>systemd-udevd</command> is used in an
+ initrd, those without will be processed both in the initrd and on the host.</para>
<varlistentry>
<term><varname>udev.log_priority=</varname></term>
<term><varname>rd.udev.log_priority=</varname></term>
setting in the configuration file and the one on the program command line.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>udev.blockdev_read_only</varname></term>
+ <term><varname>rd.udev.blockdev_read_only</varname></term>
+ <listitem>
+ <para>If specified, mark all physical block devices read-only as they appear. Synthetic block
+ devices (such as loopback block devices or device mapper devices) are left as they are. This is
+ useful to guarantee that the contents of physical block devices remains unmodified during runtime,
+ for example to implement fully stateless systems, for testing or for recovery situations where
+ corrupted file systems shall not be corrupted further through accidental modification.</para>
+
+ <para>A block device may be marked writable again by issuing the <command>blockdev
+ --setrw</command> command, see <citerefentry
+ project='man-pages'><refentrytitle>blockdev</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ for details.</para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><varname>net.ifnames=</varname></term>
<listitem>
<para>Automount units may be used to implement on-demand mounting
as well as parallelized mounting of file systems.</para>
+
+ <para>Note that automount units are separate from the mount itself, so you
+ should not set <varname>After=</varname> or <varname>Requires=</varname>
+ for mount dependencies here. For example, you should not set
+ <varname>After=network-online.target</varname> or similar on network
+ filesystems. Doing so may result in an ordering cycle.</para>
</refsect1>
<refsect1>
When unset, the kernel's default will be used.
</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>IPv4AcceptLocal=</varname></term>
+ <listitem><para>Takes a boolean. Accept packets with local source addresses. In combination
+ with suitable routing, this can be used to direct packets between two local interfaces over
+ the wire and have them accepted properly. When unset, the kernel's default will be used.
+ </para></listitem>
+ </varlistentry>
<varlistentry>
<term><varname>IPv4ProxyARP=</varname></term>
<listitem><para>Takes a boolean. Configures proxy ARP for IPv4. Proxy ARP is the technique in which one host,
<varlistentry>
<term><varname>TimeoutStartSec=</varname></term>
- <listitem><para>Configures the time to wait for start-up. If a
- daemon service does not signal start-up completion within the
- configured time, the service will be considered failed and
- will be shut down again. Takes a unit-less value in seconds,
- or a time span value such as "5min 20s". Pass
- <literal>infinity</literal> to disable the timeout logic. Defaults to
- <varname>DefaultTimeoutStartSec=</varname> from the manager
- configuration file, except when
- <varname>Type=oneshot</varname> is used, in which case the
- timeout is disabled by default (see
+ <listitem><para>Configures the time to wait for start-up. If a daemon service does not signal start-up
+ completion within the configured time, the service will be considered failed and will be shut down again. The
+ precise action depends on the <varname>TimeoutStartFailureMode=</varname> option. Takes a unit-less value in
+ seconds, or a time span value such as "5min 20s". Pass <literal>infinity</literal> to disable the timeout logic.
+ Defaults to <varname>DefaultTimeoutStartSec=</varname> from the manager configuration file, except when
+ <varname>Type=oneshot</varname> is used, in which case the timeout is disabled by default (see
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para>
<listitem><para>This option serves two purposes. First, it configures the time to wait for each
<varname>ExecStop=</varname> command. If any of them times out, subsequent <varname>ExecStop=</varname> commands
are skipped and the service will be terminated by <constant>SIGTERM</constant>. If no <varname>ExecStop=</varname>
- commands are specified, the service gets the <constant>SIGTERM</constant> immediately. Second, it configures the time
+ commands are specified, the service gets the <constant>SIGTERM</constant> immediately. This default behavior
+ can be changed by the <varname>TimeoutStopFailureMode=</varname> option. Second, it configures the time
to wait for the service itself to stop. If it doesn't terminate in the specified time, it will be forcibly terminated
by <constant>SIGKILL</constant> (see <varname>KillMode=</varname> in
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>TimeoutStartFailureMode=</varname></term>
+ <term><varname>TimeoutStopFailureMode=</varname></term>
+
+ <listitem><para>These options configure the action that is taken in case a daemon service does not signal
+ start-up within its configured <varname>TimeoutStartSec=</varname>, respectively if it does not stop within
+ <varname>TimeoutStopSec=</varname>. Takes one of <option>terminate</option>, <option>abort</option> and
+ <option>kill</option>. Both options default to <option>terminate</option>.</para>
+
+ <para>If <option>terminate</option> is set the service will be gracefully terminated by sending the signal
+ specified in <varname>KillSignal=</varname> (defaults to <constant>SIGTERM</constant>, see
+ <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If the
+ service does not terminate the <varname>FinalKillSignal=</varname> is sent after
+ <varname>TimeoutStopSec=</varname>. If <option>abort</option> is set, <varname>WatchdogSignal=</varname> is sent
+ instead and <varname>TimeoutAbortSec=</varname> applies before sending <varname>FinalKillSignal=</varname>.
+ This setting may be used to analyze services that fail to start-up or shut-down intermittently.
+ By using <option>kill</option> the service is immediately terminated by sending
+ <varname>FinalKillSignal=</varname> without any further timeout. This setting can be used to expedite the
+ shutdown of failing services.
+ </para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>RuntimeMaxSec=</varname></term>
<para>Maximum number of seconds to wait for the event
queue to become empty. The default value is 120 seconds. A
value of 0 will check if the queue is empty and always
- return immediately.</para>
+ return immediately. A non-zero value will return an exit
+ code of 0 if queue became empty before timeout was reached,
+ non-zero otherwise.</para>
</listitem>
</varlistentry>
<varlistentry>
--- /dev/null
+# 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
return 0
fi
-
if [[ "$cur" = -* ]]; then
COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
return 0
/* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */
static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list);
static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-#define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug;
-
-#else /* !ENABLE_DEBUG_HASHMAP */
-#define HASHMAP_DEBUG_FIELDS
-#endif /* ENABLE_DEBUG_HASHMAP */
+#endif
enum HashmapType {
HASHMAP_TYPE_PLAIN,
bool from_pool:1; /* whether was allocated from mempool */
bool dirty:1; /* whether dirtied since last iterated_cache_get() */
bool cached:1; /* whether this hashmap is being cached */
- HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */
+
+#if ENABLE_DEBUG_HASHMAP
+ struct hashmap_debug_info debug;
+#endif
};
/* Specific hash types
unsigned n_direct_buckets;
};
-static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
+static _used_ const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
[HASHMAP_TYPE_PLAIN] = {
.head_size = sizeof(Hashmap),
.entry_size = sizeof(struct plain_hashmap_entry),
: hashmap_iterate_in_internal_order(h, i);
}
-bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
+bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
struct hashmap_base_entry *e;
void *data;
unsigned idx;
}
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) \
(idx != IDX_NIL); \
(idx) = hashmap_iterate_entry((h), &(i)))
-IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h) {
+IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h) {
IteratedCache *cache;
assert(h);
return h;
}
-Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+Hashmap *_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
}
-OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
}
-Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
}
return 0;
}
-int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
}
-int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
}
-int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
}
free(h);
}
-HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
+HashmapBase *_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
if (h) {
- internal_hashmap_clear(h, default_free_key, default_free_value);
+ _hashmap_clear(h, default_free_key, default_free_value);
hashmap_free_no_clear(h);
}
return NULL;
}
-void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
+void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
free_func_t free_key, free_value;
if (!h)
return;
* hash table, and only then call the destructor functions. If these destructors then try to unregister
* themselves from our hash table a second time, the entry is already gone. */
- while (internal_hashmap_size(h) > 0) {
+ while (_hashmap_size(h) > 0) {
void *k = NULL;
void *v;
- v = internal_hashmap_first_key_and_value(h, true, &k);
+ v = _hashmap_first_key_and_value(h, true, &k);
if (free_key)
free_key(k);
return 0;
}
-void *internal_hashmap_get(HashmapBase *h, const void *key) {
+void *_hashmap_get(HashmapBase *h, const void *key) {
struct hashmap_base_entry *e;
unsigned hash, idx;
return e->value;
}
-bool internal_hashmap_contains(HashmapBase *h, const void *key) {
+bool _hashmap_contains(HashmapBase *h, const void *key) {
unsigned hash;
if (!h)
return bucket_scan(h, hash, key) != IDX_NIL;
}
-void *internal_hashmap_remove(HashmapBase *h, const void *key) {
+void *_hashmap_remove(HashmapBase *h, const void *key) {
struct hashmap_base_entry *e;
unsigned hash, idx;
void *data;
return 0;
}
-void *internal_hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
+void *_hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
struct hashmap_base_entry *e;
unsigned hash, idx;
return hashmap_iterate_entry(h, &i);
}
-void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
+void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
struct hashmap_base_entry *e;
void *key, *data;
unsigned idx;
return data;
}
-unsigned internal_hashmap_size(HashmapBase *h) {
+unsigned _hashmap_size(HashmapBase *h) {
if (!h)
return 0;
return n_entries(h);
}
-unsigned internal_hashmap_buckets(HashmapBase *h) {
+unsigned _hashmap_buckets(HashmapBase *h) {
if (!h)
return 0;
return n_buckets(h);
}
-int internal_hashmap_merge(Hashmap *h, Hashmap *other) {
+int _hashmap_merge(Hashmap *h, Hashmap *other) {
Iterator i;
unsigned idx;
return 0;
}
-int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) {
+int _hashmap_reserve(HashmapBase *h, unsigned entries_add) {
int r;
assert(h);
* Returns: 0 on success.
* -ENOMEM on alloc failure, in which case no move has been done.
*/
-int internal_hashmap_move(HashmapBase *h, HashmapBase *other) {
+int _hashmap_move(HashmapBase *h, HashmapBase *other) {
struct swap_entries swap;
struct hashmap_base_entry *e, *n;
Iterator i;
return 0;
}
-int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
+int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
struct swap_entries swap;
unsigned h_hash, other_hash, idx;
struct hashmap_base_entry *e, *n;
return 0;
}
-HashmapBase *internal_hashmap_copy(HashmapBase *h) {
+HashmapBase *_hashmap_copy(HashmapBase *h) {
HashmapBase *copy;
int r;
}
if (r < 0) {
- internal_hashmap_free(copy, false, false);
+ _hashmap_free(copy, false, false);
return NULL;
}
return copy;
}
-char **internal_hashmap_get_strv(HashmapBase *h) {
+char **_hashmap_get_strv(HashmapBase *h) {
char **sv;
Iterator i;
unsigned idx, n;
* will be treated as empty hashmap for all read operations. That way it is not
* necessary to instantiate an object for each Hashmap use.
*
- * If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap),
+ * If ENABLE_DEBUG_HASHMAP is defined (by configuring with -Ddebug-extra=hashmap),
* the implementation will:
* - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
* - perform extra checks for invalid use of iterators
typedef void* (*hashmap_destroy_t)(void *p);
-/* The base type for all hashmap and set types. Many functions in the
- * implementation take (HashmapBase*) parameters and are run-time polymorphic,
- * though the API is not meant to be polymorphic (do not call functions
- * internal_*() directly). */
+/* The base type for all hashmap and set types. Many functions in the implementation take (HashmapBase*)
+ * parameters and are run-time polymorphic, though the API is not meant to be polymorphic (do not call
+ * underscore-prefixed functions directly). */
typedef struct HashmapBase HashmapBase;
/* Specific hashmap/set types */
# define HASHMAP_DEBUG_PASS_ARGS
#endif
-Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
-#define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
+Hashmap *_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define hashmap_new(ops) _hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
+#define ordered_hashmap_new(ops) _ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
#define hashmap_free_and_replace(a, b) \
({ \
0; \
})
-HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
+HashmapBase *_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
static inline Hashmap *hashmap_free(Hashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, NULL);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
}
static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, NULL);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
}
static inline Hashmap *hashmap_free_free(Hashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, free);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free);
}
static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, free);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free);
}
static inline Hashmap *hashmap_free_free_key(Hashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, NULL);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL);
}
static inline OrderedHashmap *ordered_hashmap_free_free_key(OrderedHashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, NULL);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL);
}
static inline Hashmap *hashmap_free_free_free(Hashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, free);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), free, free);
}
static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, free);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), free, free);
}
IteratedCache *iterated_cache_free(IteratedCache *cache);
int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries);
-HashmapBase *internal_hashmap_copy(HashmapBase *h);
+HashmapBase *_hashmap_copy(HashmapBase *h);
static inline Hashmap *hashmap_copy(Hashmap *h) {
- return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
+ return (Hashmap*) _hashmap_copy(HASHMAP_BASE(h));
}
static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
- return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
+ return (OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h));
}
-int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
-#define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+#define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
-IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h);
+IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h);
static inline IteratedCache *hashmap_iterated_cache_new(Hashmap *h) {
- return (IteratedCache*) internal_hashmap_iterated_cache_new(HASHMAP_BASE(h));
+ return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
}
static inline IteratedCache *ordered_hashmap_iterated_cache_new(OrderedHashmap *h) {
- return (IteratedCache*) internal_hashmap_iterated_cache_new(HASHMAP_BASE(h));
+ return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
}
int hashmap_put(Hashmap *h, const void *key, void *value);
return hashmap_replace(PLAIN_HASHMAP(h), key, value);
}
-void *internal_hashmap_get(HashmapBase *h, const void *key);
+void *_hashmap_get(HashmapBase *h, const void *key);
static inline void *hashmap_get(Hashmap *h, const void *key) {
- return internal_hashmap_get(HASHMAP_BASE(h), key);
+ return _hashmap_get(HASHMAP_BASE(h), key);
}
static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) {
- return internal_hashmap_get(HASHMAP_BASE(h), key);
+ return _hashmap_get(HASHMAP_BASE(h), key);
}
void *hashmap_get2(Hashmap *h, const void *key, void **rkey);
return hashmap_get2(PLAIN_HASHMAP(h), key, rkey);
}
-bool internal_hashmap_contains(HashmapBase *h, const void *key);
+bool _hashmap_contains(HashmapBase *h, const void *key);
static inline bool hashmap_contains(Hashmap *h, const void *key) {
- return internal_hashmap_contains(HASHMAP_BASE(h), key);
+ return _hashmap_contains(HASHMAP_BASE(h), key);
}
static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) {
- return internal_hashmap_contains(HASHMAP_BASE(h), key);
+ return _hashmap_contains(HASHMAP_BASE(h), key);
}
-void *internal_hashmap_remove(HashmapBase *h, const void *key);
+void *_hashmap_remove(HashmapBase *h, const void *key);
static inline void *hashmap_remove(Hashmap *h, const void *key) {
- return internal_hashmap_remove(HASHMAP_BASE(h), key);
+ return _hashmap_remove(HASHMAP_BASE(h), key);
}
static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) {
- return internal_hashmap_remove(HASHMAP_BASE(h), key);
+ return _hashmap_remove(HASHMAP_BASE(h), key);
}
void *hashmap_remove2(Hashmap *h, const void *key, void **rkey);
return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey);
}
-void *internal_hashmap_remove_value(HashmapBase *h, const void *key, void *value);
+void *_hashmap_remove_value(HashmapBase *h, const void *key, void *value);
static inline void *hashmap_remove_value(Hashmap *h, const void *key, void *value) {
- return internal_hashmap_remove_value(HASHMAP_BASE(h), key, value);
+ return _hashmap_remove_value(HASHMAP_BASE(h), key, value);
}
static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
/* Since merging data from a OrderedHashmap into a Hashmap or vice-versa
* should just work, allow this by having looser type-checking here. */
-int internal_hashmap_merge(Hashmap *h, Hashmap *other);
-#define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
+int _hashmap_merge(Hashmap *h, Hashmap *other);
+#define hashmap_merge(h, other) _hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
#define ordered_hashmap_merge(h, other) hashmap_merge(h, other)
-int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add);
+int _hashmap_reserve(HashmapBase *h, unsigned entries_add);
static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) {
- return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+ return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
}
static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) {
- return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+ return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
}
-int internal_hashmap_move(HashmapBase *h, HashmapBase *other);
+int _hashmap_move(HashmapBase *h, HashmapBase *other);
/* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */
static inline int hashmap_move(Hashmap *h, Hashmap *other) {
- return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
+ return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
}
static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) {
- return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
+ return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
}
-int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
+int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
- return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
+ return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
}
static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) {
- return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
+ return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
}
-unsigned internal_hashmap_size(HashmapBase *h) _pure_;
+unsigned _hashmap_size(HashmapBase *h) _pure_;
static inline unsigned hashmap_size(Hashmap *h) {
- return internal_hashmap_size(HASHMAP_BASE(h));
+ return _hashmap_size(HASHMAP_BASE(h));
}
static inline unsigned ordered_hashmap_size(OrderedHashmap *h) {
- return internal_hashmap_size(HASHMAP_BASE(h));
+ return _hashmap_size(HASHMAP_BASE(h));
}
static inline bool hashmap_isempty(Hashmap *h) {
return ordered_hashmap_size(h) == 0;
}
-unsigned internal_hashmap_buckets(HashmapBase *h) _pure_;
+unsigned _hashmap_buckets(HashmapBase *h) _pure_;
static inline unsigned hashmap_buckets(Hashmap *h) {
- return internal_hashmap_buckets(HASHMAP_BASE(h));
+ return _hashmap_buckets(HASHMAP_BASE(h));
}
static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) {
- return internal_hashmap_buckets(HASHMAP_BASE(h));
+ return _hashmap_buckets(HASHMAP_BASE(h));
}
-bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key);
+bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key);
static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) {
- return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
+ return _hashmap_iterate(HASHMAP_BASE(h), i, value, key);
}
static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) {
- return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
+ return _hashmap_iterate(HASHMAP_BASE(h), i, value, key);
}
-void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
+void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
static inline void hashmap_clear(Hashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
+ _hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
}
static inline void ordered_hashmap_clear(OrderedHashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
+ _hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
}
static inline void hashmap_clear_free(Hashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), NULL, free);
+ _hashmap_clear(HASHMAP_BASE(h), NULL, free);
}
static inline void ordered_hashmap_clear_free(OrderedHashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), NULL, free);
+ _hashmap_clear(HASHMAP_BASE(h), NULL, free);
}
static inline void hashmap_clear_free_key(Hashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), free, NULL);
+ _hashmap_clear(HASHMAP_BASE(h), free, NULL);
}
static inline void ordered_hashmap_clear_free_key(OrderedHashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), free, NULL);
+ _hashmap_clear(HASHMAP_BASE(h), free, NULL);
}
static inline void hashmap_clear_free_free(Hashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), free, free);
+ _hashmap_clear(HASHMAP_BASE(h), free, free);
}
static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), free, free);
+ _hashmap_clear(HASHMAP_BASE(h), free, free);
}
/*
* the first entry is O(1).
*/
-void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key);
+void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key);
static inline void *hashmap_steal_first_key_and_value(Hashmap *h, void **ret) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
}
static inline void *ordered_hashmap_steal_first_key_and_value(OrderedHashmap *h, void **ret) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
}
static inline void *hashmap_first_key_and_value(Hashmap *h, void **ret) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
}
static inline void *ordered_hashmap_first_key_and_value(OrderedHashmap *h, void **ret) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
}
static inline void *hashmap_steal_first(Hashmap *h) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
}
static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
}
static inline void *hashmap_first(Hashmap *h) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
}
static inline void *ordered_hashmap_first(OrderedHashmap *h) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
}
-static inline void *internal_hashmap_first_key(HashmapBase *h, bool remove) {
+static inline void *_hashmap_first_key(HashmapBase *h, bool remove) {
void *key = NULL;
- (void) internal_hashmap_first_key_and_value(HASHMAP_BASE(h), remove, &key);
+ (void) _hashmap_first_key_and_value(HASHMAP_BASE(h), remove, &key);
return key;
}
static inline void *hashmap_steal_first_key(Hashmap *h) {
- return internal_hashmap_first_key(HASHMAP_BASE(h), true);
+ return _hashmap_first_key(HASHMAP_BASE(h), true);
}
static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) {
- return internal_hashmap_first_key(HASHMAP_BASE(h), true);
+ return _hashmap_first_key(HASHMAP_BASE(h), true);
}
static inline void *hashmap_first_key(Hashmap *h) {
- return internal_hashmap_first_key(HASHMAP_BASE(h), false);
+ return _hashmap_first_key(HASHMAP_BASE(h), false);
}
static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
- return internal_hashmap_first_key(HASHMAP_BASE(h), false);
+ return _hashmap_first_key(HASHMAP_BASE(h), false);
}
#define hashmap_clear_with_destructor(_s, _f) \
/* no hashmap_next */
void *ordered_hashmap_next(OrderedHashmap *h, const void *key);
-char **internal_hashmap_get_strv(HashmapBase *h);
+char **_hashmap_get_strv(HashmapBase *h);
static inline char **hashmap_get_strv(Hashmap *h) {
- return internal_hashmap_get_strv(HASHMAP_BASE(h));
+ return _hashmap_get_strv(HASHMAP_BASE(h));
}
static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
- return internal_hashmap_get_strv(HASHMAP_BASE(h));
+ return _hashmap_get_strv(HASHMAP_BASE(h));
}
/*
"tracefs");
}
+bool fstype_is_blockdev_backed(const char *fstype) {
+ const char *x;
+
+ x = startswith(fstype, "fuse.");
+ if (x)
+ fstype = x;
+
+ return !streq(fstype, "9p") && !fstype_is_network(fstype) && !fstype_is_api_vfs(fstype);
+}
+
bool fstype_is_ro(const char *fstype) {
/* All Linux file systems that are necessarily read-only */
return STR_IN_SET(fstype,
bool fstype_is_network(const char *fstype);
bool fstype_is_api_vfs(const char *fstype);
+bool fstype_is_blockdev_backed(const char *fstype);
bool fstype_is_ro(const char *fsype);
bool fstype_can_discard(const char *fstype);
bool fstype_can_uid_gid(const char *fstype);
}
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);
0; \
})
-Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
+Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define set_new(ops) _set_new(ops HASHMAP_DEBUG_SRC_ARGS)
static inline Set *set_free(Set *s) {
- return (Set*) internal_hashmap_free(HASHMAP_BASE(s), NULL, NULL);
+ return (Set*) _hashmap_free(HASHMAP_BASE(s), NULL, NULL);
}
static inline Set *set_free_free(Set *s) {
- return (Set*) internal_hashmap_free(HASHMAP_BASE(s), free, NULL);
+ return (Set*) _hashmap_free(HASHMAP_BASE(s), free, NULL);
}
/* no set_free_free_free */
static inline Set *set_copy(Set *s) {
- return (Set*) internal_hashmap_copy(HASHMAP_BASE(s));
+ return (Set*) _hashmap_copy(HASHMAP_BASE(s));
}
-int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define set_ensure_allocated(h, ops) _set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
int set_put(Set *s, const void *key);
/* no set_update */
/* no set_replace */
static inline void *set_get(const Set *s, void *key) {
- return internal_hashmap_get(HASHMAP_BASE((Set *) s), key);
+ return _hashmap_get(HASHMAP_BASE((Set *) s), key);
}
/* no set_get2 */
static inline bool set_contains(const Set *s, const void *key) {
- return internal_hashmap_contains(HASHMAP_BASE((Set *) s), key);
+ return _hashmap_contains(HASHMAP_BASE((Set *) s), key);
}
static inline void *set_remove(Set *s, const void *key) {
- return internal_hashmap_remove(HASHMAP_BASE(s), key);
+ return _hashmap_remove(HASHMAP_BASE(s), key);
}
/* no set_remove2 */
int set_merge(Set *s, Set *other);
static inline int set_reserve(Set *h, unsigned entries_add) {
- return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+ return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
}
static inline int set_move(Set *s, Set *other) {
- return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other));
+ return _hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other));
}
static inline int set_move_one(Set *s, Set *other, const void *key) {
- return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key);
+ return _hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key);
}
static inline unsigned set_size(const Set *s) {
- return internal_hashmap_size(HASHMAP_BASE((Set *) s));
+ return _hashmap_size(HASHMAP_BASE((Set *) s));
}
static inline bool set_isempty(const Set *s) {
}
static inline unsigned set_buckets(const Set *s) {
- return internal_hashmap_buckets(HASHMAP_BASE((Set *) s));
+ return _hashmap_buckets(HASHMAP_BASE((Set *) s));
}
bool set_iterate(const Set *s, Iterator *i, void **value);
static inline void set_clear(Set *s) {
- internal_hashmap_clear(HASHMAP_BASE(s), NULL, NULL);
+ _hashmap_clear(HASHMAP_BASE(s), NULL, NULL);
}
static inline void set_clear_free(Set *s) {
- internal_hashmap_clear(HASHMAP_BASE(s), free, NULL);
+ _hashmap_clear(HASHMAP_BASE(s), free, NULL);
}
/* no set_clear_free_free */
static inline void *set_steal_first(Set *s) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(s), true, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(s), true, NULL);
}
#define set_clear_with_destructor(_s, _f) \
/* no set_first_key */
static inline void *set_first(const Set *s) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE((Set *) s), false, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE((Set *) s), false, NULL);
}
/* no set_next */
static inline char **set_get_strv(Set *s) {
- return internal_hashmap_get_strv(HASHMAP_BASE(s));
+ return _hashmap_get_strv(HASHMAP_BASE(s));
}
int set_consume(Set *s, void *value);
return 1;
}
-int string_strv_hashmap_put(Hashmap **h, const char *key, const char *value) {
+int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
int r;
- r = hashmap_ensure_allocated(h, &string_strv_hash_ops);
+ r = _hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
return string_strv_hashmap_put_internal(*h, key, value);
}
-int string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value) {
+int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
int r;
- r = ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops);
+ r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
})
extern const struct hash_ops string_strv_hash_ops;
-int string_strv_hashmap_put(Hashmap **h, const char *key, const char *value);
-int string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value);
+int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS);
+int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS);
+#define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS)
+#define string_strv_ordered_hashmap_put(h, k, v) _string_strv_ordered_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS)
[SERVICE_STOP_SIGTERM] = "stop-sigterm",
[SERVICE_STOP_SIGKILL] = "stop-sigkill",
[SERVICE_STOP_POST] = "stop-post",
+ [SERVICE_FINAL_WATCHDOG] = "final-watchdog",
[SERVICE_FINAL_SIGTERM] = "final-sigterm",
[SERVICE_FINAL_SIGKILL] = "final-sigkill",
[SERVICE_FAILED] = "failed",
SERVICE_STOP_SIGTERM,
SERVICE_STOP_SIGKILL,
SERVICE_STOP_POST,
+ SERVICE_FINAL_WATCHDOG, /* In case the STOP_POST executable needs to be aborted. */
SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */
SERVICE_FINAL_SIGKILL,
SERVICE_FAILED,
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
static BUS_DEFINE_PROPERTY_GET(property_get_timeout_abort_usec, "t", Service, service_timeout_abort_usec);
static BUS_DEFINE_PROPERTY_GET(property_get_watchdog_usec, "t", Service, service_get_watchdog_usec);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode);
static int property_get_exit_status_set(
sd_bus *bus,
SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimeoutAbortUSec", "t", property_get_timeout_abort_usec, 0, 0),
+ SD_BUS_PROPERTY("TimeoutStartFailureMode", "s", property_get_timeout_failure_mode, offsetof(Service, timeout_start_failure_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TimeoutStopFailureMode", "s", property_get_timeout_failure_mode, offsetof(Service, timeout_stop_failure_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WatchdogUSec", "t", property_get_watchdog_usec, 0, 0),
BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart, ServiceRestart, service_restart_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(bus_name, sd_bus_service_name_is_valid);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(timeout_failure_mode, ServiceTimeoutFailureMode, service_timeout_failure_mode_from_string);
static int bus_service_set_transient_property(
Service *s,
return r;
}
+ if (streq(name, "TimeoutStartFailureMode"))
+ return bus_set_transient_timeout_failure_mode(u, name, &s->timeout_start_failure_mode, message, flags, error);
+
+ if (streq(name, "TimeoutStopFailureMode"))
+ return bus_set_transient_timeout_failure_mode(u, name, &s->timeout_stop_failure_mode, message, flags, error);
+
if (streq(name, "RuntimeMaxUSec"))
return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error);
Service.TimeoutStartSec, config_parse_service_timeout, 0, 0
Service.TimeoutStopSec, config_parse_sec_fix_0, 0, offsetof(Service, timeout_stop_usec)
Service.TimeoutAbortSec, config_parse_service_timeout_abort, 0, 0
+Service.TimeoutStartFailureMode, config_parse_service_timeout_failure_mode, 0, offsetof(Service, timeout_start_failure_mode)
+Service.TimeoutStopFailureMode, config_parse_service_timeout_failure_mode, 0, offsetof(Service, timeout_stop_failure_mode)
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
m4_dnl The following five only exist for compatibility, they moved into Unit, see above
DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_service_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode, "Failed to parse timeout failure mode");
DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
DEFINE_CONFIG_PARSE_ENUM(config_parse_oom_policy, oom_policy, OOMPolicy, "Failed to parse OOM policy");
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value");
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
{ config_parse_service_type, "SERVICETYPE" },
{ config_parse_service_restart, "SERVICERESTART" },
+ { config_parse_service_timeout_failure_mode, "TIMEOUTMODE" },
{ config_parse_kill_mode, "KILLMODE" },
{ config_parse_signal, "SIGNAL" },
{ config_parse_socket_listen, "SOCKET [...]" },
CONFIG_PARSER_PROTOTYPE(config_parse_exec);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_abort);
+CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_failure_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_service_type);
CONFIG_PARSER_PROTOTYPE(config_parse_service_restart);
CONFIG_PARSER_PROTOTYPE(config_parse_socket_bindtodevice);
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
[SERVICE_STOP_POST] = UNIT_DEACTIVATING,
+ [SERVICE_FINAL_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
[SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
[SERVICE_FAILED] = UNIT_FAILED,
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
[SERVICE_STOP_POST] = UNIT_DEACTIVATING,
+ [SERVICE_FINAL_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
[SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
[SERVICE_FAILED] = UNIT_FAILED,
fprintf(f,
"%sRestartSec: %s\n"
"%sTimeoutStartSec: %s\n"
- "%sTimeoutStopSec: %s\n",
+ "%sTimeoutStopSec: %s\n"
+ "%sTimeoutStartFailureMode: %s\n"
+ "%sTimeoutStopFailureMode: %s\n",
prefix, format_timespan(buf_restart, sizeof(buf_restart), s->restart_usec, USEC_PER_SEC),
prefix, format_timespan(buf_start, sizeof(buf_start), s->timeout_start_usec, USEC_PER_SEC),
- prefix, format_timespan(buf_stop, sizeof(buf_stop), s->timeout_stop_usec, USEC_PER_SEC));
+ prefix, format_timespan(buf_stop, sizeof(buf_stop), s->timeout_stop_usec, USEC_PER_SEC),
+ prefix, service_timeout_failure_mode_to_string(s->timeout_start_failure_mode),
+ prefix, service_timeout_failure_mode_to_string(s->timeout_stop_failure_mode));
if (s->timeout_abort_set)
fprintf(f,
SERVICE_RUNNING,
SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+ SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_AUTO_RESTART,
SERVICE_CLEANING))
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
+ SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
service_unwatch_main_pid(s);
s->main_command = NULL;
}
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+ SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) {
service_unwatch_control_pid(s);
s->control_command = NULL;
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
+ SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
!(state == SERVICE_DEAD && UNIT(s)->job))
service_close_socket_fd(s);
return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_stop_usec);
case SERVICE_STOP_WATCHDOG:
+ case SERVICE_FINAL_WATCHDOG:
return usec_add(UNIT(s)->state_change_timestamp.monotonic, service_timeout_abort_usec(s));
case SERVICE_AUTO_RESTART:
SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
+ SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
r = unit_watch_pid(UNIT(s), s->main_pid, false);
if (r < 0)
return r;
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+ SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) {
r = unit_watch_pid(UNIT(s), s->control_pid, false);
if (r < 0)
switch (state) {
case SERVICE_STOP_WATCHDOG:
+ case SERVICE_FINAL_WATCHDOG:
return KILL_WATCHDOG;
case SERVICE_STOP_SIGTERM:
}
static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) {
- int r;
+ int kill_operation, r;
assert(s);
* died now */
(void) unit_enqueue_rewatch_pids(UNIT(s));
+ kill_operation = state_to_kill_operation(s, state);
r = unit_kill_context(
UNIT(s),
&s->kill_context,
- state_to_kill_operation(s, state),
+ kill_operation,
s->main_pid,
s->control_pid,
s->main_pid_alien);
if (r > 0) {
r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC),
- state == SERVICE_STOP_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec));
+ kill_operation == KILL_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec));
if (r < 0)
goto fail;
service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_SUCCESS);
else if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
service_enter_stop_post(s, SERVICE_SUCCESS);
- else if (state == SERVICE_FINAL_SIGTERM && s->kill_context.send_sigkill)
+ else if (IN_SET(state, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM) && s->kill_context.send_sigkill)
service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
else
service_enter_dead(s, SERVICE_SUCCESS, true);
* please! */
if (IN_SET(s->state,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_CLEANING))
+ SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_CLEANING))
return -EAGAIN;
/* Already on it! */
/* Already on it */
if (IN_SET(s->state,
SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
+ SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
return 0;
/* A restart will be scheduled or is in progress. */
break;
case SERVICE_STOP_POST:
+ case SERVICE_FINAL_WATCHDOG:
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
if (main_pid_good(s) <= 0 && control_pid_good(s) <= 0)
break;
+ case SERVICE_FINAL_WATCHDOG:
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
break;
+ case SERVICE_FINAL_WATCHDOG:
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
if (main_pid_good(s) <= 0)
case SERVICE_CONDITION:
case SERVICE_START_PRE:
case SERVICE_START:
- log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", service_state_to_string(s->state));
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
- break;
-
case SERVICE_START_POST:
- log_unit_warning(UNIT(s), "Start-post operation timed out. Stopping.");
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+ switch (s->timeout_start_failure_mode) {
+
+ case SERVICE_TIMEOUT_TERMINATE:
+ log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", service_state_to_string(s->state));
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+ break;
+
+ case SERVICE_TIMEOUT_ABORT:
+ log_unit_warning(UNIT(s), "%s operation timed out. Aborting.", service_state_to_string(s->state));
+ service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+ break;
+
+ case SERVICE_TIMEOUT_KILL:
+ if (s->kill_context.send_sigkill) {
+ log_unit_warning(UNIT(s), "%s operation timed out. Killing.", service_state_to_string(s->state));
+ service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+ } else {
+ log_unit_warning(UNIT(s), "%s operation timed out. Skipping SIGKILL.", service_state_to_string(s->state));
+ service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+ }
+ break;
+
+ default:
+ assert_not_reached("unknown timeout mode");
+ }
break;
case SERVICE_RUNNING:
break;
case SERVICE_STOP:
- log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+ switch (s->timeout_stop_failure_mode) {
+
+ case SERVICE_TIMEOUT_TERMINATE:
+ log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+ break;
+
+ case SERVICE_TIMEOUT_ABORT:
+ log_unit_warning(UNIT(s), "Stopping timed out. Aborting.");
+ service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+ break;
+
+ case SERVICE_TIMEOUT_KILL:
+ if (s->kill_context.send_sigkill) {
+ log_unit_warning(UNIT(s), "Stopping timed out. Killing.");
+ service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+ } else {
+ log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL.");
+ service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+ }
+ break;
+
+ default:
+ assert_not_reached("unknown timeout mode");
+ }
break;
case SERVICE_STOP_WATCHDOG:
- log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Terminating.");
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+ if (s->kill_context.send_sigkill) {
+ log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Killing.");
+ service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+ } else {
+ log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Skipping SIGKILL.");
+ service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+ }
break;
case SERVICE_STOP_SIGTERM:
- if (s->kill_context.send_sigkill) {
+ if (s->timeout_stop_failure_mode == SERVICE_TIMEOUT_ABORT) {
+ log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Aborting.");
+ service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+ } else if (s->kill_context.send_sigkill) {
log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Killing.");
service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
} else {
break;
case SERVICE_STOP_POST:
- log_unit_warning(UNIT(s), "State 'stop-post' timed out. Terminating.");
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+ switch (s->timeout_stop_failure_mode) {
+
+ case SERVICE_TIMEOUT_TERMINATE:
+ log_unit_warning(UNIT(s), "State 'stop-post' timed out. Terminating.");
+ service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+ break;
+
+ case SERVICE_TIMEOUT_ABORT:
+ log_unit_warning(UNIT(s), "State 'stop-post' timed out. Aborting.");
+ service_enter_signal(s, SERVICE_FINAL_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+ break;
+
+ case SERVICE_TIMEOUT_KILL:
+ if (s->kill_context.send_sigkill) {
+ log_unit_warning(UNIT(s), "State 'stop-post' timed out. Killing.");
+ service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+ } else {
+ log_unit_warning(UNIT(s), "State 'stop-post' timed out. Skipping SIGKILL. Entering failed mode.");
+ service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
+ }
+ break;
+
+ default:
+ assert_not_reached("unknown timeout mode");
+ }
break;
- case SERVICE_FINAL_SIGTERM:
+ case SERVICE_FINAL_WATCHDOG:
if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Killing.");
+ log_unit_warning(UNIT(s), "State 'final-watchdog' timed out. Killing.");
service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Skipping SIGKILL. Entering failed mode.");
+ log_unit_warning(UNIT(s), "State 'final-watchdog' timed out. Skipping SIGKILL. Entering failed mode.");
+ service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
+ }
+ break;
+
+ case SERVICE_FINAL_SIGTERM:
+ if (s->timeout_stop_failure_mode == SERVICE_TIMEOUT_ABORT) {
+ log_unit_warning(UNIT(s), "State 'final-sigterm' timed out. Aborting.");
+ service_enter_signal(s, SERVICE_FINAL_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+ } else if (s->kill_context.send_sigkill) {
+ log_unit_warning(UNIT(s), "State 'final-sigterm' timed out. Killing.");
+ service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+ } else {
+ log_unit_warning(UNIT(s), "State 'final-sigterm' timed out. Skipping SIGKILL. Entering failed mode.");
service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
}
SERVICE_STOP_SIGTERM,
SERVICE_STOP_SIGKILL,
SERVICE_STOP_POST,
+ SERVICE_FINAL_WATCHDOG,
SERVICE_FINAL_SIGTERM,
SERVICE_FINAL_SIGKILL);
}
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
+static const char* const service_timeout_failure_mode_table[_SERVICE_TIMEOUT_FAILURE_MODE_MAX] = {
+ [SERVICE_TIMEOUT_TERMINATE] = "terminate",
+ [SERVICE_TIMEOUT_ABORT] = "abort",
+ [SERVICE_TIMEOUT_KILL] = "kill",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_timeout_failure_mode, ServiceTimeoutFailureMode);
+
const UnitVTable service_vtable = {
.object_size = sizeof(Service),
.exec_context_offset = offsetof(Service, exec_context),
_SERVICE_RESULT_INVALID = -1
} ServiceResult;
+typedef enum ServiceTimeoutFailureMode {
+ SERVICE_TIMEOUT_TERMINATE,
+ SERVICE_TIMEOUT_ABORT,
+ SERVICE_TIMEOUT_KILL,
+ _SERVICE_TIMEOUT_FAILURE_MODE_MAX,
+ _SERVICE_TIMEOUT_FAILURE_MODE_INVALID = -1
+} ServiceTimeoutFailureMode;
+
struct ServiceFDStore {
Service *service;
usec_t timeout_abort_usec;
bool timeout_abort_set;
usec_t runtime_max_usec;
+ ServiceTimeoutFailureMode timeout_start_failure_mode;
+ ServiceTimeoutFailureMode timeout_stop_failure_mode;
dual_timestamp watchdog_timestamp;
usec_t watchdog_usec; /* the requested watchdog timeout in the unit file */
const char* service_result_to_string(ServiceResult i) _const_;
ServiceResult service_result_from_string(const char *s) _pure_;
+const char* service_timeout_failure_mode_to_string(ServiceTimeoutFailureMode i) _const_;
+ServiceTimeoutFailureMode service_timeout_failure_mode_from_string(const char *s) _pure_;
+
DEFINE_CAST(SERVICE, Service);
#define STATUS_TEXT_MAX (16U*1024U)
if (r < 0)
return r;
- return 0;
+ return 1;
}
static int slice_freeze(Unit *s) {
#define CRYPT_SECTOR_SIZE 512
#define CRYPT_MAX_SECTOR_SIZE 4096
-static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT or CRYPT_PLAIN */
+static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT, CRYPT_BITLK or CRYPT_PLAIN */
static char *arg_cipher = NULL;
static unsigned arg_key_size = 0;
static unsigned arg_sector_size = CRYPT_SECTOR_SIZE;
arg_submit_from_crypt_cpus = true;
else if (streq(option, "luks"))
arg_type = ANY_LUKS;
+/* since cryptsetup 2.3.0 (Feb 2020) */
+#ifdef CRYPT_BITLK
+ else if (streq(option, "bitlk"))
+ arg_type = CRYPT_BITLK;
+#endif
else if (streq(option, "tcrypt"))
arg_type = CRYPT_TCRYPT;
else if (STR_IN_SET(option, "tcrypt-hidden", "tcrypthidden")) {
return 0;
}
-static int attach_luks_or_plain(
+static int attach_luks_or_plain_or_bitlk(
struct crypt_device *cd,
const char *name,
const char *key_file,
}
}
+/* since cryptsetup 2.3.0 (Feb 2020) */
+#ifdef CRYPT_BITLK
+ if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_BITLK)) {
+ r = crypt_load(cd, CRYPT_BITLK, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load Bitlocker superblock on device %s: %m", crypt_get_device_name(cd));
+ }
+#endif
+
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
_cleanup_strv_free_erase_ char **passwords = NULL;
if (streq_ptr(arg_type, CRYPT_TCRYPT))
r = attach_tcrypt(cd, argv[2], key_file, key_data, key_data_size, passwords, flags);
else
- r = attach_luks_or_plain(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until);
+ r = attach_luks_or_plain_or_bitlk(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until);
if (r >= 0)
break;
if (r != -EAGAIN)
usage()
{
echo "Usage:"
- echo " $0 add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]"
- echo " $0 remove KERNEL-VERSION"
+ echo " $0 [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]"
+ echo " $0 [OPTIONS...] remove KERNEL-VERSION"
+ echo "Options:"
+ echo " -h,--help Print this help"
+ echo " -v,--verbose Increase verbosity"
}
dropindirs_sort()
return network_link_get_string(ifindex, "ADDRESS_STATE", state);
}
+_public_ int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id) {
+ return network_link_get_string(ifindex, "DHCP4_CLIENT_ID", client_id);
+}
+
_public_ int sd_network_link_get_required_for_online(int ifindex) {
_cleanup_free_ char *s = NULL;
int r;
ENV{DRIVER}=="", IMPORT{cmdline}="nomodeset", TAG+="seat", TAG+="master-of-seat"
SUBSYSTEM=="drm", KERNEL=="card[0-9]*", TAG+="seat", TAG+="master-of-seat"
+
+# Allow individual USB ports to be assigned to a seat
+SUBSYSTEM=="usb", ATTR{bDeviceClass}=="00", TAG+="seat"
+
+# Allow USB hubs (and all downstream ports) to be assigned to a seat
SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat"
# 'Plugable' USB hub, sound, network, graphics adapter
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"At most two arguments required.");
- if (arg_mount_type && (fstype_is_api_vfs(arg_mount_type) || fstype_is_network(arg_mount_type))) {
+ if (arg_mount_type && !fstype_is_blockdev_backed(arg_mount_type)) {
arg_mount_what = strdup(argv[optind]);
if (!arg_mount_what)
return log_oom();
if (arg_action == ACTION_UMOUNT)
return action_umount(bus, argc, argv);
- if ((!arg_mount_type || !fstype_is_network(arg_mount_type))
+ if ((!arg_mount_type || fstype_is_blockdev_backed(arg_mount_type))
&& !path_is_normalized(arg_mount_what)) {
log_error("Path contains non-normalized components: %s", arg_mount_what);
return -EINVAL;
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL,
**pop3_server = NULL, **smtp_server = NULL, **lpr_server = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
- _cleanup_free_ char *t = NULL, *network = NULL;
+ _cleanup_free_ char *t = NULL, *network = NULL, *client_id = NULL;
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
const char *on_color_operational, *off_color_operational,
*on_color_setup, *off_color_setup;
return table_log_add_error(r);
}
+ r = sd_network_link_get_dhcp4_client_id_string(info->ifindex, &client_id);
+ if (r >= 0) {
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "DHCP4 Client ID:",
+ TABLE_STRING, client_id);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
r = dump_lldp_neighbors(table, "Connected To:", info->ifindex);
if (r < 0)
return r;
return 0;
}
+static int link_set_ipv4_accept_local(Link *link) {
+ int r;
+
+ if (link->flags & IFF_LOOPBACK)
+ return 0;
+
+ if (link->network->ipv4_accept_local < 0)
+ return 0;
+
+ r = sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface: %m");
+
+ return 0;
+}
+
static bool link_is_static_address_configured(Link *link, Address *address) {
Address *net_address;
if (r < 0)
return r;
+ r = link_set_ipv4_accept_local(link);
+ if (r < 0)
+ return r;
+
r = link_set_flags(link);
if (r < 0)
return r;
if (link->dhcp_lease) {
struct in_addr address;
const char *tz = NULL;
+ size_t client_id_len;
+ const void *client_id;
assert(link->network);
fputc('\n', f);
}
+ r = sd_dhcp_lease_get_client_id(link->dhcp_lease, &client_id, &client_id_len);
+ if (r >= 0) {
+ _cleanup_free_ char *id = NULL;
+
+ r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id);
+ if (r >= 0)
+ fprintf(f, "DHCP4_CLIENT_ID=%s\n", id);
+ }
+
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
if (r < 0)
goto fail;
Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit)
Network.IPv6ProxyNDP, config_parse_tristate, 0, offsetof(Network, ipv6_proxy_ndp)
Network.IPv6MTUBytes, config_parse_mtu, AF_INET6, offsetof(Network, ipv6_mtu)
+Network.IPv4AcceptLocal, config_parse_tristate, 0, offsetof(Network, ipv4_accept_local)
Network.ActiveSlave, config_parse_bool, 0, offsetof(Network, active_slave)
Network.PrimarySlave, config_parse_bool, 0, offsetof(Network, primary_slave)
Network.IPv4ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp)
/* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
.link_local = _ADDRESS_FAMILY_INVALID,
+ .ipv4_accept_local = -1,
+
.ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
.ipv6_accept_ra = -1,
.ipv6_dad_transmits = -1,
AddressFamily ip_forward;
bool ip_masquerade;
+ int ipv4_accept_local;
int ipv6_accept_ra;
int ipv6_dad_transmits;
"NotifyAccess",
"USBFunctionDescriptors",
"USBFunctionStrings",
- "OOMPolicy"))
+ "OOMPolicy",
+ "TimeoutStartFailureMode",
+ "TimeoutStopFailureMode"))
return bus_append_string(m, field, eq);
if (STR_IN_SET(field, "PermissionsStartOnly",
/* Get the timezone that was learnt on a specific link. */
int sd_network_link_get_timezone(int ifindex, char **timezone);
+/* Get DHCPv4 client id for a given link. */
+int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id);
+
/* Monitor object */
typedef struct sd_network_monitor sd_network_monitor;
static usec_t arg_exec_delay_usec = 0;
static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
static int arg_timeout_signal = SIGKILL;
+static bool arg_blockdev_read_only = false;
typedef struct Manager {
sd_event *event;
return 1;
}
+static int worker_mark_block_device_read_only(sd_device *dev) {
+ _cleanup_close_ int fd = -1;
+ const char *val;
+ int state = 1, r;
+
+ assert(dev);
+
+ if (!arg_blockdev_read_only)
+ return 0;
+
+ /* Do this only once, when the block device is new. If the device is later retriggered let's not
+ * toggle the bit again, so that people can boot up with full read-only mode and then unset the bit
+ * for specific devices only. */
+ if (!device_for_action(dev, DEVICE_ACTION_ADD))
+ return 0;
+
+ r = sd_device_get_subsystem(dev, &val);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to get subsystem: %m");
+
+ if (!streq(val, "block"))
+ return 0;
+
+ r = sd_device_get_sysname(dev, &val);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to get sysname: %m");
+
+ /* Exclude synthetic devices for now, this is supposed to be a safety feature to avoid modification
+ * of physical devices, and what sits on top of those doesn't really matter if we don't allow the
+ * underlying block devices to recieve changes. */
+ if (STARTSWITH_SET(val, "dm-", "md", "drbd", "loop", "nbd", "zram"))
+ return 0;
+
+ r = sd_device_get_devname(dev, &val);
+ if (r == -ENOENT)
+ return 0;
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to get devname: %m");
+
+ fd = open(val, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
+ if (fd < 0)
+ return log_device_debug_errno(dev, errno, "Failed to open '%s', ignoring: %m", val);
+
+ if (ioctl(fd, BLKROSET, &state) < 0)
+ return log_device_warning_errno(dev, errno, "Failed to mark block device '%s' read-only: %m", val);
+
+ log_device_info(dev, "Successfully marked block device '%s' read-only.", val);
+ return 0;
+}
+
static int worker_process_device(Manager *manager, sd_device *dev) {
_cleanup_(udev_event_freep) UdevEvent *udev_event = NULL;
_cleanup_close_ int fd_lock = -1;
if (r < 0)
return r;
+ (void) worker_mark_block_device_read_only(dev);
+
/* apply rules, create node, symlinks */
r = udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_timeout_signal, manager->properties, manager->rules);
if (r < 0)
* udev.children_max=<number of workers> events are fully serialized if set to 1
* udev.exec_delay=<number of seconds> delay execution of every executed program
* udev.event_timeout=<number of seconds> seconds to wait before terminating an event
+ * udev.blockdev_read_only<=bool> mark all block devices read-only when they appear
*/
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
- int r = 0;
+ int r;
assert(key);
- if (!value)
- return 0;
-
if (proc_cmdline_key_streq(key, "udev.log_priority")) {
if (proc_cmdline_value_missing(key, value))
r = parse_sec(value, &arg_exec_delay_usec);
} else if (proc_cmdline_key_streq(key, "udev.timeout_signal")) {
+
if (proc_cmdline_value_missing(key, value))
return 0;
r = signal_from_string(value);
if (r > 0)
arg_timeout_signal = r;
- } else if (startswith(key, "udev."))
- log_warning("Unknown udev kernel command line option \"%s\", ignoring", key);
+
+ } else if (proc_cmdline_key_streq(key, "udev.blockdev_read_only")) {
+
+ if (!value)
+ arg_blockdev_read_only = true;
+ else {
+ r = parse_boolean(value);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse udev.blockdev-read-only argument, ignoring: %s", value);
+ else
+ arg_blockdev_read_only = r;
+ }
+
+ if (arg_blockdev_read_only)
+ log_notice("All physical block devices will be marked read-only.");
+
+ return 0;
+
+ } else {
+ if (startswith(key, "udev."))
+ log_warning("Unknown udev kernel command line option \"%s\", ignoring.", key);
+
+ return 0;
+ }
if (r < 0)
log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);
IPv6ProxyNDPAddress=
IPv6AcceptRA=
IPv6AcceptRouterAdvertisements=
+IPv4AcceptLocal=
DNSSECNegativeTrustAnchors=
MACVTAP=
IPv6PrivacyExtensions=
IPv4ProxyARP=true
IPv6ProxyNDP=true
IPv6AcceptRA=no
+IPv4AcceptLocal=yes
self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
+ self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
def test_sysctl_disable_ipv6(self):
copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
with self.subTest(test=test):
if test == 'no-slave':
# bridge has no slaves; it's up but *might* not have carrier
- self.wait_online(['bridge99:no-carrier'])
+ # It may take very long time that the interface become configured state.
+ self.wait_online(['bridge99:no-carrier'], timeout='2m')
# due to a bug in the kernel, newly-created bridges are brought up
# *with* carrier, unless they have had any setting changed; e.g.
# their mac set, priority set, etc. Then, they will lose carrier
echo -n " - freeze from outside: "
echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+ # Give kernel some time to freeze the slice
+ sleep 1
# Our state should not be affected
check_freezer_state "${slice}" "running"
echo -n " - thaw from outside: "
echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+ sleep 1
+
check_freezer_state "${unit}" "running"
check_freezer_state "${slice}" "running"
grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1+
-from __future__ import print_function
-
import gdb
class sd_dump_hashmaps(gdb.Command):
- "dump systemd's hashmaps"
-
- def __init__(self):
- super(sd_dump_hashmaps, self).__init__("sd_dump_hashmaps", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
-
- def invoke(self, arg, from_tty):
- d = gdb.parse_and_eval("hashmap_debug_list")
- all_entry_sizes = gdb.parse_and_eval("all_entry_sizes")
- all_direct_buckets = gdb.parse_and_eval("all_direct_buckets")
- uchar_t = gdb.lookup_type("unsigned char")
- ulong_t = gdb.lookup_type("unsigned long")
- debug_offset = gdb.parse_and_eval("(unsigned long)&((HashmapBase*)0)->debug")
-
- print("type, hash, indirect, entries, max_entries, buckets, creator")
- while d:
- h = gdb.parse_and_eval("(HashmapBase*)((char*)%d - %d)" % (int(d.cast(ulong_t)), debug_offset))
-
- if h["has_indirect"]:
- storage_ptr = h["indirect"]["storage"].cast(uchar_t.pointer())
- n_entries = h["indirect"]["n_entries"]
- n_buckets = h["indirect"]["n_buckets"]
- else:
- storage_ptr = h["direct"]["storage"].cast(uchar_t.pointer())
- n_entries = h["n_direct_entries"]
- n_buckets = all_direct_buckets[int(h["type"])];
-
- t = ["plain", "ordered", "set"][int(h["type"])]
-
- print("{}, {}, {}, {}, {}, {}, {} ({}:{})".format(t, h["hash_ops"], bool(h["has_indirect"]), n_entries, d["max_entries"], n_buckets, d["func"], d["file"], d["line"]))
-
- if arg != "" and n_entries > 0:
- dib_raw_addr = storage_ptr + (all_entry_sizes[h["type"]] * n_buckets)
-
- histogram = {}
- for i in xrange(0, n_buckets):
- dib = int(dib_raw_addr[i])
- histogram[dib] = histogram.get(dib, 0) + 1
-
- for dib in sorted(iter(histogram)):
- if dib != 255:
- print("{:>3} {:>8} {} of entries".format(dib, histogram[dib], 100.0*histogram[dib]/n_entries))
- else:
- print("{:>3} {:>8} {} of slots".format(dib, histogram[dib], 100.0*histogram[dib]/n_buckets))
- print("mean DIB of entries: {}".format(sum([dib*histogram[dib] for dib in iter(histogram) if dib != 255])*1.0/n_entries))
-
- blocks = []
- current_len = 1
- prev = int(dib_raw_addr[0])
- for i in xrange(1, n_buckets):
- dib = int(dib_raw_addr[i])
- if (dib == 255) != (prev == 255):
- if prev != 255:
- blocks += [[i, current_len]]
- current_len = 1
- else:
- current_len += 1
-
- prev = dib
- if prev != 255:
- blocks += [[i, current_len]]
- # a block may be wrapped around
- if len(blocks) > 1 and blocks[0][0] == blocks[0][1] and blocks[-1][0] == n_buckets - 1:
- blocks[0][1] += blocks[-1][1]
- blocks = blocks[0:-1]
- print("max block: {}".format(max(blocks, key=lambda a: a[1])))
- print("sum block lens: {}".format(sum(b[1] for b in blocks)))
- print("mean block len: {}".format((1.0 * sum(b[1] for b in blocks) / len(blocks))))
-
- d = d["debug_list_next"]
+ "dump systemd's hashmaps"
+
+ def __init__(self):
+ super().__init__("sd_dump_hashmaps", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
+
+ def invoke(self, arg, from_tty):
+ d = gdb.parse_and_eval("hashmap_debug_list")
+ hashmap_type_info = gdb.parse_and_eval("hashmap_type_info")
+ uchar_t = gdb.lookup_type("unsigned char")
+ ulong_t = gdb.lookup_type("unsigned long")
+ debug_offset = gdb.parse_and_eval("(unsigned long)&((HashmapBase*)0)->debug")
+
+ print("type, hash, indirect, entries, max_entries, buckets, creator")
+ while d:
+ h = gdb.parse_and_eval(f"(HashmapBase*)((char*){int(d.cast(ulong_t))} - {debug_offset})")
+
+ if h["has_indirect"]:
+ storage_ptr = h["indirect"]["storage"].cast(uchar_t.pointer())
+ n_entries = h["indirect"]["n_entries"]
+ n_buckets = h["indirect"]["n_buckets"]
+ else:
+ storage_ptr = h["direct"]["storage"].cast(uchar_t.pointer())
+ n_entries = h["n_direct_entries"]
+ n_buckets = hashmap_type_info[h["type"]]["n_direct_buckets"]
+
+ t = ["plain", "ordered", "set"][int(h["type"])]
+
+ print(f'{t}, {h["hash_ops"]}, {bool(h["has_indirect"])}, {n_entries}, {d["max_entries"]}, {n_buckets}, {d["func"].string()}, {d["file"].string()}:{d["line"]}')
+
+ if arg != "" and n_entries > 0:
+ dib_raw_addr = storage_ptr + hashmap_type_info[h["type"]]["entry_size"] * n_buckets
+
+ histogram = {}
+ for i in range(0, n_buckets):
+ dib = int(dib_raw_addr[i])
+ histogram[dib] = histogram.get(dib, 0) + 1
+
+ for dib in sorted(histogram):
+ if dib != 255:
+ print(f"{dib:>3} {histogram[dib]:>8} {float(histogram[dib]/n_entries):.0%} of entries")
+ else:
+ print(f"{dib:>3} {histogram[dib]:>8} {float(histogram[dib]/n_buckets):.0%} of slots")
+ s = sum(dib*count for (dib, count) in histogram.items() if dib != 255) / n_entries
+ print(f"mean DIB of entries: {s}")
+
+ blocks = []
+ current_len = 1
+ prev = int(dib_raw_addr[0])
+ for i in range(1, n_buckets):
+ dib = int(dib_raw_addr[i])
+ if (dib == 255) != (prev == 255):
+ if prev != 255:
+ blocks += [[i, current_len]]
+ current_len = 1
+ else:
+ current_len += 1
+
+ prev = dib
+ if prev != 255:
+ blocks += [[i, current_len]]
+ # a block may be wrapped around
+ if len(blocks) > 1 and blocks[0][0] == blocks[0][1] and blocks[-1][0] == n_buckets - 1:
+ blocks[0][1] += blocks[-1][1]
+ blocks = blocks[0:-1]
+ print("max block: {}".format(max(blocks, key=lambda a: a[1])))
+ print("sum block lens: {}".format(sum(b[1] for b in blocks)))
+ print("mean block len: {}".format(sum(b[1] for b in blocks) / len(blocks)))
+
+ d = d["debug_list_next"]
sd_dump_hashmaps()
# (at your option) any later version.
[Unit]
-Description=Cleanup udevd DB
+Description=Cleanup udev Database
DefaultDependencies=no
ConditionPathExists=/etc/initrd-release
Conflicts=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udev-trigger.service systemd-udev-settle.service
# expect a populated /dev during bootup.
[Unit]
-Description=udev Wait for Complete Device Initialization
+Description=Wait for udev To Complete Device Initialization
Documentation=man:systemd-udev-settle.service(8)
DefaultDependencies=no
Wants=systemd-udevd.service
# (at your option) any later version.
[Unit]
-Description=udev Coldplug all Devices
+Description=Coldplug All udev Devices
Documentation=man:udev(7) man:systemd-udevd.service(8)
DefaultDependencies=no
Wants=systemd-udevd.service