summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--TODO8
-rw-r--r--hwdb.d/60-keyboard.hwdb4
-rw-r--r--man/crypttab.xml7
-rw-r--r--man/kernel-command-line.xml3
-rw-r--r--man/systemd-udevd.service.xml28
-rw-r--r--man/systemd.network.xml9
-rw-r--r--src/basic/hashmap.c70
-rw-r--r--src/basic/hashmap.h171
-rw-r--r--src/basic/ordered-set.h2
-rw-r--r--src/basic/parse-util.c161
-rw-r--r--src/basic/parse-util.h6
-rw-r--r--src/basic/set.h40
-rw-r--r--src/basic/strv.c8
-rw-r--r--src/basic/strv.h6
-rw-r--r--src/basic/user-util.c37
-rw-r--r--src/cryptsetup/cryptsetup.c20
-rw-r--r--src/home/homectl.c2
-rw-r--r--src/libsystemd-network/sd-lldp.c2
-rw-r--r--src/libsystemd/sd-network/sd-network.c4
-rw-r--r--src/network/networkctl.c12
-rw-r--r--src/network/networkd-link.c31
-rw-r--r--src/network/networkd-network-gperf.gperf1
-rw-r--r--src/network/networkd-network.c2
-rw-r--r--src/network/networkd-network.h1
-rw-r--r--src/resolve/resolv.conf2
-rw-r--r--src/resolve/resolved-resolv-conf.c2
-rw-r--r--src/systemd/sd-network.h3
-rw-r--r--src/test/test-parse-util.c58
-rw-r--r--src/test/test-user-util.c101
-rw-r--r--src/udev/udevd.c86
-rw-r--r--test/fuzz/fuzz-network-parser/directives.network1
-rw-r--r--test/test-network/conf/25-sysctl.network1
-rwxr-xr-xtest/test-network/systemd-networkd-tests.py13
-rw-r--r--tools/gdb-sd_dump_hashmaps.py140
-rw-r--r--units/initrd-udevadm-cleanup-db.service2
-rw-r--r--units/systemd-udev-settle.service2
-rw-r--r--units/systemd-udev-trigger.service2
38 files changed, 752 insertions, 299 deletions
diff --git a/.gitignore b/.gitignore
index 5d18705531..f47de39f3d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,8 @@
.config.args
.gdb_history
.deps/
+.mypy_cache/
+__pycache__/
/*.gcda
/*.gcno
/*.tar.bz2
@@ -34,4 +36,3 @@
/mkosi.builddir/
/mkosi.output/
/tags
-__pycache__/
diff --git a/TODO b/TODO
index dd9907b2c0..c4275b48e0 100644
--- a/TODO
+++ b/TODO
@@ -19,6 +19,14 @@ Janitorial Clean-ups:
Features:
+* add systemd.random_seed= on the kernel cmdline, taking some hex or base64
+ encoded data. During earliest boot, credit it to entropy. This is not useful
+ for general purpose systems, but certainly for testing environments in VMs
+ and such, as it allows us to boot up instantly with fully initialized entropy
+ pool even if RNG pass-thru is not available.
+
+* Support ProtectProc= or so, using: https://patchwork.kernel.org/cover/11310197/
+
* if /usr/bin/swapoff fails due to OOM, log a friendly explanatory message about it
* build short web pages out of each catalog entry, build them along with man
diff --git a/hwdb.d/60-keyboard.hwdb b/hwdb.d/60-keyboard.hwdb
index 875bf66bd8..99fd78c364 100644
--- a/hwdb.d/60-keyboard.hwdb
+++ b/hwdb.d/60-keyboard.hwdb
@@ -529,6 +529,10 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*[sS][pP][eE][cC][tT][rR][eE]*x360Convert
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*13*x360*:pvr*
KEYBOARD_KEY_d7=unknown
+# Spectre x360 13
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPSpectrex360Convertible13*:pvr*
+ KEYBOARD_KEY_82=f20 # Fn+F12; Microphone mute button, should be micmute
+
# Elitebook
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:pvr*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:pvr*
diff --git a/man/crypttab.xml b/man/crypttab.xml
index 3170e5880f..2046911c78 100644
--- a/man/crypttab.xml
+++ b/man/crypttab.xml
@@ -178,6 +178,13 @@
</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>
<listitem><para>Marks this cryptsetup device as requiring network. It will be
diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml
index 7e59a1aaed..52939deec0 100644
--- a/man/kernel-command-line.xml
+++ b/man/kernel-command-line.xml
@@ -273,7 +273,8 @@
<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>
diff --git a/man/systemd-udevd.service.xml b/man/systemd-udevd.service.xml
index 55edc17353..c6c1d9bcc6 100644
--- a/man/systemd-udevd.service.xml
+++ b/man/systemd-udevd.service.xml
@@ -77,7 +77,7 @@
</varlistentry>
<varlistentry>
- <term><option>-c=</option></term>
+ <term><option>-c</option></term>
<term><option>--children-max=</option></term>
<listitem>
<para>Limit the number of events executed in parallel.</para>
@@ -85,7 +85,7 @@
</varlistentry>
<varlistentry>
- <term><option>-e=</option></term>
+ <term><option>-e</option></term>
<term><option>--exec-delay=</option></term>
<listitem>
<para>Delay the execution of <varname>RUN</varname>
@@ -97,7 +97,7 @@
</varlistentry>
<varlistentry>
- <term><option>-t=</option></term>
+ <term><option>-t</option></term>
<term><option>--event-timeout=</option></term>
<listitem>
<para>Set the number of seconds to wait for events to finish. After
@@ -121,7 +121,7 @@
</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.
@@ -140,8 +140,8 @@
<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>
@@ -185,6 +185,22 @@
</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>Network interfaces are renamed to give them predictable names
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index a4ca67a27f..ae93a39eb4 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -673,6 +673,13 @@
</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,
usually a router, answers ARP requests intended for another machine. By "faking" its identity,
@@ -3275,7 +3282,7 @@
<varlistentry>
<term><varname>Weight=</varname></term>
<listitem>
- <para>Specifies the weight of the class. Takse an integer in the range 1..1023. Defaults to
+ <para>Specifies the weight of the class. Takes an integer in the range 1..1023. Defaults to
unset in which case the kernel default is used.</para>
</listitem>
</varlistentry>
diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c
index efbe95bb9e..3172865e3e 100644
--- a/src/basic/hashmap.c
+++ b/src/basic/hashmap.c
@@ -145,12 +145,7 @@ struct hashmap_debug_info {
/* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */
static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list);
static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-#define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug;
-
-#else /* !ENABLE_DEBUG_HASHMAP */
-#define HASHMAP_DEBUG_FIELDS
-#endif /* ENABLE_DEBUG_HASHMAP */
+#endif
enum HashmapType {
HASHMAP_TYPE_PLAIN,
@@ -212,7 +207,10 @@ struct HashmapBase {
bool from_pool:1; /* whether was allocated from mempool */
bool dirty:1; /* whether dirtied since last iterated_cache_get() */
bool cached:1; /* whether this hashmap is being cached */
- HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */
+
+#if ENABLE_DEBUG_HASHMAP
+ struct hashmap_debug_info debug;
+#endif
};
/* Specific hash types
@@ -254,7 +252,7 @@ struct hashmap_type_info {
unsigned n_direct_buckets;
};
-static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
+static _used_ const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
[HASHMAP_TYPE_PLAIN] = {
.head_size = sizeof(Hashmap),
.entry_size = sizeof(struct plain_hashmap_entry),
@@ -707,7 +705,7 @@ static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
: hashmap_iterate_in_internal_order(h, i);
}
-bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
+bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
struct hashmap_base_entry *e;
void *data;
unsigned idx;
@@ -733,7 +731,7 @@ bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const v
}
bool set_iterate(const Set *s, Iterator *i, void **value) {
- return internal_hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL);
+ return _hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL);
}
#define HASHMAP_FOREACH_IDX(idx, h, i) \
@@ -741,7 +739,7 @@ bool set_iterate(const Set *s, Iterator *i, void **value) {
(idx != IDX_NIL); \
(idx) = hashmap_iterate_entry((h), &(i)))
-IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h) {
+IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h) {
IteratedCache *cache;
assert(h);
@@ -809,15 +807,15 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
return h;
}
-Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+Hashmap *_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
}
-OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
}
-Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
}
@@ -838,15 +836,15 @@ static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops
return 0;
}
-int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
}
-int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
}
-int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
}
@@ -868,16 +866,16 @@ static void hashmap_free_no_clear(HashmapBase *h) {
free(h);
}
-HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
+HashmapBase *_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
if (h) {
- internal_hashmap_clear(h, default_free_key, default_free_value);
+ _hashmap_clear(h, default_free_key, default_free_value);
hashmap_free_no_clear(h);
}
return NULL;
}
-void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
+void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
free_func_t free_key, free_value;
if (!h)
return;
@@ -891,11 +889,11 @@ void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_f
* hash table, and only then call the destructor functions. If these destructors then try to unregister
* themselves from our hash table a second time, the entry is already gone. */
- while (internal_hashmap_size(h) > 0) {
+ while (_hashmap_size(h) > 0) {
void *k = NULL;
void *v;
- v = internal_hashmap_first_key_and_value(h, true, &k);
+ v = _hashmap_first_key_and_value(h, true, &k);
if (free_key)
free_key(k);
@@ -1301,7 +1299,7 @@ int hashmap_update(Hashmap *h, const void *key, void *value) {
return 0;
}
-void *internal_hashmap_get(HashmapBase *h, const void *key) {
+void *_hashmap_get(HashmapBase *h, const void *key) {
struct hashmap_base_entry *e;
unsigned hash, idx;
@@ -1336,7 +1334,7 @@ void *hashmap_get2(Hashmap *h, const void *key, void **key2) {
return e->value;
}
-bool internal_hashmap_contains(HashmapBase *h, const void *key) {
+bool _hashmap_contains(HashmapBase *h, const void *key) {
unsigned hash;
if (!h)
@@ -1346,7 +1344,7 @@ bool internal_hashmap_contains(HashmapBase *h, const void *key) {
return bucket_scan(h, hash, key) != IDX_NIL;
}
-void *internal_hashmap_remove(HashmapBase *h, const void *key) {
+void *_hashmap_remove(HashmapBase *h, const void *key) {
struct hashmap_base_entry *e;
unsigned hash, idx;
void *data;
@@ -1484,7 +1482,7 @@ int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_
return 0;
}
-void *internal_hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
+void *_hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
struct hashmap_base_entry *e;
unsigned hash, idx;
@@ -1514,7 +1512,7 @@ static unsigned find_first_entry(HashmapBase *h) {
return hashmap_iterate_entry(h, &i);
}
-void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
+void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
struct hashmap_base_entry *e;
void *key, *data;
unsigned idx;
@@ -1539,21 +1537,21 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r
return data;
}
-unsigned internal_hashmap_size(HashmapBase *h) {
+unsigned _hashmap_size(HashmapBase *h) {
if (!h)
return 0;
return n_entries(h);
}
-unsigned internal_hashmap_buckets(HashmapBase *h) {
+unsigned _hashmap_buckets(HashmapBase *h) {
if (!h)
return 0;
return n_buckets(h);
}
-int internal_hashmap_merge(Hashmap *h, Hashmap *other) {
+int _hashmap_merge(Hashmap *h, Hashmap *other) {
Iterator i;
unsigned idx;
@@ -1589,7 +1587,7 @@ int set_merge(Set *s, Set *other) {
return 0;
}
-int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) {
+int _hashmap_reserve(HashmapBase *h, unsigned entries_add) {
int r;
assert(h);
@@ -1607,7 +1605,7 @@ int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) {
* Returns: 0 on success.
* -ENOMEM on alloc failure, in which case no move has been done.
*/
-int internal_hashmap_move(HashmapBase *h, HashmapBase *other) {
+int _hashmap_move(HashmapBase *h, HashmapBase *other) {
struct swap_entries swap;
struct hashmap_base_entry *e, *n;
Iterator i;
@@ -1652,7 +1650,7 @@ int internal_hashmap_move(HashmapBase *h, HashmapBase *other) {
return 0;
}
-int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
+int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
struct swap_entries swap;
unsigned h_hash, other_hash, idx;
struct hashmap_base_entry *e, *n;
@@ -1689,7 +1687,7 @@ int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *ke
return 0;
}
-HashmapBase *internal_hashmap_copy(HashmapBase *h) {
+HashmapBase *_hashmap_copy(HashmapBase *h) {
HashmapBase *copy;
int r;
@@ -1712,14 +1710,14 @@ HashmapBase *internal_hashmap_copy(HashmapBase *h) {
}
if (r < 0) {
- internal_hashmap_free(copy, false, false);
+ _hashmap_free(copy, false, false);
return NULL;
}
return copy;
}
-char **internal_hashmap_get_strv(HashmapBase *h) {
+char **_hashmap_get_strv(HashmapBase *h) {
char **sv;
Iterator i;
unsigned idx, n;
diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h
index a3bc328142..230d322213 100644
--- a/src/basic/hashmap.h
+++ b/src/basic/hashmap.h
@@ -14,7 +14,7 @@
* will be treated as empty hashmap for all read operations. That way it is not
* necessary to instantiate an object for each Hashmap use.
*
- * If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap),
+ * If ENABLE_DEBUG_HASHMAP is defined (by configuring with -Ddebug-extra=hashmap),
* the implementation will:
* - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
* - perform extra checks for invalid use of iterators
@@ -24,10 +24,9 @@
typedef void* (*hashmap_destroy_t)(void *p);
-/* The base type for all hashmap and set types. Many functions in the
- * implementation take (HashmapBase*) parameters and are run-time polymorphic,
- * though the API is not meant to be polymorphic (do not call functions
- * internal_*() directly). */
+/* The base type for all hashmap and set types. Many functions in the implementation take (HashmapBase*)
+ * parameters and are run-time polymorphic, though the API is not meant to be polymorphic (do not call
+ * underscore-prefixed functions directly). */
typedef struct HashmapBase HashmapBase;
/* Specific hashmap/set types */
@@ -84,10 +83,10 @@ typedef struct {
# define HASHMAP_DEBUG_PASS_ARGS
#endif
-Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
-#define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
+Hashmap *_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define hashmap_new(ops) _hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
+#define ordered_hashmap_new(ops) _ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
#define hashmap_free_and_replace(a, b) \
({ \
@@ -97,57 +96,57 @@ OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HA
0; \
})
-HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
+HashmapBase *_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
static inline Hashmap *hashmap_free(Hashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, NULL);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
}
static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, NULL);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
}
static inline Hashmap *hashmap_free_free(Hashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, free);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free);
}
static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, free);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free);
}
static inline Hashmap *hashmap_free_free_key(Hashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, NULL);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL);
}
static inline OrderedHashmap *ordered_hashmap_free_free_key(OrderedHashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, NULL);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL);
}
static inline Hashmap *hashmap_free_free_free(Hashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, free);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), free, free);
}
static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) {
- return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, free);
+ return (void*) _hashmap_free(HASHMAP_BASE(h), free, free);
}
IteratedCache *iterated_cache_free(IteratedCache *cache);
int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries);
-HashmapBase *internal_hashmap_copy(HashmapBase *h);
+HashmapBase *_hashmap_copy(HashmapBase *h);
static inline Hashmap *hashmap_copy(Hashmap *h) {
- return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
+ return (Hashmap*) _hashmap_copy(HASHMAP_BASE(h));
}
static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
- return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
+ return (OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h));
}
-int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
-#define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+#define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
-IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h);
+IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h);
static inline IteratedCache *hashmap_iterated_cache_new(Hashmap *h) {
- return (IteratedCache*) internal_hashmap_iterated_cache_new(HASHMAP_BASE(h));
+ return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
}
static inline IteratedCache *ordered_hashmap_iterated_cache_new(OrderedHashmap *h) {
- return (IteratedCache*) internal_hashmap_iterated_cache_new(HASHMAP_BASE(h));
+ return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
}
int hashmap_put(Hashmap *h, const void *key, void *value);
@@ -167,12 +166,12 @@ static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, vo
return hashmap_replace(PLAIN_HASHMAP(h), key, value);
}
-void *internal_hashmap_get(HashmapBase *h, const void *key);
+void *_hashmap_get(HashmapBase *h, const void *key);
static inline void *hashmap_get(Hashmap *h, const void *key) {
- return internal_hashmap_get(HASHMAP_BASE(h), key);
+ return _hashmap_get(HASHMAP_BASE(h), key);
}
static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) {
- return internal_hashmap_get(HASHMAP_BASE(h), key);
+ return _hashmap_get(HASHMAP_BASE(h), key);
}
void *hashmap_get2(Hashmap *h, const void *key, void **rkey);
@@ -180,20 +179,20 @@ static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, voi
return hashmap_get2(PLAIN_HASHMAP(h), key, rkey);
}
-bool internal_hashmap_contains(HashmapBase *h, const void *key);
+bool _hashmap_contains(HashmapBase *h, const void *key);
static inline bool hashmap_contains(Hashmap *h, const void *key) {
- return internal_hashmap_contains(HASHMAP_BASE(h), key);
+ return _hashmap_contains(HASHMAP_BASE(h), key);
}
static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) {
- return internal_hashmap_contains(HASHMAP_BASE(h), key);
+ return _hashmap_contains(HASHMAP_BASE(h), key);
}
-void *internal_hashmap_remove(HashmapBase *h, const void *key);
+void *_hashmap_remove(HashmapBase *h, const void *key);
static inline void *hashmap_remove(Hashmap *h, const void *key) {
- return internal_hashmap_remove(HASHMAP_BASE(h), key);
+ return _hashmap_remove(HASHMAP_BASE(h), key);
}
static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) {
- return internal_hashmap_remove(HASHMAP_BASE(h), key);
+ return _hashmap_remove(HASHMAP_BASE(h), key);
}
void *hashmap_remove2(Hashmap *h, const void *key, void **rkey);
@@ -201,9 +200,9 @@ static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key,
return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey);
}
-void *internal_hashmap_remove_value(HashmapBase *h, const void *key, void *value);
+void *_hashmap_remove_value(HashmapBase *h, const void *key, void *value);
static inline void *hashmap_remove_value(Hashmap *h, const void *key, void *value) {
- return internal_hashmap_remove_value(HASHMAP_BASE(h), key, value);
+ return _hashmap_remove_value(HASHMAP_BASE(h), key, value);
}
static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
@@ -222,41 +221,41 @@ static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const vo
/* Since merging data from a OrderedHashmap into a Hashmap or vice-versa
* should just work, allow this by having looser type-checking here. */
-int internal_hashmap_merge(Hashmap *h, Hashmap *other);
-#define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
+int _hashmap_merge(Hashmap *h, Hashmap *other);
+#define hashmap_merge(h, other) _hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
#define ordered_hashmap_merge(h, other) hashmap_merge(h, other)
-int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add);
+int _hashmap_reserve(HashmapBase *h, unsigned entries_add);
static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) {
- return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+ return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
}
static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) {
- return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+ return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
}
-int internal_hashmap_move(HashmapBase *h, HashmapBase *other);
+int _hashmap_move(HashmapBase *h, HashmapBase *other);
/* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */
static inline int hashmap_move(Hashmap *h, Hashmap *other) {
- return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
+ return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
}
static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) {
- return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
+ return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
}
-int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
+int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
- return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
+ return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
}
static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) {
- return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
+ return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
}
-unsigned internal_hashmap_size(HashmapBase *h) _pure_;
+unsigned _hashmap_size(HashmapBase *h) _pure_;
static inline unsigned hashmap_size(Hashmap *h) {
- return internal_hashmap_size(HASHMAP_BASE(h));
+ return _hashmap_size(HASHMAP_BASE(h));
}
static inline unsigned ordered_hashmap_size(OrderedHashmap *h) {
- return internal_hashmap_size(HASHMAP_BASE(h));
+ return _hashmap_size(HASHMAP_BASE(h));
}
static inline bool hashmap_isempty(Hashmap *h) {
@@ -266,49 +265,49 @@ static inline bool ordered_hashmap_isempty(OrderedHashmap *h) {
return ordered_hashmap_size(h) == 0;
}
-unsigned internal_hashmap_buckets(HashmapBase *h) _pure_;
+unsigned _hashmap_buckets(HashmapBase *h) _pure_;
static inline unsigned hashmap_buckets(Hashmap *h) {
- return internal_hashmap_buckets(HASHMAP_BASE(h));
+ return _hashmap_buckets(HASHMAP_BASE(h));
}
static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) {
- return internal_hashmap_buckets(HASHMAP_BASE(h));
+ return _hashmap_buckets(HASHMAP_BASE(h));
}
-bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key);
+bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key);
static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) {
- return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
+ return _hashmap_iterate(HASHMAP_BASE(h), i, value, key);
}
static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) {
- return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
+ return _hashmap_iterate(HASHMAP_BASE(h), i, value, key);
}
-void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
+void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
static inline void hashmap_clear(Hashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
+ _hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
}
static inline void ordered_hashmap_clear(OrderedHashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
+ _hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
}
static inline void hashmap_clear_free(Hashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), NULL, free);
+ _hashmap_clear(HASHMAP_BASE(h), NULL, free);
}
static inline void ordered_hashmap_clear_free(OrderedHashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), NULL, free);
+ _hashmap_clear(HASHMAP_BASE(h), NULL, free);
}
static inline void hashmap_clear_free_key(Hashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), free, NULL);
+ _hashmap_clear(HASHMAP_BASE(h), free, NULL);
}
static inline void ordered_hashmap_clear_free_key(OrderedHashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), free, NULL);
+ _hashmap_clear(HASHMAP_BASE(h), free, NULL);
}
static inline void hashmap_clear_free_free(Hashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), free, free);
+ _hashmap_clear(HASHMAP_BASE(h), free, free);
}
static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h), free, free);
+ _hashmap_clear(HASHMAP_BASE(h), free, free);
}
/*
@@ -322,50 +321,50 @@ static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
* the first entry is O(1).
*/
-void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key);
+void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key);
static inline void *hashmap_steal_first_key_and_value(Hashmap *h, void **ret) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
}
static inline void *ordered_hashmap_steal_first_key_and_value(OrderedHashmap *h, void **ret) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
}
static inline void *hashmap_first_key_and_value(Hashmap *h, void **ret) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
}
static inline void *ordered_hashmap_first_key_and_value(OrderedHashmap *h, void **ret) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
}
static inline void *hashmap_steal_first(Hashmap *h) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
}
static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
}
static inline void *hashmap_first(Hashmap *h) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
}
static inline void *ordered_hashmap_first(OrderedHashmap *h) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
}
-static inline void *internal_hashmap_first_key(HashmapBase *h, bool remove) {
+static inline void *_hashmap_first_key(HashmapBase *h, bool remove) {
void *key = NULL;
- (void) internal_hashmap_first_key_and_value(HASHMAP_BASE(h), remove, &key);
+ (void) _hashmap_first_key_and_value(HASHMAP_BASE(h), remove, &key);
return key;
}
static inline void *hashmap_steal_first_key(Hashmap *h) {
- return internal_hashmap_first_key(HASHMAP_BASE(h), true);
+ return _hashmap_first_key(HASHMAP_BASE(h), true);
}
static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) {
- return internal_hashmap_first_key(HASHMAP_BASE(h), true);
+ return _hashmap_first_key(HASHMAP_BASE(h), true);
}
static inline void *hashmap_first_key(Hashmap *h) {
- return internal_hashmap_first_key(HASHMAP_BASE(h), false);
+ return _hashmap_first_key(HASHMAP_BASE(h), false);
}
static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
- return internal_hashmap_first_key(HASHMAP_BASE(h), false);
+ return _hashmap_first_key(HASHMAP_BASE(h), false);
}
#define hashmap_clear_with_destructor(_s, _f) \
@@ -394,12 +393,12 @@ static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
/* no hashmap_next */
void *ordered_hashmap_next(OrderedHashmap *h, const void *key);
-char **internal_hashmap_get_strv(HashmapBase *h);
+char **_hashmap_get_strv(HashmapBase *h);
static inline char **hashmap_get_strv(Hashmap *h) {
- return internal_hashmap_get_strv(HASHMAP_BASE(h));
+ return _hashmap_get_strv(HASHMAP_BASE(h));
}
static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
- return internal_hashmap_get_strv(HASHMAP_BASE(h));
+ return _hashmap_get_strv(HASHMAP_BASE(h));
}
/*
diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h
index 383a729cab..a42a57eb49 100644
--- a/src/basic/ordered-set.h
+++ b/src/basic/ordered-set.h
@@ -59,7 +59,7 @@ static inline void* ordered_set_steal_first(OrderedSet *s) {
}
static inline char **ordered_set_get_strv(OrderedSet *s) {
- return internal_hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s));
+ return _hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s));
}
int ordered_set_consume(OrderedSet *s, void *p);
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 59f8a31cec..44f0438cf4 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -70,26 +70,24 @@ int parse_pid(const char *s, pid_t* ret_pid) {
}
int parse_mode(const char *s, mode_t *ret) {
- char *x;
- long l;
+ unsigned m;
+ int r;
assert(s);
- assert(ret);
-
- s += strspn(s, WHITESPACE);
- if (s[0] == '-')
- return -ERANGE;
- errno = 0;
- l = strtol(s, &x, 8);
- if (errno > 0)
- return -errno;
- if (!x || x == s || *x != 0)
- return -EINVAL;
- if (l < 0 || l > 07777)
+ r = safe_atou_full(s, 8 |
+ SAFE_ATO_REFUSE_PLUS_MINUS, /* Leading '+' or even '-' char? that's just weird,
+ * refuse. User might have wanted to add mode flags or
+ * so, but this parser doesn't allow that, so let's
+ * better be safe. */
+ &m);
+ if (r < 0)
+ return r;
+ if (m > 07777)
return -ERANGE;
- *ret = (mode_t) l;
+ if (ret)
+ *ret = m;
return 0;
}
@@ -354,30 +352,73 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) {
return 0;
}
+static const char *mangle_base(const char *s, unsigned *base) {
+ const char *k;
+
+ assert(s);
+ assert(base);
+
+ /* Base already explicitly specified, then don't do anything. */
+ if (SAFE_ATO_MASK_FLAGS(*base) != 0)
+ return s;
+
+ /* Support Python 3 style "0b" and 0x" prefixes, because they truly make sense, much more than C's "0" prefix for octal. */
+ k = STARTSWITH_SET(s, "0b", "0B");
+ if (k) {
+ *base = 2 | (*base & SAFE_ATO_ALL_FLAGS);
+ return k;
+ }
+
+ k = STARTSWITH_SET(s, "0o", "0O");
+ if (k) {
+ *base = 8 | (*base & SAFE_ATO_ALL_FLAGS);
+ return k;
+ }
+
+ return s;
+}
+
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
char *x = NULL;
unsigned long l;
assert(s);
- assert(base <= 16);
+ assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
- /* strtoul() is happy to parse negative values, and silently
- * converts them to unsigned values without generating an
- * error. We want a clean error, hence let's look for the "-"
- * prefix on our own, and generate an error. But let's do so
- * only after strtoul() validated that the string is clean
- * otherwise, so that we return EINVAL preferably over
- * ERANGE. */
+ /* strtoul() is happy to parse negative values, and silently converts them to unsigned values without
+ * generating an error. We want a clean error, hence let's look for the "-" prefix on our own, and
+ * generate an error. But let's do so only after strtoul() validated that the string is clean
+ * otherwise, so that we return EINVAL preferably over ERANGE. */
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
+ strchr(WHITESPACE, s[0]))
+ return -EINVAL;
s += strspn(s, WHITESPACE);
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
+ IN_SET(s[0], '+', '-'))
+ return -EINVAL; /* Note that we check the "-" prefix again a second time below, but return a
+ * different error. I.e. if the SAFE_ATO_REFUSE_PLUS_MINUS flag is set we
+ * blanket refuse +/- prefixed integers, while if it is missing we'll just
+ * return ERANGE, because the string actually parses correctly, but doesn't
+ * fit in the return type. */
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
+ s[0] == '0' && !streq(s, "0"))
+ return -EINVAL; /* This is particularly useful to avoid ambiguities between C's octal
+ * notation and assumed-to-be-decimal integers with a leading zero. */
+
+ s = mangle_base(s, &base);
+
errno = 0;
- l = strtoul(s, &x, base);
+ l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base) /* Let's mask off the flags bits so that only the actual
+ * base is left */);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
return -EINVAL;
- if (s[0] == '-')
+ if (l != 0 && s[0] == '-')
return -ERANGE;
if ((unsigned long) (unsigned) l != l)
return -ERANGE;
@@ -389,13 +430,17 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
}
int safe_atoi(const char *s, int *ret_i) {
+ unsigned base = 0;
char *x = NULL;
long l;
assert(s);
+ s += strspn(s, WHITESPACE);
+ s = mangle_base(s, &base);
+
errno = 0;
- l = strtol(s, &x, 0);
+ l = strtol(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
@@ -414,16 +459,31 @@ int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu)
unsigned long long l;
assert(s);
+ assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
+ strchr(WHITESPACE, s[0]))
+ return -EINVAL;
s += strspn(s, WHITESPACE);
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
+ IN_SET(s[0], '+', '-'))
+ return -EINVAL;
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
+ s[0] == '0' && s[1] != 0)
+ return -EINVAL;
+
+ s = mangle_base(s, &base);
+
errno = 0;
- l = strtoull(s, &x, base);
+ l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base));
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
return -EINVAL;
- if (*s == '-')
+ if (l != 0 && s[0] == '-')
return -ERANGE;
if (ret_llu)
@@ -433,13 +493,17 @@ int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu)
}
int safe_atolli(const char *s, long long int *ret_lli) {
+ unsigned base = 0;
char *x = NULL;
long long l;
assert(s);
+ s += strspn(s, WHITESPACE);
+ s = mangle_base(s, &base);
+
errno = 0;
- l = strtoll(s, &x, 0);
+ l = strtoll(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
@@ -452,20 +516,22 @@ int safe_atolli(const char *s, long long int *ret_lli) {
}
int safe_atou8(const char *s, uint8_t *ret) {
- char *x = NULL;
+ unsigned base = 0;
unsigned long l;
+ char *x = NULL;
assert(s);
s += strspn(s, WHITESPACE);
+ s = mangle_base(s, &base);
errno = 0;
- l = strtoul(s, &x, 0);
+ l = strtoul(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
return -EINVAL;
- if (s[0] == '-')
+ if (l != 0 && s[0] == '-')
return -ERANGE;
if ((unsigned long) (uint8_t) l != l)
return -ERANGE;
@@ -480,34 +546,53 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
unsigned long l;
assert(s);
- assert(ret);
- assert(base <= 16);
+ assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
+ strchr(WHITESPACE, s[0]))
+ return -EINVAL;
s += strspn(s, WHITESPACE);
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
+ IN_SET(s[0], '+', '-'))
+ return -EINVAL;
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
+ s[0] == '0' && s[1] != 0)
+ return -EINVAL;
+
+ s = mangle_base(s, &base);
+
errno = 0;
- l = strtoul(s, &x, base);
+ l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base));
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
return -EINVAL;
- if (s[0] == '-')
+ if (l != 0 && s[0] == '-')
return -ERANGE;
if ((unsigned long) (uint16_t) l != l)
return -ERANGE;
- *ret = (uint16_t) l;
+ if (ret)
+ *ret = (uint16_t) l;
+
return 0;
}
int safe_atoi16(const char *s, int16_t *ret) {
+ unsigned base = 0;
char *x = NULL;
long l;
assert(s);
+ s += strspn(s, WHITESPACE);
+ s = mangle_base(s, &base);
+
errno = 0;
- l = strtol(s, &x, 0);
+ l = strtol(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
index 970bdefbf0..9a516ce5f6 100644
--- a/src/basic/parse-util.h
+++ b/src/basic/parse-util.h
@@ -21,6 +21,12 @@ int parse_range(const char *t, unsigned *lower, unsigned *upper);
int parse_errno(const char *t);
int parse_syscall_and_errno(const char *in, char **name, int *error);
+#define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
+#define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)
+#define SAFE_ATO_REFUSE_LEADING_WHITESPACE (1U << 28)
+#define SAFE_ATO_ALL_FLAGS (SAFE_ATO_REFUSE_PLUS_MINUS|SAFE_ATO_REFUSE_LEADING_ZERO|SAFE_ATO_REFUSE_LEADING_WHITESPACE)
+#define SAFE_ATO_MASK_FLAGS(base) ((base) & ~SAFE_ATO_ALL_FLAGS)
+
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u);
static inline int safe_atou(const char *s, unsigned *ret_u) {
diff --git a/src/basic/set.h b/src/basic/set.h
index 8a95fec05f..621e83bf27 100644
--- a/src/basic/set.h
+++ b/src/basic/set.h
@@ -13,40 +13,40 @@
0; \
})
-Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
+Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define set_new(ops) _set_new(ops HASHMAP_DEBUG_SRC_ARGS)
static inline Set *set_free(Set *s) {
- return (Set*) internal_hashmap_free(HASHMAP_BASE(s), NULL, NULL);
+ return (Set*) _hashmap_free(HASHMAP_BASE(s), NULL, NULL);
}
static inline Set *set_free_free(Set *s) {
- return (Set*) internal_hashmap_free(HASHMAP_BASE(s), free, NULL);
+ return (Set*) _hashmap_free(HASHMAP_BASE(s), free, NULL);
}
/* no set_free_free_free */
static inline Set *set_copy(Set *s) {
- return (Set*) internal_hashmap_copy(HASHMAP_BASE(s));
+ return (Set*) _hashmap_copy(HASHMAP_BASE(s));
}
-int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define set_ensure_allocated(h, ops) _set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
int set_put(Set *s, const void *key);
/* no set_update */
/* no set_replace */
static inline void *set_get(const Set *s, void *key) {
- return internal_hashmap_get(HASHMAP_BASE((Set *) s), key);
+ return _hashmap_get(HASHMAP_BASE((Set *) s), key);
}
/* no set_get2 */
static inline bool set_contains(const Set *s, const void *key) {
- return internal_hashmap_contains(HASHMAP_BASE((Set *) s), key);
+ return _hashmap_contains(HASHMAP_BASE((Set *) s), key);
}
static inline void *set_remove(Set *s, const void *key) {
- return internal_hashmap_remove(HASHMAP_BASE(s), key);
+ return _hashmap_remove(HASHMAP_BASE(s), key);
}
/* no set_remove2 */
@@ -56,19 +56,19 @@ int set_remove_and_put(Set *s, const void *old_key, const void *new_key);
int set_merge(Set *s, Set *other);
static inline int set_reserve(Set *h, unsigned entries_add) {
- return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+ return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
}
static inline int set_move(Set *s, Set *other) {
- return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other));
+ return _hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other));
}
static inline int set_move_one(Set *s, Set *other, const void *key) {
- return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key);
+ return _hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key);
}
static inline unsigned set_size(const Set *s) {
- return internal_hashmap_size(HASHMAP_BASE((Set *) s));
+ return _hashmap_size(HASHMAP_BASE((Set *) s));
}
static inline bool set_isempty(const Set *s) {
@@ -76,23 +76,23 @@ static inline bool set_isempty(const Set *s) {
}
static inline unsigned set_buckets(const Set *s) {
- return internal_hashmap_buckets(HASHMAP_BASE((Set *) s));
+ return _hashmap_buckets(HASHMAP_BASE((Set *) s));
}
bool set_iterate(const Set *s, Iterator *i, void **value);
static inline void set_clear(Set *s) {
- internal_hashmap_clear(HASHMAP_BASE(s), NULL, NULL);
+ _hashmap_clear(HASHMAP_BASE(s), NULL, NULL);
}
static inline void set_clear_free(Set *s) {
- internal_hashmap_clear(HASHMAP_BASE(s), free, NULL);
+ _hashmap_clear(HASHMAP_BASE(s), free, NULL);
}
/* no set_clear_free_free */
static inline void *set_steal_first(Set *s) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE(s), true, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE(s), true, NULL);
}
#define set_clear_with_destructor(_s, _f) \
@@ -111,13 +111,13 @@ static inline void *set_steal_first(Set *s) {
/* no set_first_key */
static inline void *set_first(const Set *s) {
- return internal_hashmap_first_key_and_value(HASHMAP_BASE((Set *) s), false, NULL);
+ return _hashmap_first_key_and_value(HASHMAP_BASE((Set *) s), false, NULL);
}
/* no set_next */
static inline char **set_get_strv(Set *s) {
- return internal_hashmap_get_strv(HASHMAP_BASE(s));
+ return _hashmap_get_strv(HASHMAP_BASE(s));
}
int set_consume(Set *s, void *value);
diff --git a/src/basic/strv.c b/src/basic/strv.c
index f1d2bb5190..858e1e62ec 100644
--- a/src/basic/strv.c
+++ b/src/basic/strv.c
@@ -946,20 +946,20 @@ static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const c
return 1;
}
-int string_strv_hashmap_put(Hashmap **h, const char *key, const char *value) {
+int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
int r;
- r = hashmap_ensure_allocated(h, &string_strv_hash_ops);
+ r = _hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
return string_strv_hashmap_put_internal(*h, key, value);
}
-int string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value) {
+int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
int r;
- r = ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops);
+ r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
diff --git a/src/basic/strv.h b/src/basic/strv.h
index 0f81e34580..2ad927bce5 100644
--- a/src/basic/strv.h
+++ b/src/basic/strv.h
@@ -226,5 +226,7 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
})
extern const struct hash_ops string_strv_hash_ops;
-int string_strv_hashmap_put(Hashmap **h, const char *key, const char *value);
-int string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value);
+int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS);
+int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS);
+#define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS)
+#define string_strv_ordered_hashmap_put(h, k, v) _string_strv_ordered_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS)
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index 2db8ef6abf..7dd2f6664a 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -49,7 +49,15 @@ int parse_uid(const char *s, uid_t *ret) {
assert(s);
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
- r = safe_atou32_full(s, 10, &uid);
+
+ /* We are very strict when parsing UIDs, and prohibit +/- as prefix, leading zero as prefix, and
+ * whitespace. We do this, since this call is often used in a context where we parse things as UID
+ * first, and if that doesn't work we fall back to NSS. Thus we really want to make sure that UIDs
+ * are parsed as UIDs only if they really really look like UIDs. */
+ r = safe_atou32_full(s, 10
+ | SAFE_ATO_REFUSE_PLUS_MINUS
+ | SAFE_ATO_REFUSE_LEADING_ZERO
+ | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &uid);
if (r < 0)
return r;
@@ -66,22 +74,39 @@ int parse_uid(const char *s, uid_t *ret) {
}
int parse_uid_range(const char *s, uid_t *ret_lower, uid_t *ret_upper) {
- uint32_t u, l;
+ _cleanup_free_ char *word = NULL;
+ uid_t l, u;
int r;
assert(s);
assert(ret_lower);
assert(ret_upper);
- r = parse_range(s, &l, &u);
+ r = extract_first_word(&s, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EINVAL;
+
+ r = parse_uid(word, &l);
if (r < 0)
return r;
- if (l > u)
+ /* Check for the upper bound and extract it if needed */
+ if (!s)
+ /* Single number with no dash. */
+ u = l;
+ else if (!*s)
+ /* Trailing dash is an error. */
return -EINVAL;
+ else {
+ r = parse_uid(s, &u);
+ if (r < 0)
+ return r;
- if (!uid_is_valid(l) || !uid_is_valid(u))
- return -ENXIO;
+ if (l > u)
+ return -EINVAL;
+ }
*ret_lower = l;
*ret_upper = u;
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 5886f86db6..c05e2d1351 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -38,7 +38,7 @@
#define CRYPT_SECTOR_SIZE 512
#define CRYPT_MAX_SECTOR_SIZE 4096
-static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT or CRYPT_PLAIN */
+static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT, CRYPT_BITLK or CRYPT_PLAIN */
static char *arg_cipher = NULL;
static unsigned arg_key_size = 0;
static unsigned arg_sector_size = CRYPT_SECTOR_SIZE;
@@ -220,6 +220,11 @@ static int parse_one_option(const char *option) {
arg_submit_from_crypt_cpus = true;
else if (streq(option, "luks"))
arg_type = ANY_LUKS;
+/* since cryptsetup 2.3.0 (Feb 2020) */
+#ifdef CRYPT_BITLK
+ else if (streq(option, "bitlk"))
+ arg_type = CRYPT_BITLK;
+#endif
else if (streq(option, "tcrypt"))
arg_type = CRYPT_TCRYPT;
else if (STR_IN_SET(option, "tcrypt-hidden", "tcrypthidden")) {
@@ -545,7 +550,7 @@ static int attach_tcrypt(
return 0;
}
-static int attach_luks_or_plain(
+static int attach_luks_or_plain_or_bitlk(
struct crypt_device *cd,
const char *name,
const char *key_file,
@@ -950,6 +955,15 @@ static int run(int argc, char *argv[]) {
}
}
+/* since cryptsetup 2.3.0 (Feb 2020) */
+#ifdef CRYPT_BITLK
+ if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_BITLK)) {
+ r = crypt_load(cd, CRYPT_BITLK, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load Bitlocker superblock on device %s: %m", crypt_get_device_name(cd));
+ }
+#endif
+
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
_cleanup_strv_free_erase_ char **passwords = NULL;
@@ -988,7 +1002,7 @@ static int run(int argc, char *argv[]) {
if (streq_ptr(arg_type, CRYPT_TCRYPT))
r = attach_tcrypt(cd, argv[2], key_file, key_data, key_data_size, passwords, flags);
else
- r = attach_luks_or_plain(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until);
+ r = attach_luks_or_plain_or_bitlk(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until);
if (r >= 0)
break;
if (r != -EAGAIN)
diff --git a/src/home/homectl.c b/src/home/homectl.c
index e9eb7c0ddb..f7237d22d8 100644
--- a/src/home/homectl.c
+++ b/src/home/homectl.c
@@ -2171,7 +2171,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --location=LOCATION Set location of user on earth\n"
" --icon-name=NAME Icon name for user\n"
" -d --home-dir=PATH Home directory\n"
- " --uid=UID Numeric UID for user\n"
+ " -u --uid=UID Numeric UID for user\n"
" -G --member-of=GROUP Add user to group\n"
" --skel=PATH Skeleton directory to use\n"
" --shell=PATH Shell for account\n"
diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c
index 1f28c5731f..d3606cf501 100644
--- a/src/libsystemd-network/sd-lldp.c
+++ b/src/libsystemd-network/sd-lldp.c
@@ -466,7 +466,7 @@ _public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) {
_public_ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t m) {
assert_return(lldp, -EINVAL);
- assert_return(m <= 0, -EINVAL);
+ assert_return(m > 0, -EINVAL);
lldp->neighbors_max = m;
lldp_make_space(lldp, 0);
diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c
index 7e03817f82..5195a5850f 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -168,6 +168,10 @@ _public_ int sd_network_link_get_address_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "ADDRESS_STATE", state);
}
+_public_ int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id) {
+ return network_link_get_string(ifindex, "DHCP4_CLIENT_ID", client_id);
+}
+
_public_ int sd_network_link_get_required_for_online(int ifindex) {
_cleanup_free_ char *s = NULL;
int r;
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 59c2ed278b..dea190eb0d 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -1381,7 +1381,7 @@ static int link_status_one(
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL,
**pop3_server = NULL, **smtp_server = NULL, **lpr_server = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
- _cleanup_free_ char *t = NULL, *network = NULL;
+ _cleanup_free_ char *t = NULL, *network = NULL, *client_id = NULL;
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
const char *on_color_operational, *off_color_operational,
*on_color_setup, *off_color_setup;
@@ -2073,6 +2073,16 @@ static int link_status_one(
return table_log_add_error(r);
}
+ r = sd_network_link_get_dhcp4_client_id_string(info->ifindex, &client_id);
+ if (r >= 0) {
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "DHCP4 Client ID:",
+ TABLE_STRING, client_id);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
r = dump_lldp_neighbors(table, "Connected To:", info->ifindex);
if (r < 0)
return r;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 805aff3ab1..20c5c1c4c8 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -2532,6 +2532,22 @@ static int link_set_ipv6_mtu(Link *link) {
return 0;
}
+static int link_set_ipv4_accept_local(Link *link) {
+ int r;
+
+ if (link->flags & IFF_LOOPBACK)
+ return 0;
+
+ if (link->network->ipv4_accept_local < 0)
+ return 0;
+
+ r = sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface: %m");
+
+ return 0;
+}
+
static bool link_is_static_address_configured(Link *link, Address *address) {
Address *net_address;
@@ -2871,6 +2887,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
+ r = link_set_ipv4_accept_local(link);
+ if (r < 0)
+ return r;
+
r = link_set_flags(link);
if (r < 0)
return r;
@@ -4354,6 +4374,8 @@ int link_save(Link *link) {
if (link->dhcp_lease) {
struct in_addr address;
const char *tz = NULL;
+ size_t client_id_len;
+ const void *client_id;
assert(link->network);
@@ -4368,6 +4390,15 @@ int link_save(Link *link) {
fputc('\n', f);
}
+ r = sd_dhcp_lease_get_client_id(link->dhcp_lease, &client_id, &client_id_len);
+ if (r >= 0) {
+ _cleanup_free_ char *id = NULL;
+
+ r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id);
+ if (r >= 0)
+ fprintf(f, "DHCP4_CLIENT_ID=%s\n", id);
+ }
+
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
if (r < 0)
goto fail;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 3918890664..5c2a4d36a1 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -96,6 +96,7 @@ Network.IPv6DuplicateAddressDetection, config_parse_int,
Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit)
Network.IPv6ProxyNDP, config_parse_tristate, 0, offsetof(Network, ipv6_proxy_ndp)
Network.IPv6MTUBytes, config_parse_mtu, AF_INET6, offsetof(Network, ipv6_mtu)
+Network.IPv4AcceptLocal, config_parse_tristate, 0, offsetof(Network, ipv4_accept_local)
Network.ActiveSlave, config_parse_bool, 0, offsetof(Network, active_slave)
Network.PrimarySlave, config_parse_bool, 0, offsetof(Network, primary_slave)
Network.IPv4ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 124c570b0e..bbecd706ce 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -450,6 +450,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
/* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
.link_local = _ADDRESS_FAMILY_INVALID,
+ .ipv4_accept_local = -1,
+
.ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
.ipv6_accept_ra = -1,
.ipv6_dad_transmits = -1,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 934a33ac94..5901622862 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -237,6 +237,7 @@ struct Network {
AddressFamily ip_forward;
bool ip_masquerade;
+ int ipv4_accept_local;
int ipv6_accept_ra;
int ipv6_dad_transmits;
diff --git a/src/resolve/resolv.conf b/src/resolve/resolv.conf
index c3079aca1d..dc5ac05532 100644
--- a/src/resolve/resolv.conf
+++ b/src/resolve/resolv.conf
@@ -15,4 +15,4 @@
# operation for /etc/resolv.conf.
nameserver 127.0.0.53
-options edns0
+options edns0 trust-ad
diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c
index 97aee7abc8..c6f48d6d88 100644
--- a/src/resolve/resolved-resolv-conf.c
+++ b/src/resolve/resolved-resolv-conf.c
@@ -307,7 +307,7 @@ static int write_stub_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet
"# operation for /etc/resolv.conf.\n"
"\n"
"nameserver 127.0.0.53\n"
- "options edns0\n", f);
+ "options edns0 trust-ad\n", f);
if (!ordered_set_isempty(domains))
write_resolv_conf_search(domains, f);
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index 2637a0f8bb..876f010c95 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -188,6 +188,9 @@ int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes);
/* Get the timezone that was learnt on a specific link. */
int sd_network_link_get_timezone(int ifindex, char **timezone);
+/* Get DHCPv4 client id for a given link. */
+int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id);
+
/* Monitor object */
typedef struct sd_network_monitor sd_network_monitor;
diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c
index 1627bc747d..3ca5e1e639 100644
--- a/src/test/test-parse-util.c
+++ b/src/test/test-parse-util.c
@@ -75,14 +75,22 @@ static void test_parse_mode(void) {
mode_t m;
assert_se(parse_mode("-1", &m) < 0);
+ assert_se(parse_mode("+1", &m) < 0);
assert_se(parse_mode("", &m) < 0);
assert_se(parse_mode("888", &m) < 0);
assert_se(parse_mode("77777", &m) < 0);
assert_se(parse_mode("544", &m) >= 0 && m == 0544);
+ assert_se(parse_mode("0544", &m) >= 0 && m == 0544);
+ assert_se(parse_mode("00544", &m) >= 0 && m == 0544);
assert_se(parse_mode("777", &m) >= 0 && m == 0777);
+ assert_se(parse_mode("0777", &m) >= 0 && m == 0777);
+ assert_se(parse_mode("00777", &m) >= 0 && m == 0777);
assert_se(parse_mode("7777", &m) >= 0 && m == 07777);
+ assert_se(parse_mode("07777", &m) >= 0 && m == 07777);
+ assert_se(parse_mode("007777", &m) >= 0 && m == 07777);
assert_se(parse_mode("0", &m) >= 0 && m == 0);
+ assert_se(parse_mode(" 1", &m) >= 0 && m == 1);
}
static void test_parse_size(void) {
@@ -358,6 +366,18 @@ static void test_safe_atolli(void) {
assert_se(r == 0);
assert_se(l == -12345);
+ r = safe_atolli("0x5", &l);
+ assert_se(r == 0);
+ assert_se(l == 5);
+
+ r = safe_atolli("0o6", &l);
+ assert_se(r == 0);
+ assert_se(l == 6);
+
+ r = safe_atolli("0B101", &l);
+ assert_se(r == 0);
+ assert_se(l == 5);
+
r = safe_atolli("12345678901234567890", &l);
assert_se(r == -ERANGE);
@@ -431,6 +451,14 @@ static void test_safe_atoi16(void) {
assert_se(r == 0);
assert_se(l == 32767);
+ r = safe_atoi16("0o11", &l);
+ assert_se(r == 0);
+ assert_se(l == 9);
+
+ r = safe_atoi16("0B110", &l);
+ assert_se(r == 0);
+ assert_se(l == 6);
+
r = safe_atoi16("36536", &l);
assert_se(r == -ERANGE);
@@ -475,6 +503,13 @@ static void test_safe_atoux16(void) {
r = safe_atoux16(" -1", &l);
assert_se(r == -ERANGE);
+ r = safe_atoux16("0b1", &l);
+ assert_se(r == 0);
+ assert_se(l == 177);
+
+ r = safe_atoux16("0o70", &l);
+ assert_se(r == -EINVAL);
+
r = safe_atoux16("junk", &l);
assert_se(r == -EINVAL);
@@ -500,6 +535,14 @@ static void test_safe_atou64(void) {
assert_se(r == 0);
assert_se(l == 12345);
+ r = safe_atou64("0o11", &l);
+ assert_se(r == 0);
+ assert_se(l == 9);
+
+ r = safe_atou64("0b11", &l);
+ assert_se(r == 0);
+ assert_se(l == 3);
+
r = safe_atou64("18446744073709551617", &l);
assert_se(r == -ERANGE);
@@ -542,6 +585,14 @@ static void test_safe_atoi64(void) {
assert_se(r == 0);
assert_se(l == 32767);
+ r = safe_atoi64(" 0o20", &l);
+ assert_se(r == 0);
+ assert_se(l == 16);
+
+ r = safe_atoi64(" 0b01010", &l);
+ assert_se(r == 0);
+ assert_se(l == 10);
+
r = safe_atoi64("9223372036854775813", &l);
assert_se(r == -ERANGE);
@@ -577,6 +628,13 @@ static void test_safe_atoux64(void) {
assert_se(r == 0);
assert_se(l == 0x12345);
+ r = safe_atoux64("0b11011", &l);
+ assert_se(r == 0);
+ assert_se(l == 11603985);
+
+ r = safe_atoux64("0o11011", &l);
+ assert_se(r == -EINVAL);
+
r = safe_atoux64("18446744073709551617", &l);
assert_se(r == -ERANGE);
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
index 3165232fef..c9bff941be 100644
--- a/src/test/test-user-util.c
+++ b/src/test/test-user-util.c
@@ -42,6 +42,22 @@ static void test_parse_uid(void) {
log_info("/* %s */", __func__);
+ r = parse_uid("0", &uid);
+ assert_se(r == 0);
+ assert_se(uid == 0);
+
+ r = parse_uid("1", &uid);
+ assert_se(r == 0);
+ assert_se(uid == 1);
+
+ r = parse_uid("01", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 1);
+
+ r = parse_uid("001", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 1);
+
r = parse_uid("100", &uid);
assert_se(r == 0);
assert_se(uid == 100);
@@ -54,13 +70,57 @@ static void test_parse_uid(void) {
assert_se(r == -EINVAL);
assert_se(uid == 100);
+ r = parse_uid("0o1234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("0b1234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("+1234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("-1234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid(" 1234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
r = parse_uid("01234", &uid);
- assert_se(r == 0);
- assert_se(uid == 1234);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("001234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("0001234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("-0", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("+0", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("00", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("000", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
r = parse_uid("asdsdas", &uid);
assert_se(r == -EINVAL);
- assert_se(uid == 1234);
+ assert_se(uid == 100);
}
static void test_uid_ptr(void) {
@@ -359,6 +419,39 @@ static void test_gid_lists_ops(void) {
assert_se(gids);
}
+static void test_parse_uid_range(void) {
+ uid_t a = 4711, b = 4711;
+
+ log_info("/* %s */", __func__);
+
+ assert_se(parse_uid_range("", &a, &b) == -EINVAL && a == 4711 && b == 4711);
+ assert_se(parse_uid_range(" ", &a, &b) == -EINVAL && a == 4711 && b == 4711);
+ assert_se(parse_uid_range("x", &a, &b) == -EINVAL && a == 4711 && b == 4711);
+
+ assert_se(parse_uid_range("0", &a, &b) >= 0 && a == 0 && b == 0);
+ assert_se(parse_uid_range("1", &a, &b) >= 0 && a == 1 && b == 1);
+ assert_se(parse_uid_range("2-2", &a, &b) >= 0 && a == 2 && b == 2);
+ assert_se(parse_uid_range("3-3", &a, &b) >= 0 && a == 3 && b == 3);
+ assert_se(parse_uid_range("4-5", &a, &b) >= 0 && a == 4 && b == 5);
+
+ assert_se(parse_uid_range("7-6", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("-1", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("01", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("001", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("+1", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("1--1", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range(" 1", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range(" 1-2", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("1 -2", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("1- 2", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("1-2 ", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("01-2", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("1-02", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("001-2", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range("1-002", &a, &b) == -EINVAL && a == 4 && b == 5);
+ assert_se(parse_uid_range(" 01", &a, &b) == -EINVAL && a == 4 && b == 5);
+}
+
int main(int argc, char *argv[]) {
test_uid_to_name_one(0, "root");
test_uid_to_name_one(UID_NOBODY, NOBODY_USER_NAME);
@@ -396,5 +489,7 @@ int main(int argc, char *argv[]) {
test_in_gid();
test_gid_lists_ops();
+ test_parse_uid_range();
+
return 0;
}
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index a2b8c6162c..6e0ce72553 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -76,6 +76,7 @@ static unsigned arg_children_max = 0;
static usec_t arg_exec_delay_usec = 0;
static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
static int arg_timeout_signal = SIGKILL;
+static bool arg_blockdev_read_only = false;
typedef struct Manager {
sd_event *event;
@@ -383,6 +384,56 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) {
return 1;
}
+static int worker_mark_block_device_read_only(sd_device *dev) {
+ _cleanup_close_ int fd = -1;
+ const char *val;
+ int state = 1, r;
+
+ assert(dev);
+
+ if (!arg_blockdev_read_only)
+ return 0;
+
+ /* Do this only once, when the block device is new. If the device is later retriggered let's not
+ * toggle the bit again, so that people can boot up with full read-only mode and then unset the bit
+ * for specific devices only. */
+ if (!device_for_action(dev, DEVICE_ACTION_ADD))
+ return 0;
+
+ r = sd_device_get_subsystem(dev, &val);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to get subsystem: %m");
+
+ if (!streq(val, "block"))
+ return 0;
+
+ r = sd_device_get_sysname(dev, &val);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to get sysname: %m");
+
+ /* Exclude synthetic devices for now, this is supposed to be a safety feature to avoid modification
+ * of physical devices, and what sits on top of those doesn't really matter if we don't allow the
+ * underlying block devices to recieve changes. */
+ if (STARTSWITH_SET(val, "dm-", "md", "drbd", "loop", "nbd", "zram"))
+ return 0;
+
+ r = sd_device_get_devname(dev, &val);
+ if (r == -ENOENT)
+ return 0;
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to get devname: %m");
+
+ fd = open(val, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
+ if (fd < 0)
+ return log_device_debug_errno(dev, errno, "Failed to open '%s', ignoring: %m", val);
+
+ if (ioctl(fd, BLKROSET, &state) < 0)
+ return log_device_warning_errno(dev, errno, "Failed to mark block device '%s' read-only: %m", val);
+
+ log_device_info(dev, "Successfully marked block device '%s' read-only.", val);
+ return 0;
+}
+
static int worker_process_device(Manager *manager, sd_device *dev) {
_cleanup_(udev_event_freep) UdevEvent *udev_event = NULL;
_cleanup_close_ int fd_lock = -1;
@@ -412,6 +463,8 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
if (r < 0)
return r;
+ (void) worker_mark_block_device_read_only(dev);
+
/* apply rules, create node, symlinks */
r = udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_timeout_signal, manager->properties, manager->rules);
if (r < 0)
@@ -1417,15 +1470,13 @@ static int listen_fds(int *ret_ctrl, int *ret_netlink) {
* udev.children_max=<number of workers> events are fully serialized if set to 1
* udev.exec_delay=<number of seconds> delay execution of every executed program
* udev.event_timeout=<number of seconds> seconds to wait before terminating an event
+ * udev.blockdev_read_only<=bool> mark all block devices read-only when they appear
*/
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
- int r = 0;
+ int r;
assert(key);
- if (!value)
- return 0;
-
if (proc_cmdline_key_streq(key, "udev.log_priority")) {
if (proc_cmdline_value_missing(key, value))
@@ -1457,14 +1508,37 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
r = parse_sec(value, &arg_exec_delay_usec);
} else if (proc_cmdline_key_streq(key, "udev.timeout_signal")) {
+
if (proc_cmdline_value_missing(key, value))
return 0;
r = signal_from_string(value);
if (r > 0)
arg_timeout_signal = r;
- } else if (startswith(key, "udev."))
- log_warning("Unknown udev kernel command line option \"%s\", ignoring", key);
+
+ } else if (proc_cmdline_key_streq(key, "udev.blockdev_read_only")) {
+
+ if (!value)
+ arg_blockdev_read_only = true;
+ else {
+ r = parse_boolean(value);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse udev.blockdev-read-only argument, ignoring: %s", value);
+ else
+ arg_blockdev_read_only = r;
+ }
+
+ if (arg_blockdev_read_only)
+ log_notice("All physical block devices will be marked read-only.");
+
+ return 0;
+
+ } else {
+ if (startswith(key, "udev."))
+ log_warning("Unknown udev kernel command line option \"%s\", ignoring.", key);
+
+ return 0;
+ }
if (r < 0)
log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 7cade0e9ed..478b574418 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -153,6 +153,7 @@ Address=
IPv6ProxyNDPAddress=
IPv6AcceptRA=
IPv6AcceptRouterAdvertisements=
+IPv4AcceptLocal=
DNSSECNegativeTrustAnchors=
MACVTAP=
IPv6PrivacyExtensions=
diff --git a/test/test-network/conf/25-sysctl.network b/test/test-network/conf/25-sysctl.network
index 68be305477..dc1d6542c0 100644
--- a/test/test-network/conf/25-sysctl.network
+++ b/test/test-network/conf/25-sysctl.network
@@ -9,3 +9,4 @@ IPv6HopLimit=5
IPv4ProxyARP=true
IPv6ProxyNDP=true
IPv6AcceptRA=no
+IPv4AcceptLocal=yes
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index da4063d51c..5d08a7584c 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -2203,6 +2203,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
+ self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
def test_sysctl_disable_ipv6(self):
copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
@@ -2354,7 +2355,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
output = check_output('tc qdisc show dev test1')
print(output)
self.assertRegex(output, 'qdisc netem')
- self.assertRegex(output, 'limit 100 delay 50.0ms 10.0ms loss 20%')
+ self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
self.assertRegex(output, 'qdisc ingress')
output = check_output('tc qdisc show dev dummy98')
@@ -2365,9 +2366,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, r'default (0x30|30)')
self.assertRegex(output, 'qdisc netem 30: parent 2:30')
- self.assertRegex(output, 'limit 100 delay 50.0ms 10.0ms loss 20%')
+ self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
self.assertRegex(output, 'qdisc fq_codel')
- self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
+ self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
self.assertRegex(output, 'qdisc teql1 31: parent 2:31')
@@ -2378,13 +2379,13 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'maxrate 1Mbit')
self.assertRegex(output, 'qdisc codel 33: parent 2:33')
- self.assertRegex(output, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
+ self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
self.assertRegex(output, 'qdisc fq_codel 34: parent 2:34')
- self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
+ self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
self.assertRegex(output, 'qdisc tbf 35: parent 2:35')
- self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
+ self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
self.assertRegex(output, 'qdisc sfq 36: parent 2:36')
self.assertRegex(output, 'perturb 5sec')
diff --git a/tools/gdb-sd_dump_hashmaps.py b/tools/gdb-sd_dump_hashmaps.py
index 4e8593f320..66018a54fd 100644
--- a/tools/gdb-sd_dump_hashmaps.py
+++ b/tools/gdb-sd_dump_hashmaps.py
@@ -1,79 +1,77 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1+
-from __future__ import print_function
-
import gdb
class sd_dump_hashmaps(gdb.Command):
- "dump systemd's hashmaps"
-
- def __init__(self):
- super(sd_dump_hashmaps, self).__init__("sd_dump_hashmaps", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
-
- def invoke(self, arg, from_tty):
- d = gdb.parse_and_eval("hashmap_debug_list")
- all_entry_sizes = gdb.parse_and_eval("all_entry_sizes")
- all_direct_buckets = gdb.parse_and_eval("all_direct_buckets")
- uchar_t = gdb.lookup_type("unsigned char")
- ulong_t = gdb.lookup_type("unsigned long")
- debug_offset = gdb.parse_and_eval("(unsigned long)&((HashmapBase*)0)->debug")
-
- print("type, hash, indirect, entries, max_entries, buckets, creator")
- while d:
- h = gdb.parse_and_eval("(HashmapBase*)((char*)%d - %d)" % (int(d.cast(ulong_t)), debug_offset))
-
- if h["has_indirect"]:
- storage_ptr = h["indirect"]["storage"].cast(uchar_t.pointer())
- n_entries = h["indirect"]["n_entries"]
- n_buckets = h["indirect"]["n_buckets"]
- else:
- storage_ptr = h["direct"]["storage"].cast(uchar_t.pointer())
- n_entries = h["n_direct_entries"]
- n_buckets = all_direct_buckets[int(h["type"])];
-
- t = ["plain", "ordered", "set"][int(h["type"])]
-
- print("{}, {}, {}, {}, {}, {}, {} ({}:{})".format(t, h["hash_ops"], bool(h["has_indirect"]), n_entries, d["max_entries"], n_buckets, d["func"], d["file"], d["line"]))
-
- if arg != "" and n_entries > 0:
- dib_raw_addr = storage_ptr + (all_entry_sizes[h["type"]] * n_buckets)
-
- histogram = {}
- for i in xrange(0, n_buckets):
- dib = int(dib_raw_addr[i])
- histogram[dib] = histogram.get(dib, 0) + 1
-
- for dib in sorted(iter(histogram)):
- if dib != 255:
- print("{:>3} {:>8} {} of entries".format(dib, histogram[dib], 100.0*histogram[dib]/n_entries))
- else:
- print("{:>3} {:>8} {} of slots".format(dib, histogram[dib], 100.0*histogram[dib]/n_buckets))
- print("mean DIB of entries: {}".format(sum([dib*histogram[dib] for dib in iter(histogram) if dib != 255])*1.0/n_entries))
-
- blocks = []
- current_len = 1
- prev = int(dib_raw_addr[0])
- for i in xrange(1, n_buckets):
- dib = int(dib_raw_addr[i])
- if (dib == 255) != (prev == 255):
- if prev != 255:
- blocks += [[i, current_len]]
- current_len = 1
- else:
- current_len += 1
-
- prev = dib
- if prev != 255:
- blocks += [[i, current_len]]
- # a block may be wrapped around
- if len(blocks) > 1 and blocks[0][0] == blocks[0][1] and blocks[-1][0] == n_buckets - 1:
- blocks[0][1] += blocks[-1][1]
- blocks = blocks[0:-1]
- print("max block: {}".format(max(blocks, key=lambda a: a[1])))
- print("sum block lens: {}".format(sum(b[1] for b in blocks)))
- print("mean block len: {}".format((1.0 * sum(b[1] for b in blocks) / len(blocks))))
-
- d = d["debug_list_next"]
+ "dump systemd's hashmaps"
+
+ def __init__(self):
+ super().__init__("sd_dump_hashmaps", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
+
+ def invoke(self, arg, from_tty):
+ d = gdb.parse_and_eval("hashmap_debug_list")
+ hashmap_type_info = gdb.parse_and_eval("hashmap_type_info")
+ uchar_t = gdb.lookup_type("unsigned char")
+ ulong_t = gdb.lookup_type("unsigned long")
+ debug_offset = gdb.parse_and_eval("(unsigned long)&((HashmapBase*)0)->debug")
+
+ print("type, hash, indirect, entries, max_entries, buckets, creator")
+ while d:
+ h = gdb.parse_and_eval(f"(HashmapBase*)((char*){int(d.cast(ulong_t))} - {debug_offset})")
+
+ if h["has_indirect"]:
+ storage_ptr = h["indirect"]["storage"].cast(uchar_t.pointer())
+ n_entries = h["indirect"]["n_entries"]
+ n_buckets = h["indirect"]["n_buckets"]
+ else:
+ storage_ptr = h["direct"]["storage"].cast(uchar_t.pointer())
+ n_entries = h["n_direct_entries"]
+ n_buckets = hashmap_type_info[h["type"]]["n_direct_buckets"]
+
+ t = ["plain", "ordered", "set"][int(h["type"])]
+
+ print(f'{t}, {h["hash_ops"]}, {bool(h["has_indirect"])}, {n_entries}, {d["max_entries"]}, {n_buckets}, {d["func"].string()}, {d["file"].string()}:{d["line"]}')
+
+ if arg != "" and n_entries > 0:
+ dib_raw_addr = storage_ptr + hashmap_type_info[h["type"]]["entry_size"] * n_buckets
+
+ histogram = {}
+ for i in range(0, n_buckets):
+ dib = int(dib_raw_addr[i])
+ histogram[dib] = histogram.get(dib, 0) + 1
+
+ for dib in sorted(histogram):
+ if dib != 255:
+ print(f"{dib:>3} {histogram[dib]:>8} {float(histogram[dib]/n_entries):.0%} of entries")
+ else:
+ print(f"{dib:>3} {histogram[dib]:>8} {float(histogram[dib]/n_buckets):.0%} of slots")
+ s = sum(dib*count for (dib, count) in histogram.items() if dib != 255) / n_entries
+ print(f"mean DIB of entries: {s}")
+
+ blocks = []
+ current_len = 1
+ prev = int(dib_raw_addr[0])
+ for i in range(1, n_buckets):
+ dib = int(dib_raw_addr[i])
+ if (dib == 255) != (prev == 255):
+ if prev != 255:
+ blocks += [[i, current_len]]
+ current_len = 1
+ else:
+ current_len += 1
+
+ prev = dib
+ if prev != 255:
+ blocks += [[i, current_len]]
+ # a block may be wrapped around
+ if len(blocks) > 1 and blocks[0][0] == blocks[0][1] and blocks[-1][0] == n_buckets - 1:
+ blocks[0][1] += blocks[-1][1]
+ blocks = blocks[0:-1]
+ print("max block: {}".format(max(blocks, key=lambda a: a[1])))
+ print("sum block lens: {}".format(sum(b[1] for b in blocks)))
+ print("mean block len: {}".format(sum(b[1] for b in blocks) / len(blocks)))
+
+ d = d["debug_list_next"]
sd_dump_hashmaps()
diff --git a/units/initrd-udevadm-cleanup-db.service b/units/initrd-udevadm-cleanup-db.service
index ad2f2a5b35..810cf5775e 100644
--- a/units/initrd-udevadm-cleanup-db.service
+++ b/units/initrd-udevadm-cleanup-db.service
@@ -8,7 +8,7 @@
# (at your option) any later version.
[Unit]
-Description=Cleanup udevd DB
+Description=Cleanup udev Database
DefaultDependencies=no
ConditionPathExists=/etc/initrd-release
Conflicts=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udev-trigger.service systemd-udev-settle.service
diff --git a/units/systemd-udev-settle.service b/units/systemd-udev-settle.service
index ed6a68b864..9352c6f598 100644
--- a/units/systemd-udev-settle.service
+++ b/units/systemd-udev-settle.service
@@ -12,7 +12,7 @@
# expect a populated /dev during bootup.
[Unit]
-Description=udev Wait for Complete Device Initialization
+Description=Wait for udev To Complete Device Initialization
Documentation=man:systemd-udev-settle.service(8)
DefaultDependencies=no
Wants=systemd-udevd.service
diff --git a/units/systemd-udev-trigger.service b/units/systemd-udev-trigger.service
index 8a625b6305..cfe8d61c2a 100644
--- a/units/systemd-udev-trigger.service
+++ b/units/systemd-udev-trigger.service
@@ -8,7 +8,7 @@
# (at your option) any later version.
[Unit]
-Description=udev Coldplug all Devices
+Description=Coldplug All udev Devices
Documentation=man:udev(7) man:systemd-udevd.service(8)
DefaultDependencies=no
Wants=systemd-udevd.service