There is g_variant_equal(), which can handle all variant types (however
that is not a compare function).
There is g_variant_compare(), which is a compare function but only works for
basic types.
Add nm_g_variant_cmp() which works with all variant types.
This is based on nm_property_compare(), with some differences:
- nm_property_compare() tries (wrongly) to accept string dictionaries in
any order. That functionality seems wrong, and nm_g_variant_cmp()
doesn't do that.
- nm_property_compare() does possibly not support all variant types.
This can be a problem, if we call the function on untrusted data
(and it can be hard to validate first, whether the function can
be called with a particular variant). Instead, nm_g_variant_cmp()
should work with all variants.
The unit tests are copied from "src/libnm-core-impl/tests/test-compare.c"
with some adjustments (because nm_property_compare() is not the same as
nm_g_variant_cmp()).
Note that the code is actually unused. It was written as replacement for
nm_property_compare(), but turns out not to be used there. For now,
leave it, because it might still be useful to have in the toolbox and it
exists (including tests).
Glib's MIN()/MAX() should not be used, in favor of NM_MIN()/NM_MAX().
That's because the NM variants
- evaluate arguments only once
- have a static assertion that the signedness of the arguments matches
However, previously those macros never evaluated to a compile time
constant. Unlike the glib variants, which do so when the arguments are
compile time constants. That is sometimes important when using the
macros in a context that requires a constant.
Extend NM_MIN()/NM_MAX() to be a compile time constant, when possible.
Note that there are still a few places where NM_MIN()/NM_MAX() cannot be
used due to the expression statement. For those cases, there is
NM_MIN_CONST()/NM_MAX_CONST().
Calling getpwuid_r() is cumbersome, because it has a separate passwd and
string buffer, and you shall retry, when the buffer is too small.
Extract nm_getpwuid() for that. This one always allocates a suitable
buffer, that the caller can free.
This will allow callers to get the full passwd struct. It will also
allow callers to avoid the additional strdup() of nm_utils_uid_to_name(),
when we don't need a clone of the string.
nm_inet_parse_bin_full() supports a legacy mode for IPv4, which used
inet_aton(). This is only used by initrd reader, which parses the
kernel command line as defined by dracut. Since that dracut API is old
and not defined by us, we want to be more forgiving in case a user
specifies something that used to work in the past. In particular,
we want to parse "255.256.256.000" as netmask (which inet_pton() would
reject).
inet_aton() trips off some ABI checkers that we shouldn't use this ABI.
It was anyway only used as *additional* guard when we parsed certain
legacy formats for IPv4 addresses. We can drop that and just use our
parser.
Note that there is still an nm_assert() path, which loads inet_aton()
dynamically, just to ensure that our legacy parser implementation is in
agree with inet_aton().
https://bugzilla.redhat.com/show_bug.cgi?id=2049134
This is the version shipped in Fedora 37. As Fedora 37 is now out, the
core developers switch to it. Our gitlab-ci will also use that as base
image for the check-{patch.tree} tests and to generate the pages. There
is a need that everybody agrees on which clang-format version to use,
and that version should be the one of the currently used Fedora release.
Also update the used Fedora image in "contrib/scripts/nm-code-format-container.sh"
script.
The gitlab-ci still needs update in the following commit. The change
in isolation will break the "check-tree" test.
For g_assert() and g_return*() we already do the same, in
"src/libnm-glib-aux/nm-gassert-patch.h"
Also patch __assert_fail() so that it omits the condition text and the
function name in production builds.
Note that this is a bit ugly, for two reasons:
- again, we make assumptions that __assert_fail() exists. In practice,
this is the case for glibc and musl.
- <assert.h> can be included multiple times, while also forward
declaring __assert_fail(). That means, we cannot add a macro
#define __assert_fail(...)
because that would break the forward declaration. Instead,
just `#define __assert_fail _nm_assert_fail_internal`
Of course, this only affects direct calls to assert(), which we have
few. nm_assert() is not affected, because that anyway doesn't do
anything, unless NM_MORE_ASSERTS is enabled.
Taken from systemd's "Prioq".
Differences from Prioq:
- It is glib-ized, so certain operations cannot fail since g_malloc()
never fails.
- Unlike Prioq, this structure is stack allocated. I think that makes
sense, because we basically always want to embed the data structure
in another object. There is never a need for passing this around as a
pointer. And if you really want, you can box it yourself.
- The queue either accepts a GCompareFunc or a GComareDataFunc. This
is for convenience. The prioq_ensure_allocated() and
prioq_ensure_put() consequently are dropped, as they would be
cumbersome with this pattern and don't seem useful.
NMStrBuf can also contains NUL characters. We thus cannot use g_strndup(),
which uses strncpy() and truncates at the first NUL.
Fixes: 13d25f9d0b ('glib-aux: add support for starting with stack-allocated buffer in NMStrBuf')
Add nm_g_array_index() as a replacement for g_array_index(). The value
of nm_g_array_index(), nm_g_array_index_p(), nm_g_array_first() and
nm_g_array_last() is that they add nm_assert() checks for valid
parameters.
nm_g_array_{first,last}() now returns an lvalue and not a pointer.
As such, they are just shorthands for nm_g_array_index() at index
0 and len-1, respectively.
`nm_g_array_index_p(arr, Type, idx)` is almost the same as
`&nm_g_array_index(arr, Type, idx)`. The only difference (and why the
former variant exists), is that nm_g_array_index_p() allows to get a
pointer one after the end.
This means, this is correct and valid to do:
// arr->len might be zero
arr = nm_g_array_index_p(arr, Type, 0);
for (i = 0; i < arr->len; i++, arr++)
...
ptr = nm_g_array_index_p(arr, Type, 0);
end = nm_g_array_index_p(arr, Type, arr->len);
for (; ptr < end; ptr++)
...
This would not be valid to do with nm_g_array_{index,first,last}().
Also fix supporting "const GArray *arr" parameter. Of course, the function
casts the constness away. Technically, that matches the fact that arr->data
is also not a const pointer. In practice, we might want to propagate the
constness of the container to the constness of the element lookup. While
doable, that is not implemented.
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
Heavily inspired by systemd ([1]).
We now also have nm_random_get_bytes{,_full}() and
nm_random_get_crypto_bytes(), like systemd's random_bytes()
and crypto_random_bytes(), respectively.
Differences:
- instead of systemd's random_bytes(), our nm_random_get_bytes_full()
also estimates whether the output is of high quality. The caller
may find that interesting. Due to that, we will first try to call
getrandom(GRND_NONBLOCK) before getrandom(GRND_INSECURE). That is
reversed from systemd's random_bytes(), because we want to find
out whether we can get good random numbers. In most cases, kernel
should have entropy already, and it makes no difference.
Otherwise, heavily rework the code. It should be easy to understand
and correct.
There is also a major bugfix here. Previously, if getrandom() failed
with ENOSYS and we fell back to /dev/urandom, we would assume that we
have high quality random numbers. That assumption is not warranted.
Now instead poll on /dev/random to find out.
[1] a268e7f402/src/basic/random-util.c (L81)
On m68k, integers are 2-byte aligned. Hence the assertion was wrong.
What we really want to check, is that NMIPAddr has not a smaller
alignment than in_addr_t and similar.
While at it, also assert the alignment for NMEtherAddr.
NM_STR_BUF_INIT() and nm_str_buf_init() were pretty much redundant. Drop one of
them.
Usually our pattern is that we don't have functions that return structs.
But NM_STR_BUF_INIT() returns a struct, because it's convenient to use
with
nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(...);
So use that variant instead.
Allow to initialize NMStrBuf with an externally allocated array.
Usually a stack buffer. If the NMStrBuf grows beyond the size of
that initial buffer, then it would switch using malloc.
The idea is to support the common case where the result is small enough
to fit on the stack.
I always wanted to do such optimization because the main purpose of
NMStrBuf is to put it on the stack and ad-hoc construct a string.
I just figured, it would complicate the implementation and add
a runtime overhead. But turns out, it doesn't really.
The biggest question is how NMStrBuf should behave with a pre-allocated
buffer? Turns out, most choices can be made in a rather obvious way.
The only non-obvious thing is that nm_str_buf_finalize() would malloc()
a buffer, but that too seems consistent and what a user would probably
expect. As such, this doesn't seem to add unexpected semantics to the API.
On glibc, HOST_NAME_MAX is defined as 64. Also, Linux'
sethostname() enforces that limit (__NEW_UTS_LEN). Also,
`man gethostname` comments that HOST_NAME_MAX on Linux is
64.
However, when building against musl, HOST_NAME_MAX is defined as 255.
That seems wrong. We use this limit to validate the hostname, and that
should not depend on the libc or on the compilation.
Hardcode the value to 64.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1197
nm_hostname_is_valid() determines the valid length based on
HOST_NAME_MAX, which is defined differently for glibc and musl.
Fixes: 9ff1f66680 ('glib-aux: add nm_hostname_is_valid() helper from systemd')
We use these functions, currently from our systemd fork. One day we want
to stop importing systemd code, so we need them ourselves.
Copy them, and adjust for NM style.
We write lease files for internal DHCP client ("systemd" and "nettools")
in a systemd-specific format. We want to drop systemd code, so we need
to have our own parsing code.
Granted, nettools only writes a single "ADDRESS=" line, so parsing that
would be easy. On the other hand, systemd's parser is not complicated
either (in particular, if we can steal their implementation). Also, it's
a commonly used format in systemd, so having the parser would allow us
to parse similar formats.
Also, we could opt to choose that format, where it makes sense.
We use clang-format for automatic formatting of our source files.
Since clang-format is actively maintained software, the actual
formatting depends on the used version of clang-format. That is
unfortunate and painful, but really unavoidable unless clang-format
would be strictly bug-compatible.
So the version that we must use is from the current Fedora release, which
is also tested by our gitlab-ci. Previously, we were using Fedora 34 with
clang-tools-extra-12.0.1-1.fc34.x86_64.
As Fedora 35 comes along, we need to update our formatting as Fedora 35
comes with version "13.0.0~rc1-1.fc35".
An alternative would be to freeze on version 12, but that has different
problems (like, it's cumbersome to rebuild clang 12 on Fedora 35 and it
would be cumbersome for our developers which are on Fedora 35 to use a
clang that they cannot easily install).
The (differently painful) solution is to reformat from time to time, as we
switch to a new Fedora (and thus clang) version.
Usually we would expect that such a reformatting brings minor changes.
But this time, the changes are huge. That is mentioned in the release
notes [1] as
Makes PointerAligment: Right working with AlignConsecutiveDeclarations. (Fixes https://llvm.org/PR27353)
[1] https://releases.llvm.org/13.0.0/tools/clang/docs/ReleaseNotes.html#clang-format
Naming is important, because the name of a thing should give you a good
idea what it does. Also, to find a thing, it needs a good name in the
first place. But naming is also hard.
Historically, some strv helper API was named as nm_utils_strv_*(),
and some API had a leading underscore (as it is internal API).
This was all inconsistent. Do some renaming and try to unify things.
We get rid of the leading underscore if this is just a regular
(internal) helper. But not for example from _nm_strv_find_first(),
because that is the implementation of nm_strv_find_first().
- _nm_utils_strv_cleanup() -> nm_strv_cleanup()
- _nm_utils_strv_cleanup_const() -> nm_strv_cleanup_const()
- _nm_utils_strv_cmp_n() -> _nm_strv_cmp_n()
- _nm_utils_strv_dup() -> _nm_strv_dup()
- _nm_utils_strv_dup_packed() -> _nm_strv_dup_packed()
- _nm_utils_strv_find_first() -> _nm_strv_find_first()
- _nm_utils_strv_sort() -> _nm_strv_sort()
- _nm_utils_strv_to_ptrarray() -> nm_strv_to_ptrarray()
- _nm_utils_strv_to_slist() -> nm_strv_to_gslist()
- nm_utils_strv_cmp_n() -> nm_strv_cmp_n()
- nm_utils_strv_dup() -> nm_strv_dup()
- nm_utils_strv_dup_packed() -> nm_strv_dup_packed()
- nm_utils_strv_dup_shallow_maybe_a() -> nm_strv_dup_shallow_maybe_a()
- nm_utils_strv_equal() -> nm_strv_equal()
- nm_utils_strv_find_binary_search() -> nm_strv_find_binary_search()
- nm_utils_strv_find_first() -> nm_strv_find_first()
- nm_utils_strv_make_deep_copied() -> nm_strv_make_deep_copied()
- nm_utils_strv_make_deep_copied_n() -> nm_strv_make_deep_copied_n()
- nm_utils_strv_make_deep_copied_nonnull() -> nm_strv_make_deep_copied_nonnull()
- nm_utils_strv_sort() -> nm_strv_sort()
Note that no names are swapped and none of the new names existed
previously. That means, all the new names are really new, which
simplifies to find errors due to this larger refactoring. E.g. if
you backport a patch from after this change to an old branch, you'll
get a compiler error and notice that something is missing.
These functions have overlap with g_ascii_is*() functions.
However g_ascii_is*() (and the is* functions from <ctype.h>) are
always confusing to me, in the sense that it's not clearly stated
which characters qualify for a certain category. And review is not
easy either, because they are implemented via a table lookup.
E.g. were you aware that 127 is considered g_ascii_iscntrl()? Probably
you were, but it's not clear to see that anywhere.
The main point of our own functions is to have is easier to see how
characters get categorized, by using comparison instead of table lookup.
Also, several existing code did in fact not use the g_ascii_is*()
macros, possibly because of the (perceived) difficulty to understand
their exact meaning. As a consequence, several checks got wrong.
For example, (ch < ' ') is not a valid check for testing whether
the character is a ASCII control character, for two reasons:
- if char is a signed type (as likely it is), then this also evaluates
to TRUE for all non-ASCII, UTF-8 characters that are greater than
127.
- it does not consider DEL character (127) a control character.
Replace NM_STATIC_ASSERT_EXPR() by NM_STATIC_ASSERT_EXPR_1() and
NM_STATIC_ASSERT_EXPR_VOID(). NM_STATIC_ASSERT_EXPR_VOID() can be
used as an expression that returns void (that is, a simple statement).
On the other hand, NM_STATIC_ASSERT_EXPR_1() itself retuns
a compile time constant of int value 1. The latter is useful, because
we can use the 1 to combine static assertions in expressions that
are themself compile time constants, like
#define STATIC_CHECK_AND_GET(cond, value) \
(NM_STATIC_ASSERT_EXPR_1(cond) ? (value) : (value))
This is itself a compile time constant if value is a compile
time constant. Also, it does the compile time check that "cond"
is true.
Coverity wrongly think there is a use after free in the test:
Error: USE_AFTER_FREE (CWE-416): [#def559] [important]
NetworkManager-1.31.90/src/libnm-glib-aux/tests/test-shared-general.c:1305: alias: Assigning: "s1" = "_s". Now both point to the same storage.
NetworkManager-1.31.90/src/libnm-glib-aux/tests/test-shared-general.c:1324: freed_arg: "g_source_unref" frees "s1".
NetworkManager-1.31.90/src/libnm-glib-aux/tests/test-shared-general.c:1330: deref_after_free: Dereferencing freed pointer "s1".
# 1328| s2 = nm_g_source_sentinel_get(0);
# 1329| g_assert(s2 == s1);
# 1330|-> g_assert_cmpint(g_atomic_int_get(&s1->ref_count), >=, 1);
# 1331| }
# 1332| }
Rework the code in the hope to avoid the false warning.
(cherry picked from commit 7825609f1f)
This helper is useful to get a dummy GSource instance that can be
refed, unrefed and destroyed. It can act as a replacement for
a timeout source with infinite timeout.
Imaging you track a list of NMRefString instances. You could
directly expose them as strv array, but then you need a way
from the string back to the NMRefString instance.
That's easy to do. Add NM_REF_STRING_UPCAST() for that.
Avoid dependencies but explicitly link the static library where it is
used.
This also fixes that we linked libnm-log-core into
libnm-settings-plugin-ifcfg-rh.so, which duplicated the symbols
while it should used them from NetworkManager.