summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-07-13 23:40:46 +0200
committerThomas Haller <thaller@redhat.com>2020-07-13 23:40:48 +0200
commit7b14686ae2b0d610661af1958062c5388c0cb6bf (patch)
treefc9be8c6b5758ca10fd59d28549f46d8a44f68a8 /shared
parent8582a5f356b758b9fc44f977fbad10132fcbd926 (diff)
parent5542275672672299860117f6cc3c5b8e234bd8dc (diff)
downloadNetworkManager-1.27.1-dev.tar.gz
release: bump version to 1.27.1 (development)1.27.1-dev
Diffstat (limited to 'shared')
-rw-r--r--shared/c-siphash/src/c-siphash.c2
-rw-r--r--shared/c-stdaux/src/test-basic.c2
-rw-r--r--shared/meson.build16
-rw-r--r--shared/n-acd/src/n-acd-probe.c4
-rw-r--r--shared/n-acd/src/n-acd.c4
-rw-r--r--shared/n-acd/src/test.h2
-rw-r--r--shared/n-acd/src/util/timer.c2
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-connection.c2
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-lease.c8
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-probe.c18
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-client.c8
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-private.h2
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-s-connection.c2
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-socket.c8
-rw-r--r--shared/n-dhcp4/src/test-run-client.c2
-rw-r--r--shared/n-dhcp4/src/test.h2
-rw-r--r--shared/n-dhcp4/src/util/packet.c2
-rw-r--r--shared/nm-default.h2
-rw-r--r--shared/nm-glib-aux/nm-errno.c4
-rw-r--r--shared/nm-glib-aux/nm-hash-utils.h2
-rw-r--r--shared/nm-glib-aux/nm-io-utils.c2
-rw-r--r--shared/nm-glib-aux/nm-io-utils.h2
-rw-r--r--shared/nm-glib-aux/nm-jansson.h105
-rw-r--r--shared/nm-glib-aux/nm-json-aux.c157
-rw-r--r--shared/nm-glib-aux/nm-json-aux.h297
-rw-r--r--shared/nm-glib-aux/nm-macros-internal.h604
-rw-r--r--shared/nm-glib-aux/nm-ref-string.c4
-rw-r--r--shared/nm-glib-aux/nm-secret-utils.h4
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.c290
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.h115
-rw-r--r--shared/nm-glib-aux/nm-str-buf.h118
-rw-r--r--shared/nm-glib-aux/tests/meson.build42
-rw-r--r--shared/nm-glib-aux/tests/test-json-aux.c163
-rw-r--r--shared/nm-glib-aux/tests/test-shared-general.c106
-rw-r--r--shared/nm-std-aux/nm-std-aux.h621
-rw-r--r--shared/nm-std-aux/nm-std-utils.c76
-rw-r--r--shared/nm-std-aux/nm-std-utils.h36
-rw-r--r--shared/nm-test-utils-impl.c2
-rw-r--r--shared/nm-version-macros.h.in1
-rw-r--r--shared/systemd/nm-sd-utils-shared.c2
-rw-r--r--shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h2
-rw-r--r--shared/systemd/src/basic/process-util.c2
-rw-r--r--shared/systemd/src/basic/random-util.c2
-rw-r--r--shared/systemd/src/basic/socket-util.c2
44 files changed, 1838 insertions, 1011 deletions
diff --git a/shared/c-siphash/src/c-siphash.c b/shared/c-siphash/src/c-siphash.c
index fae3abadd7..720e403a43 100644
--- a/shared/c-siphash/src/c-siphash.c
+++ b/shared/c-siphash/src/c-siphash.c
@@ -227,7 +227,7 @@ _c_public_ uint64_t c_siphash_finalize(CSipHash *state) {
*
* CSipHash state;
* c_siphash_init(&state, seed);
- * c_siphash_apend(&state, bytes, n_bytes);
+ * c_siphash_append(&state, bytes, n_bytes);
* return c_siphash_finalize(&state);
*
* Unlike the streaming API, this is a one-shot call suitable for any data that
diff --git a/shared/c-stdaux/src/test-basic.c b/shared/c-stdaux/src/test-basic.c
index 291a8e199b..9549a14303 100644
--- a/shared/c-stdaux/src/test-basic.c
+++ b/shared/c-stdaux/src/test-basic.c
@@ -203,7 +203,7 @@ static void test_misc(int non_constant_expr) {
/*
* Div Round Up: Normal division, but round up to next integer, instead
* of clipping. Also verify that it does not suffer from the integer
- * overflow in the prevalant, alternative implementation:
+ * overflow in the prevalent, alternative implementation:
* [(x + y - 1) / y].
*/
{
diff --git a/shared/meson.build b/shared/meson.build
index 48880ec4f6..0f46a00cbb 100644
--- a/shared/meson.build
+++ b/shared/meson.build
@@ -113,15 +113,17 @@ nm_test_utils_impl_source = files('nm-test-utils-impl.c')
nm_vpn_plugin_utils_source = files('nm-utils/nm-vpn-plugin-utils.c')
-c_flags = [
- '-DG_LOG_DOMAIN="@0@"'.format(libnm_name),
- '-DNETWORKMANAGER_COMPILATION=0',
-]
-
libnm_std_aux = static_library(
'nm-std-aux',
- sources: 'nm-std-aux/c-list-util.c',
- c_args: c_flags,
+ sources: [
+ 'nm-std-aux/c-list-util.c',
+ 'nm-std-aux/nm-std-utils.c',
+ ],
+ include_directories: top_inc,
+ c_args: [
+ '-DG_LOG_DOMAIN="@0@"'.format(libnm_name),
+ '-DNETWORKMANAGER_COMPILATION=0',
+ ],
)
sources = files(
diff --git a/shared/n-acd/src/n-acd-probe.c b/shared/n-acd/src/n-acd-probe.c
index 43dd344c38..2a5c645192 100644
--- a/shared/n-acd/src/n-acd-probe.c
+++ b/shared/n-acd/src/n-acd-probe.c
@@ -682,7 +682,7 @@ _c_public_ void n_acd_probe_get_userdata(NAcdProbe *probe, void **userdatap) {
/**
* n_acd_probe_announce() - announce the configured IP address
* @probe: probe to operate on
- * @defend: defence policy
+ * @defend: defense policy
*
* Announce the IP address on the local link, and start defending it according
* to the given policy, which mut be one of N_ACD_DEFEND_ONCE,
@@ -691,7 +691,7 @@ _c_public_ void n_acd_probe_get_userdata(NAcdProbe *probe, void **userdatap) {
* This must be called in response to an N_ACD_EVENT_READY event, and only
* after the given address has been configured on the given network interface.
*
- * Return: 0 on success, N_ACD_E_INVALID_ARGUMENT in case the defence policy
+ * Return: 0 on success, N_ACD_E_INVALID_ARGUMENT in case the defense policy
* is invalid, negative error code on failure.
*/
_c_public_ int n_acd_probe_announce(NAcdProbe *probe, unsigned int defend) {
diff --git a/shared/n-acd/src/n-acd.c b/shared/n-acd/src/n-acd.c
index af3328c141..c1d9286503 100644
--- a/shared/n-acd/src/n-acd.c
+++ b/shared/n-acd/src/n-acd.c
@@ -578,11 +578,11 @@ static int n_acd_handle_timeout(NAcd *acd) {
int r;
/*
- * Read the current time once, and handle all timouts that triggered
+ * Read the current time once, and handle all timeouts that triggered
* before the current time. Rereading the current time in each loop
* might risk creating a live-lock, and the fact that we read the
* time after reading the timer guarantees that the timeout which
- * woke us up is hanlded.
+ * woke us up is handled.
*
* When there are no more timeouts to handle at the given time, we
* rearm the timer to potentially wake us up again in the future.
diff --git a/shared/n-acd/src/test.h b/shared/n-acd/src/test.h
index 4c6ffebb6a..69a786a013 100644
--- a/shared/n-acd/src/test.h
+++ b/shared/n-acd/src/test.h
@@ -191,7 +191,7 @@ static inline void test_setup(void) {
/*
* Move into a new network and mount namespace both associated
* with a new user namespace where the current eUID is mapped to
- * 0. Then create a a private instance of /run/netns. This ensures
+ * 0. Then create a private instance of /run/netns. This ensures
* that any network devices or network namespaces are private to
* the test process.
*/
diff --git a/shared/n-acd/src/util/timer.c b/shared/n-acd/src/util/timer.c
index 3c9570a1e8..af2a887cea 100644
--- a/shared/n-acd/src/util/timer.c
+++ b/shared/n-acd/src/util/timer.c
@@ -55,7 +55,7 @@ void timer_rearm(Timer *timer) {
int r;
/*
- * A timeout value of 0 clears the timer, we sholud only set that if
+ * A timeout value of 0 clears the timer, we should only set that if
* no timeout exists in the tree.
*/
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-connection.c b/shared/n-dhcp4/src/n-dhcp4-c-connection.c
index 8c32a984dd..6becfb5087 100644
--- a/shared/n-dhcp4/src/n-dhcp4-c-connection.c
+++ b/shared/n-dhcp4/src/n-dhcp4-c-connection.c
@@ -1236,7 +1236,7 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
/*
* Remember the start time of the transaction, and the base
* time of any relative timestamps from the pending request.
- * Thes same times applies to the response, and sholud be
+ * The same time applies to the response, and should be
* copied over.
*/
message->userdata.start_time = connection->request->userdata.start_time;
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-lease.c b/shared/n-dhcp4/src/n-dhcp4-c-lease.c
index 695a112ab7..6d9b4f3340 100644
--- a/shared/n-dhcp4/src/n-dhcp4-c-lease.c
+++ b/shared/n-dhcp4/src/n-dhcp4-c-lease.c
@@ -2,7 +2,7 @@
* DHCP4 Client Leases
*
* This implements the public API wrapping DHCP4 client leases. A lease object
- * conists of the information given to us from the server, together with the
+ * consists of the information given to us from the server, together with the
* timestamp recording the start of the validity of the lease.
*
* A probe may yield many OFFERS, each of which contains a lease object. One of
@@ -98,7 +98,7 @@ static int n_dhcp4_incoming_get_timeouts(NDhcp4Incoming *message, uint64_t *t1p,
/**
* n_dhcp4_client_lease_new() - allocate new client lease object
- * @leasep: output argumnet for new client lease object
+ * @leasep: output argument for new client lease object
* @message: incoming message representing the lease
*
* This creates a new client lease object. Client lease objects are simple
@@ -194,7 +194,7 @@ void n_dhcp4_client_lease_unlink(NDhcp4ClientLease *lease) {
* @lease: the lease to operate on
* @yiaddr: return argument for the IP address
*
- * Gets the IP address cotained in the lease. Or INADDR_ANY if the lease
+ * Gets the IP address contained in the lease. Or INADDR_ANY if the lease
* does not contain an IP address.
*/
_c_public_ void n_dhcp4_client_lease_get_yiaddr(NDhcp4ClientLease *lease, struct in_addr *yiaddr) {
@@ -208,7 +208,7 @@ _c_public_ void n_dhcp4_client_lease_get_yiaddr(NDhcp4ClientLease *lease, struct
* @lease: the lease to operate on
* @siaddr: return argument for the IP address
*
- * Gets the server IP address cotained in the lease. Or INADDR_ANY if the
+ * Gets the server IP address contained in the lease. Or INADDR_ANY if the
* lease does not contain an IP address.
*/
_c_public_ void n_dhcp4_client_lease_get_siaddr(NDhcp4ClientLease *lease, struct in_addr *siaddr) {
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-probe.c b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
index f3d4f265c6..7f20ac0527 100644
--- a/shared/n-dhcp4/src/n-dhcp4-c-probe.c
+++ b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
@@ -221,7 +221,7 @@ _c_public_ void n_dhcp4_client_probe_config_set_requested_ip(NDhcp4ClientProbeCo
* delay is specified to be a random value in the range 1000 to 10.000 ms.
* However, there does not appear to be any particular reason to
* unconditionally wait at least one second, so we move the range down to
- * start at 0 ms. The reaon for the random delay is to avoid network-wide
+ * start at 0 ms. The reason for the random delay is to avoid network-wide
* events causing too much simultaneous network traffic. However, on modern
* networks, a more reasonable value may be in the 10 ms range.
*/
@@ -236,7 +236,7 @@ _c_public_ void n_dhcp4_client_probe_config_set_start_delay(NDhcp4ClientProbeCon
*
* This adds an option to the list of options to request from the server.
*
- * A server may send options that we do not requst, and it may omit options
+ * A server may send options that we do not request, and it may omit options
* that we do request. However, to increase the likelyhood of uniform behavior
* between server implementations, we do not expose options that were not
* explicitly requested.
@@ -316,10 +316,9 @@ static void n_dhcp4_client_probe_config_initialize_random_seed(NDhcp4ClientProbe
unsigned short int seed16v[3];
const uint8_t *p;
uint64_t u64;
- int r;
/*
- * Initialize seed48_r(3)
+ * Initialize config's entropy buffer for successive jrand48(3) calls.
*
* We need random jitter for all timeouts and delays, used to reduce
* network traffic during bursts. This is not meant as security measure
@@ -360,8 +359,7 @@ static void n_dhcp4_client_probe_config_initialize_random_seed(NDhcp4ClientProbe
seed16v[1] = (u64 >> 16) ^ (u64 >> 0);
seed16v[2] = (u64 >> 32) ^ (u64 >> 16);
- r = seed48_r(seed16v, &config->entropy);
- c_assert(!r);
+ memcpy(config->entropy, seed16v, sizeof(seed16v));
}
/**
@@ -374,13 +372,7 @@ static void n_dhcp4_client_probe_config_initialize_random_seed(NDhcp4ClientProbe
* Return: the random data.
*/
uint32_t n_dhcp4_client_probe_config_get_random(NDhcp4ClientProbeConfig *config) {
- long int result;
- int r;
-
- r = mrand48_r(&config->entropy, &result);
- c_assert(!r);
-
- return result;
+ return jrand48(config->entropy);
};
/**
diff --git a/shared/n-dhcp4/src/n-dhcp4-client.c b/shared/n-dhcp4/src/n-dhcp4-client.c
index 403a693247..1dedbf30c8 100644
--- a/shared/n-dhcp4/src/n-dhcp4-client.c
+++ b/shared/n-dhcp4/src/n-dhcp4-client.c
@@ -146,14 +146,14 @@ _c_public_ void n_dhcp4_client_config_set_transport(NDhcp4ClientConfig *config,
*
* Background: OFFER and ACK messages from DHCP servers to clients are unicast
* to the IP address handed out, even before the IP address has
- * been configured on the taregt interface. This usually works
+ * been configured on the target interface. This usually works
* because the correct destination hardware address is explicitly
* set on the outgoing packets, rather than being resolved (which
* would not work). However, some hardware does not accept incoming
* IP packets destined for addresses they do not own, even if the
* hardware address is correct. In this case, the server must
* broadcast the replies in order for the client to receive them.
- * In general, unneccesary broadcasting is something one wants to
+ * In general, unnecessary broadcasting is something one wants to
* avoid, and some networks will not deliver broadcasts to the
* client at all, in which case this flag must not be set.
*/
@@ -549,7 +549,7 @@ void n_dhcp4_log_queue_fmt(NDhcp4LogQueue *log_queue,
if (level > log_queue->log_level)
return;
- /* Currently the logging queue is only implemented for
+ /* Currently, the logging queue is only implemented for
* the client. Nobody would enable logging except a
* client instance. */
c_assert(log_queue->is_client);
@@ -953,7 +953,7 @@ _c_public_ int n_dhcp4_client_update_mtu(NDhcp4Client *client, uint16_t mtu) {
* This creates a new probe on @client. Probes represent DHCP requests and
* track the state over the entire lifetime of a lease. Once a probe is created
* it will start looking for DHCP servers, request a lease from them, and renew
- * the lease continously whenever it expires. Furthermore, if a lease cannot be
+ * the lease continuously whenever it expires. Furthermore, if a lease cannot be
* renewed, a new lease will be requested.
*
* The API allows for many probes to be run at the same time. However, the DHCP
diff --git a/shared/n-dhcp4/src/n-dhcp4-private.h b/shared/n-dhcp4/src/n-dhcp4-private.h
index 90f8f0c355..db7b24ff7d 100644
--- a/shared/n-dhcp4/src/n-dhcp4-private.h
+++ b/shared/n-dhcp4/src/n-dhcp4-private.h
@@ -263,7 +263,7 @@ struct NDhcp4ClientProbeConfig {
bool inform_only;
bool init_reboot;
struct in_addr requested_ip;
- struct drand48_data entropy; /* entropy pool */
+ unsigned short int entropy[3];
uint64_t ms_start_delay; /* max ms to wait before starting probe */
NDhcp4ClientProbeOption *options[UINT8_MAX + 1];
int8_t request_parameters[UINT8_MAX + 1];
diff --git a/shared/n-dhcp4/src/n-dhcp4-s-connection.c b/shared/n-dhcp4/src/n-dhcp4-s-connection.c
index 71ae0be826..474a7b63c8 100644
--- a/shared/n-dhcp4/src/n-dhcp4-s-connection.c
+++ b/shared/n-dhcp4/src/n-dhcp4-s-connection.c
@@ -375,7 +375,7 @@ int n_dhcp4_s_connection_nak_new(NDhcp4SConnection *connection,
/*
* The RFC is a bit unclear on how NAK should be sent, on the
- * one hand it says that they should be unconditinoally broadcast
+ * one hand it says that they should be unconditionally broadcast
* (unless going through a relay agent), on the other, when they
* do go through a relay agent, they will not be. We treat them
* as any other reply and only broadcast when the broadcast bit
diff --git a/shared/n-dhcp4/src/n-dhcp4-socket.c b/shared/n-dhcp4/src/n-dhcp4-socket.c
index c7e897726e..4a83dd1528 100644
--- a/shared/n-dhcp4/src/n-dhcp4-socket.c
+++ b/shared/n-dhcp4/src/n-dhcp4-socket.c
@@ -22,7 +22,7 @@
/**
* n_dhcp4_c_socket_packet_new() - create a new DHCP4 client packet socket
- * @sockfdp: return argumnet for the new socket
+ * @sockfdp: return argument for the new socket
* @ifindex: interface index to bind to
*
* Create a new AF_PACKET/SOCK_DGRAM socket usable to listen to and send DHCP client
@@ -129,7 +129,7 @@ int n_dhcp4_c_socket_packet_new(int *sockfdp, int ifindex) {
/**
* n_dhcp4_c_socket_udp_new() - create a new DHCP4 client UDP socket
- * @sockfdp: return argumnet for the new socket
+ * @sockfdp: return argument for the new socket
* @ifindex: interface index to bind to
* @client_addr: client address to bind to
* @server_addr: server address to connect to
@@ -230,7 +230,7 @@ int n_dhcp4_c_socket_udp_new(int *sockfdp,
/**
* n_dhcp4_s_socket_packet_new() - create a new DHCP4 server packet socket
- * @sockfdp: return argumnet for the new socket
+ * @sockfdp: return argument for the new socket
*
* Create a new AF_PACKET/SOCK_DGRAM socket usable to send DHCP packets to clients
* before they have an IP address configured, on the given interface.
@@ -251,7 +251,7 @@ int n_dhcp4_s_socket_packet_new(int *sockfdp) {
/**
* n_dhcp4_s_socket_udp_new() - create a new DHCP4 server UDP socket
- * @sockfdp: return argumnet for the new socket
+ * @sockfdp: return argument for the new socket
* @ifindex: intercafe index to bind to
*
* Create a new AF_INET/SOCK_DGRAM socket usable to listen to DHCP server packets,
diff --git a/shared/n-dhcp4/src/test-run-client.c b/shared/n-dhcp4/src/test-run-client.c
index d29dbf1f2a..e558801470 100644
--- a/shared/n-dhcp4/src/test-run-client.c
+++ b/shared/n-dhcp4/src/test-run-client.c
@@ -440,7 +440,7 @@ static void print_help(void) {
" --ifindex IDX Index of interface to run on\n"
" --mac HEX Hardware address to use\n"
" --broadcast-mac HEX Broadcast hardware address to use\n"
- " --requested-ip IP Requested IP adress\n"
+ " --requested-ip IP Requested IP address\n"
" --requested-lifetime SECS Requested lease lifetime in seconds\n"
" --requested-parameters P1,P2,... Requested parameters\n"
" --client-id HEX Client Identifier to use\n"
diff --git a/shared/n-dhcp4/src/test.h b/shared/n-dhcp4/src/test.h
index 6933982e8c..b5acd14b37 100644
--- a/shared/n-dhcp4/src/test.h
+++ b/shared/n-dhcp4/src/test.h
@@ -85,7 +85,7 @@ static inline void test_setup(void) {
/*
* Move into a new network and mount namespace both associated
* with a new user namespace where the current eUID is mapped to
- * 0. Then create a a private instance of /run/netns. This ensures
+ * 0. Then create a private instance of /run/netns. This ensures
* that any network devices or network namespaces are private to
* the test process.
*/
diff --git a/shared/n-dhcp4/src/util/packet.c b/shared/n-dhcp4/src/util/packet.c
index 38cb399d5c..fb0313abe7 100644
--- a/shared/n-dhcp4/src/util/packet.c
+++ b/shared/n-dhcp4/src/util/packet.c
@@ -244,7 +244,7 @@ int packet_sendto_udp(int sockfd,
* @buf: buffor for payload
* @n_buf: max length of payload in bytes
* @n_transmittedp: output argument for number transmitted bytes
- * @src: return argumnet for source address, or NULL, see ip(7)
+ * @src: return argument for source address, or NULL, see ip(7)
*
* Receives an UDP packet on a AF_PACKET socket. The difference between
* this and recvfrom() on an AF_INET socket is that the packet will be
diff --git a/shared/nm-default.h b/shared/nm-default.h
index ace6ede16c..447b4dbf73 100644
--- a/shared/nm-default.h
+++ b/shared/nm-default.h
@@ -261,6 +261,8 @@ _nm_g_return_if_fail_warning (const char *log_domain,
/*****************************************************************************/
+#include "nm-std-aux/nm-std-aux.h"
+#include "nm-std-aux/nm-std-utils.h"
#include "nm-glib-aux/nm-macros-internal.h"
#include "nm-glib-aux/nm-shared-utils.h"
#include "nm-glib-aux/nm-errno.h"
diff --git a/shared/nm-glib-aux/nm-errno.c b/shared/nm-glib-aux/nm-errno.c
index e709f9e693..135e49cf80 100644
--- a/shared/nm-glib-aux/nm-errno.c
+++ b/shared/nm-glib-aux/nm-errno.c
@@ -58,7 +58,7 @@ NM_UTILS_LOOKUP_STR_DEFINE (_geterror,
* our own defines. For numbers that don't fall into this range, the numbers
* are identical to the common error numbers.
*
- * Idential to strerror(), g_strerror(), nm_strerror_native() for error numbers
+ * Identical to strerror(), g_strerror(), nm_strerror_native() for error numbers
* that are not in the reserved range of NetworkManager specific errors.
*
* Returns: (transfer none): the string representation of the error number.
@@ -97,7 +97,7 @@ nm_strerror (int nmerr)
* string may be longer than @buf_size.
*
* Returns: (transfer none): a NUL terminated error message. This is either a static
- * string (that is never freed), or the provided @buf argumnt.
+ * string (that is never freed), or the provided @buf argument.
*/
const char *
nm_strerror_native_r (int errsv, char *buf, gsize buf_size)
diff --git a/shared/nm-glib-aux/nm-hash-utils.h b/shared/nm-glib-aux/nm-hash-utils.h
index be69bfa8dc..d1ab8dbc83 100644
--- a/shared/nm-glib-aux/nm-hash-utils.h
+++ b/shared/nm-glib-aux/nm-hash-utils.h
@@ -99,7 +99,7 @@ nm_hash_update (NMHashState *state, const void *ptr, gsize n)
nm_assert (n == 0 || ptr);
/* Note: the data passed in here might be sensitive data (secrets),
- * that we should nm_explicty_zero() afterwards. However, since
+ * that we should nm_explicit_bzero() afterwards. However, since
* we are using siphash24 with a random key, that is not really
* necessary. Something to keep in mind, if we ever move away from
* this hash implementation. */
diff --git a/shared/nm-glib-aux/nm-io-utils.c b/shared/nm-glib-aux/nm-io-utils.c
index 776c63e111..81c6ad3510 100644
--- a/shared/nm-glib-aux/nm-io-utils.c
+++ b/shared/nm-glib-aux/nm-io-utils.c
@@ -357,7 +357,7 @@ nm_utils_file_set_contents (const char *filename,
/* If the final destination exists and is > 0 bytes, we want to sync the
* newly written file to ensure the data is on disk when we rename over
- * the destination. Otherwise if we get a system crash we can lose both
+ * the destination. Otherwise, if we get a system crash we can lose both
* the new and the old file on some filesystems. (I.E. those that don't
* guarantee the data is written to the disk before the metadata.)
*/
diff --git a/shared/nm-glib-aux/nm-io-utils.h b/shared/nm-glib-aux/nm-io-utils.h
index 31326fc79a..aa0b8f9b48 100644
--- a/shared/nm-glib-aux/nm-io-utils.h
+++ b/shared/nm-glib-aux/nm-io-utils.h
@@ -14,7 +14,7 @@
* NMUtilsFileGetContentsFlags:
* @NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE: no flag
* @NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET: if present, ensure that no
- * data is left in memory. Essentially, it means to call explicity_bzero()
+ * data is left in memory. Essentially, it means to call nm_explicit_bzero()
* to not leave key material on the heap (when reading secrets).
*/
typedef enum {
diff --git a/shared/nm-glib-aux/nm-jansson.h b/shared/nm-glib-aux/nm-jansson.h
index 7c034222c4..9314b50c69 100644
--- a/shared/nm-glib-aux/nm-jansson.h
+++ b/shared/nm-glib-aux/nm-jansson.h
@@ -12,11 +12,6 @@
#include <jansson.h>
-/* Added in Jansson v2.7 */
-#ifndef json_boolean_value
-#define json_boolean_value json_is_true
-#endif
-
/* Added in Jansson v2.8 */
#ifndef json_object_foreach_safe
#define json_object_foreach_safe(object, n, key, value) \
@@ -30,106 +25,6 @@
NM_AUTO_DEFINE_FCN0 (json_t *, _nm_auto_decref_json, json_decref)
#define nm_auto_decref_json nm_auto(_nm_auto_decref_json)
-/*****************************************************************************/
-
-static inline int
-nm_jansson_json_as_bool (const json_t *elem,
- bool *out_val)
-{
- if (!elem)
- return 0;
-
- if (!json_is_boolean (elem))
- return -EINVAL;
-
- NM_SET_OUT (out_val, json_boolean_value (elem));
- return 1;
-}
-
-static inline int
-nm_jansson_json_as_int32 (const json_t *elem,
- gint32 *out_val)
-{
- json_int_t v;
-
- if (!elem)
- return 0;
-
- if (!json_is_integer (elem))
- return -EINVAL;
-
- v = json_integer_value (elem);
- if ( v < (gint64) G_MININT32
- || v > (gint64) G_MAXINT32)
- return -ERANGE;
-
- NM_SET_OUT (out_val, v);
- return 1;
-}
-
-static inline int
-nm_jansson_json_as_int (const json_t *elem,
- int *out_val)
-{
- json_int_t v;
-
- if (!elem)
- return 0;
-
- if (!json_is_integer (elem))
- return -EINVAL;
-
- v = json_integer_value (elem);
- if ( v < (gint64) G_MININT
- || v > (gint64) G_MAXINT)
- return -ERANGE;
-
- NM_SET_OUT (out_val, v);
- return 1;
-}
-
-static inline int
-nm_jansson_json_as_string (const json_t *elem,
- const char **out_val)
-{
- if (!elem)
- return 0;
-
- if (!json_is_string (elem))
- return -EINVAL;
-
- NM_SET_OUT (out_val, json_string_value (elem));
- return 1;
-}
-
-/*****************************************************************************/
-
-#ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS
-#include "nm-value-type.h"
-static inline gboolean
-nm_value_type_from_json (NMValueType value_type,
- const json_t *elem,
- gpointer out_val)
-{
- switch (value_type) {
- case NM_VALUE_TYPE_BOOL: return (nm_jansson_json_as_bool (elem, out_val) > 0);
- case NM_VALUE_TYPE_INT32: return (nm_jansson_json_as_int32 (elem, out_val) > 0);
- case NM_VALUE_TYPE_INT: return (nm_jansson_json_as_int (elem, out_val) > 0);
-
- /* warning: this overwrites/leaks the previous value. You better have *out_val
- * point to uninitialized memory or NULL. */
- case NM_VALUE_TYPE_STRING: return (nm_jansson_json_as_string (elem, out_val) > 0);
-
- case NM_VALUE_TYPE_UNSPEC:
- break;
- }
- nm_assert_not_reached ();
- return FALSE;
-}
-#endif
-
-/*****************************************************************************/
-
#endif /* WITH_JANSON */
#endif /* __NM_JANSSON_H__ */
diff --git a/shared/nm-glib-aux/nm-json-aux.c b/shared/nm-glib-aux/nm-json-aux.c
index a738ab7257..e9816d7781 100644
--- a/shared/nm-glib-aux/nm-json-aux.c
+++ b/shared/nm-glib-aux/nm-json-aux.c
@@ -1,12 +1,14 @@
// SPDX-License-Identifier: LGPL-2.1+
/*
- * Copyright (C) 2019 Red Hat, Inc.
+ * Copyright (C) 2017 - 2019 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-json-aux.h"
+#include <dlfcn.h>
+
/*****************************************************************************/
static void
@@ -78,7 +80,7 @@ _gstr_append_string_len (GString *gstr,
* JSON can only contain UTF-8 and even the escape sequences can only escape Unicode
* codepoints (but not binary).
*
- * The argument is not a a string (in any known encoding), hence we cannot represent
+ * The argument is not a string (in any known encoding), hence we cannot represent
* it as a JSON string (which are unicode strings).
*
* Print an underscore instead of the invalid char :) */
@@ -96,9 +98,9 @@ _gstr_append_string_len (GString *gstr,
}
void
-nm_json_aux_gstr_append_string_len (GString *gstr,
- const char *str,
- gsize n)
+nm_json_gstr_append_string_len (GString *gstr,
+ const char *str,
+ gsize n)
{
g_return_if_fail (gstr);
@@ -106,8 +108,8 @@ nm_json_aux_gstr_append_string_len (GString *gstr,
}
void
-nm_json_aux_gstr_append_string (GString *gstr,
- const char *str)
+nm_json_gstr_append_string (GString *gstr,
+ const char *str)
{
g_return_if_fail (gstr);
@@ -118,14 +120,14 @@ nm_json_aux_gstr_append_string (GString *gstr,
}
void
-nm_json_aux_gstr_append_obj_name (GString *gstr,
- const char *key,
- char start_container)
+nm_json_gstr_append_obj_name (GString *gstr,
+ const char *key,
+ char start_container)
{
g_return_if_fail (gstr);
g_return_if_fail (key);
- nm_json_aux_gstr_append_string (gstr, key);
+ nm_json_gstr_append_string (gstr, key);
if (start_container != '\0') {
nm_assert (NM_IN_SET (start_container, '[', '{'));
@@ -133,3 +135,136 @@ nm_json_aux_gstr_append_obj_name (GString *gstr,
} else
g_string_append (gstr, ": ");
}
+
+/*****************************************************************************/
+
+typedef struct {
+ NMJsonVt vt;
+ void *dl_handle;
+} NMJsonVtInternal;
+
+static NMJsonVtInternal *
+_nm_json_vt_internal_load (void)
+{
+ NMJsonVtInternal *v;
+ const char *soname;
+ void *handle;
+
+ v = g_new0 (NMJsonVtInternal, 1);
+
+#if WITH_JANSSON && defined (JANSSON_SONAME)
+ G_STATIC_ASSERT_EXPR (NM_STRLEN (JANSSON_SONAME) > 0);
+ nm_assert (strlen (JANSSON_SONAME) > 0);
+ soname = JANSSON_SONAME;
+#elif !WITH_JANSSON && !defined (JANSSON_SONAME)
+ soname = NULL;
+#else
+#error "WITH_JANSON and JANSSON_SONAME are defined inconsistently."
+#endif
+
+ if (!soname)
+ return v;
+
+ handle = dlopen (soname, RTLD_LAZY
+ | RTLD_LOCAL
+ | RTLD_NODELETE
+#if !defined (ASAN_BUILD)
+ | RTLD_DEEPBIND
+#endif
+ | 0);
+ if (!handle)
+ return v;
+
+#define TRY_BIND_SYMBOL(symbol) \
+ G_STMT_START { \
+ void *_sym = dlsym (handle, #symbol); \
+ \
+ if (!_sym) \
+ goto fail_symbol; \
+ v->vt.nm_ ## symbol = _sym; \
+ } G_STMT_END
+
+ TRY_BIND_SYMBOL (json_array);
+ TRY_BIND_SYMBOL (json_array_append_new);
+ TRY_BIND_SYMBOL (json_array_get);
+ TRY_BIND_SYMBOL (json_array_size);
+ TRY_BIND_SYMBOL (json_delete);
+ TRY_BIND_SYMBOL (json_dumps);
+ TRY_BIND_SYMBOL (json_false);
+ TRY_BIND_SYMBOL (json_integer);
+ TRY_BIND_SYMBOL (json_integer_value);
+ TRY_BIND_SYMBOL (json_loads);
+ TRY_BIND_SYMBOL (json_object);
+ TRY_BIND_SYMBOL (json_object_del);
+ TRY_BIND_SYMBOL (json_object_get);
+ TRY_BIND_SYMBOL (json_object_iter);
+ TRY_BIND_SYMBOL (json_object_iter_key);
+ TRY_BIND_SYMBOL (json_object_iter_next);
+ TRY_BIND_SYMBOL (json_object_iter_value);
+ TRY_BIND_SYMBOL (json_object_key_to_iter);
+ TRY_BIND_SYMBOL (json_object_set_new);
+ TRY_BIND_SYMBOL (json_object_size);
+ TRY_BIND_SYMBOL (json_string);
+ TRY_BIND_SYMBOL (json_string_value);
+ TRY_BIND_SYMBOL (json_true);
+
+ v->vt.loaded = TRUE;
+ v->dl_handle = handle;
+ return v;
+
+fail_symbol:
+ dlclose (&handle);
+ *v = (NMJsonVtInternal) { };
+ return v;
+}
+
+const NMJsonVt *_nm_json_vt_ptr = NULL;
+
+const NMJsonVt *
+_nm_json_vt_init (void)
+{
+ NMJsonVtInternal *v;
+
+again:
+ v = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr);
+ if (G_UNLIKELY (!v)) {
+ v = _nm_json_vt_internal_load ();
+ if (!g_atomic_pointer_compare_and_exchange ((gpointer *) &_nm_json_vt_ptr, NULL, v)) {
+ if (v->dl_handle)
+ dlclose (v->dl_handle);
+ g_free (v);
+ goto again;
+ }
+
+ /* we transfer ownership. */
+ }
+
+ nm_assert (v && v == g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr));
+ return &v->vt;
+}
+
+const NMJsonVt *
+nmtst_json_vt_reset (gboolean loaded)
+{
+ NMJsonVtInternal *v_old;
+ NMJsonVtInternal *v;
+
+ v_old = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr);
+
+ if (!loaded) {
+ /* load a fake instance for testing. */
+ v = g_new0 (NMJsonVtInternal, 1);
+ } else
+ v = _nm_json_vt_internal_load ();
+
+ if (!g_atomic_pointer_compare_and_exchange ((gpointer *) &_nm_json_vt_ptr, v_old, v))
+ g_assert_not_reached ();
+
+ if (v_old) {
+ if (v_old->dl_handle)
+ dlclose (v_old->dl_handle);
+ g_free ((gpointer *) v_old);
+ }
+
+ return v->vt.loaded ? &v->vt : NULL;
+}
diff --git a/shared/nm-glib-aux/nm-json-aux.h b/shared/nm-glib-aux/nm-json-aux.h
index ed3be3768f..082b9e5205 100644
--- a/shared/nm-glib-aux/nm-json-aux.h
+++ b/shared/nm-glib-aux/nm-json-aux.h
@@ -1,49 +1,281 @@
// SPDX-License-Identifier: LGPL-2.1+
/*
- * Copyright (C) 2019 Red Hat, Inc.
+ * Copyright (C) 2017 - 2019 Red Hat, Inc.
*/
#ifndef __NM_JSON_AUX_H__
#define __NM_JSON_AUX_H__
+#include "nm-value-type.h"
+
/*****************************************************************************/
static inline GString *
-nm_json_aux_gstr_append_delimiter (GString *gstr)
+nm_json_gstr_append_delimiter (GString *gstr)
{
g_string_append (gstr, ", ");
return gstr;
}
-void nm_json_aux_gstr_append_string_len (GString *gstr,
- const char *str,
- gsize n);
+void nm_json_gstr_append_string_len (GString *gstr,
+ const char *str,
+ gsize n);
-void nm_json_aux_gstr_append_string (GString *gstr,
- const char *str);
+void nm_json_gstr_append_string (GString *gstr,
+ const char *str);
static inline void
-nm_json_aux_gstr_append_bool (GString *gstr,
- gboolean v)
+nm_json_gstr_append_bool (GString *gstr,
+ gboolean v)
{
g_string_append (gstr, v ? "true" : "false");
}
static inline void
-nm_json_aux_gstr_append_int64 (GString *gstr,
- gint64 v)
+nm_json_gstr_append_int64 (GString *gstr,
+ gint64 v)
{
g_string_append_printf (gstr, "%"G_GINT64_FORMAT, v);
}
-void nm_json_aux_gstr_append_obj_name (GString *gstr,
- const char *key,
- char start_container);
+void nm_json_gstr_append_obj_name (GString *gstr,
+ const char *key,
+ char start_container);
+
+/*****************************************************************************/
+
+#define NM_JSON_REJECT_DUPLICATES 0x1
+
+typedef enum {
+ NM_JSON_OBJECT,
+ NM_JSON_ARRAY,
+ NM_JSON_STRING,
+ NM_JSON_INTEGER,
+ NM_JSON_REAL,
+ NM_JSON_TRUE,
+ NM_JSON_FALSE,
+ NM_JSON_NULL,
+} nm_json_type;
+
+typedef struct nm_json_t {
+ nm_json_type type;
+ volatile size_t refcount;
+} nm_json_t;
+
+typedef long long nm_json_int_t;
+
+#define NM_JSON_ERROR_TEXT_LENGTH 160
+#define NM_JSON_ERROR_SOURCE_LENGTH 80
+
+typedef struct nm_json_error_t {
+ int line;
+ int column;
+ int position;
+ char source[NM_JSON_ERROR_SOURCE_LENGTH];
+ char text[NM_JSON_ERROR_TEXT_LENGTH];
+} nm_json_error_t;
+
+typedef struct {
+ gboolean loaded;
+ char *(*nm_json_dumps) (const nm_json_t *json, size_t flags);
+ const char *(*nm_json_object_iter_key) (void *iter);
+ const char *(*nm_json_string_value) (const nm_json_t *json);
+ int (*nm_json_array_append_new) (nm_json_t *json, nm_json_t *value);
+ int (*nm_json_object_del) (nm_json_t *json, const char *key);
+ int (*nm_json_object_set_new) (nm_json_t *json, const char *key, nm_json_t *value);
+ nm_json_int_t (*nm_json_integer_value) (const nm_json_t *json);
+ nm_json_t *(*nm_json_array) (void);
+ nm_json_t *(*nm_json_array_get) (const nm_json_t *json, size_t index);
+ nm_json_t *(*nm_json_false) (void);
+ nm_json_t *(*nm_json_integer) (nm_json_int_t value);
+ nm_json_t *(*nm_json_loads) (const char *string, size_t flags, nm_json_error_t *error);
+ nm_json_t *(*nm_json_object) (void);
+ nm_json_t *(*nm_json_object_get) (const nm_json_t *json, const char *key);
+ nm_json_t *(*nm_json_object_iter_value) (void *);
+ nm_json_t *(*nm_json_string) (const char *value);
+ nm_json_t *(*nm_json_true) (void);
+ size_t (*nm_json_array_size) (const nm_json_t *json);
+ size_t (*nm_json_object_size) (const nm_json_t *json);
+ void (*nm_json_delete) (nm_json_t *json);
+ void *(*nm_json_object_iter) (nm_json_t *json);
+ void *(*nm_json_object_iter_next) (nm_json_t *json, void *iter);
+ void *(*nm_json_object_key_to_iter) (const char *key);
+} NMJsonVt;
+
+extern const NMJsonVt *_nm_json_vt_ptr;
+
+const NMJsonVt *_nm_json_vt_init (void);
+
+static inline const NMJsonVt *
+_nm_json_vt (void)
+{
+ const NMJsonVt *vt;
+
+ vt = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr);
+ if (G_UNLIKELY (!vt)) {
+ vt = _nm_json_vt_init ();
+ nm_assert (vt);
+ }
+ return vt;
+}
+
+static inline const NMJsonVt *
+nm_json_vt (void)
+{
+ const NMJsonVt *vt;
+
+ vt = _nm_json_vt();
+ return vt->loaded ? vt : NULL;
+}
+
+static inline const NMJsonVt *
+nm_json_vt_assert (void)
+{
+ const NMJsonVt *vt;
+
+ vt = _nm_json_vt();
+ nm_assert (vt->loaded);
+ return vt;
+}
+
+const NMJsonVt *nmtst_json_vt_reset (gboolean loaded);
+
+/*****************************************************************************/
+
+#define nm_json_boolean(vt, val) \
+ ((val) ? (vt)->nm_json_true () : (vt)->nm_json_false ())
+
+static inline void
+nm_json_decref (const NMJsonVt *vt, nm_json_t *json)
+{
+ /* Our ref-counting is not threadsafe, unlike libjansson's. But we never
+ * share one json_t instance between threads, and if we would, we would very likely
+ * wrap a mutex around it. */
+ if ( json
+ && json->refcount != (size_t) -1
+ && --json->refcount == 0)
+ vt->nm_json_delete (json);
+}
+
+static inline void
+_nm_auto_decref_json (nm_json_t **p_json)
+{
+ if ( *p_json
+ && (*p_json)->refcount != (size_t) -1
+ && --(*p_json)->refcount == 0)
+ nm_json_vt ()->nm_json_delete (*p_json);
+}
+
+#define nm_auto_decref_json nm_auto(_nm_auto_decref_json)
+
+/*****************************************************************************/
+
+/* the following are implemented as pure macros in jansson.h.
+ * They can be used directly, however, add a nm_json* variant,
+ * to make it explict we don't accidentally use jansson ABI. */
+
+#define nm_json_typeof(json) ((json)->type)
+#define nm_json_is_object(json) ((json) && nm_json_typeof(json) == NM_JSON_OBJECT)
+#define nm_json_is_array(json) ((json) && nm_json_typeof(json) == NM_JSON_ARRAY)
+#define nm_json_is_string(json) ((json) && nm_json_typeof(json) == NM_JSON_STRING)
+#define nm_json_is_integer(json) ((json) && nm_json_typeof(json) == NM_JSON_INTEGER)
+#define nm_json_is_real(json) ((json) && nm_json_typeof(json) == NM_JSON_REAL)
+#define nm_json_is_number(json) (nm_json_is_integer(json) || nm_json_is_real(json))
+#define nm_json_is_true(json) ((json) && nm_json_typeof(json) == NM_JSON_TRUE)
+#define nm_json_is_false(json) ((json) && nm_json_typeof(json) == NM_JSON_FALSE)
+#define nm_json_boolean_value nm_json_is_true
+#define nm_json_is_boolean(json) (nm_json_is_true(json) || nm_json_is_false(json))
+#define nm_json_is_null(json) ((json) && nm_json_typeof(json) == NM_JSON_NULL)
+
+#define nm_json_array_foreach(vt, array, index, value) \
+ for(index = 0; \
+ index < vt->nm_json_array_size (array) && (value = vt->nm_json_array_get (array, index)); \
+ index++)
+
+#define nm_json_object_foreach(vt, object, key, value) \
+ for(key = vt->nm_json_object_iter_key (vt->nm_json_object_iter (object)); \
+ key && (value = vt->nm_json_object_iter_value (vt->nm_json_object_key_to_iter (key))); \
+ key = vt->nm_json_object_iter_key (vt->nm_json_object_iter_next (object, vt->nm_json_object_key_to_iter (key))))
+
+/*****************************************************************************/
+
+static inline int
+nm_jansson_json_as_bool (const nm_json_t *elem,
+ bool *out_val)
+{
+ if (!elem)
+ return 0;
+
+ if (!nm_json_is_boolean (elem))
+ return -EINVAL;
+
+ NM_SET_OUT (out_val, nm_json_boolean_value (elem));
+ return 1;
+}
+
+static inline int
+nm_jansson_json_as_int32 (const NMJsonVt *vt,
+ const nm_json_t *elem,
+ gint32 *out_val)
+{
+ nm_json_int_t v;
+
+ if (!elem)
+ return 0;
+
+ if (!nm_json_is_integer (elem))
+ return -EINVAL;
+
+ v = vt->nm_json_integer_value (elem);
+ if ( v < (gint64) G_MININT32
+ || v > (gint64) G_MAXINT32)
+ return -ERANGE;
+
+ NM_SET_OUT (out_val, v);
+ return 1;
+}
+
+static inline int
+nm_jansson_json_as_int (const NMJsonVt *vt,
+ const nm_json_t *elem,
+ int *out_val)
+{
+ nm_json_int_t v;
+
+ if (!elem)
+ return 0;
+
+ if (!nm_json_is_integer (elem))
+ return -EINVAL;
+
+ v = vt->nm_json_integer_value (elem);
+ if ( v < (gint64) G_MININT
+ || v > (gint64) G_MAXINT)
+ return -ERANGE;
+
+ NM_SET_OUT (out_val, v);
+ return 1;
+}
+
+static inline int
+nm_jansson_json_as_string (const NMJsonVt *vt,
+ const nm_json_t *elem,
+ const char **out_val)
+{
+ if (!elem)
+ return 0;
+
+ if (!nm_json_is_string (elem))
+ return -EINVAL;
+
+ NM_SET_OUT (out_val, vt->nm_json_string_value (elem));
+ return 1;
+}
/*****************************************************************************/
#ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS
-#include "nm-value-type.h"
+
static inline void
nm_value_type_to_json (NMValueType value_type,
GString *gstr,
@@ -53,17 +285,38 @@ nm_value_type_to_json (NMValueType value_type,
nm_assert (gstr);
switch (value_type) {
- case NM_VALUE_TYPE_BOOL: nm_json_aux_gstr_append_bool (gstr, *((const bool *) p_field)); return;
- case NM_VALUE_TYPE_INT32: nm_json_aux_gstr_append_int64 (gstr, *((const gint32 *) p_field)); return;
- case NM_VALUE_TYPE_INT: nm_json_aux_gstr_append_int64 (gstr, *((const int *) p_field)); return;
- case NM_VALUE_TYPE_STRING: nm_json_aux_gstr_append_string (gstr, *((const char *const *) p_field)); return;
+ case NM_VALUE_TYPE_BOOL: nm_json_gstr_append_bool (gstr, *((const bool *) p_field)); return;
+ case NM_VALUE_TYPE_INT32: nm_json_gstr_append_int64 (gstr, *((const gint32 *) p_field)); return;
+ case NM_VALUE_TYPE_INT: nm_json_gstr_append_int64 (gstr, *((const int *) p_field)); return;
+ case NM_VALUE_TYPE_STRING: nm_json_gstr_append_string (gstr, *((const char *const *) p_field)); return;
case NM_VALUE_TYPE_UNSPEC:
break;
}
nm_assert_not_reached ();
}
-#endif
-/*****************************************************************************/
+static inline gboolean
+nm_value_type_from_json (const NMJsonVt *vt,
+ NMValueType value_type,
+ const nm_json_t *elem,
+ gpointer out_val)
+{
+ switch (value_type) {
+ case NM_VALUE_TYPE_BOOL: return (nm_jansson_json_as_bool (elem, out_val) > 0);
+ case NM_VALUE_TYPE_INT32: return (nm_jansson_json_as_int32 (vt, elem, out_val) > 0);
+ case NM_VALUE_TYPE_INT: return (nm_jansson_json_as_int (vt, elem, out_val) > 0);
+
+ /* warning: this overwrites/leaks the previous value. You better have *out_val
+ * point to uninitialized memory or NULL. */
+ case NM_VALUE_TYPE_STRING: return (nm_jansson_json_as_string (vt, elem, out_val) > 0);
+
+ case NM_VALUE_TYPE_UNSPEC:
+ break;
+ }
+ nm_assert_not_reached ();
+ return FALSE;
+}
+
+#endif /* NM_VALUE_TYPE_DEFINE_FUNCTIONS */
-#endif /* __NM_JSON_AUX_H__ */
+#endif /* __NM_JSON_AUX_H__ */
diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h
index f56ed85699..d12fa3b602 100644
--- a/shared/nm-glib-aux/nm-macros-internal.h
+++ b/shared/nm-glib-aux/nm-macros-internal.h
@@ -16,53 +16,6 @@
/*****************************************************************************/
-#define _nm_packed __attribute__ ((__packed__))
-#define _nm_unused __attribute__ ((__unused__))
-#define _nm_used __attribute__ ((__used__))
-#define _nm_pure __attribute__ ((__pure__))
-#define _nm_const __attribute__ ((__const__))
-#define _nm_printf(a,b) __attribute__ ((__format__ (__printf__, a, b)))
-#define _nm_align(s) __attribute__ ((__aligned__ (s)))
-#define _nm_section(s) __attribute__ ((__section__ (s)))
-#define _nm_alignof(type) __alignof (type)
-#define _nm_alignas(type) _nm_align (_nm_alignof (type))
-#define nm_auto(fcn) __attribute__ ((__cleanup__(fcn)))
-
-
-/* This is required to make LTO working.
- *
- * See https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/76#note_112694
- * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48200#c28
- */
-#ifndef __clang__
-#define _nm_externally_visible __attribute__ ((__externally_visible__))
-#else
-#define _nm_externally_visible
-#endif
-
-
-#if __GNUC__ >= 7
-#define _nm_fallthrough __attribute__ ((__fallthrough__))
-#else
-#define _nm_fallthrough
-#endif
-
-/*****************************************************************************/
-
-#ifdef thread_local
-#define _nm_thread_local thread_local
-/*
- * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
- * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
- */
-#elif __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
-#define _nm_thread_local _Thread_local
-#else
-#define _nm_thread_local __thread
-#endif
-
-/*****************************************************************************/
-
/* most of our code is single-threaded with a mainloop. Hence, we usually don't need
* any thread-safety. Sometimes, we do need thread-safety (nm-logging), but we can
* avoid locking if we are on the main-thread by:
@@ -85,34 +38,6 @@
/*****************************************************************************/
-#define NM_AUTO_DEFINE_FCN_VOID(CastType, name, func) \
-static inline void name (void *v) \
-{ \
- func (*((CastType *) v)); \
-}
-
-#define NM_AUTO_DEFINE_FCN_VOID0(CastType, name, func) \
-static inline void name (void *v) \
-{ \
- if (*((CastType *) v)) \
- func (*((CastType *) v)); \
-}
-
-#define NM_AUTO_DEFINE_FCN(Type, name, func) \
-static inline void name (Type *v) \
-{ \
- func (*v); \
-}
-
-#define NM_AUTO_DEFINE_FCN0(Type, name, func) \
-static inline void name (Type *v) \
-{ \
- if (*v) \
- func (*v); \
-}
-
-/*****************************************************************************/
-
/**
* gs_free:
*
@@ -226,25 +151,6 @@ NM_AUTO_DEFINE_FCN0 (GKeyFile *, gs_local_keyfile_unref, g_key_file_unref)
/*****************************************************************************/
-static inline int nm_close (int fd);
-
-/**
- * nm_auto_free:
- *
- * Call free() on a variable location when it goes out of scope.
- * This is for pointers that are allocated with malloc() instead of
- * g_malloc().
- *
- * In practice, since glib 2.45, g_malloc()/g_free() always wraps malloc()/free().
- * See bgo#751592. In that case, it would be safe to free pointers allocated with
- * malloc() with gs_free or g_free().
- *
- * However, let's never mix them. To free malloc'ed memory, always use
- * free() or nm_auto_free.
- */
-NM_AUTO_DEFINE_FCN_VOID0 (void *, _nm_auto_free_impl, free)
-#define nm_auto_free nm_auto(_nm_auto_free_impl)
-
NM_AUTO_DEFINE_FCN0 (GVariantIter *, _nm_auto_free_variant_iter, g_variant_iter_free)
#define nm_auto_free_variant_iter nm_auto(_nm_auto_free_variant_iter)
@@ -276,30 +182,6 @@ _nm_auto_free_gstring (GString **str)
#define nm_auto_free_gstring nm_auto(_nm_auto_free_gstring)
static inline void
-_nm_auto_close (int *pfd)
-{
- if (*pfd >= 0) {
- int errsv = errno;
-
- (void) nm_close (*pfd);
- errno = errsv;
- }
-}
-#define nm_auto_close nm_auto(_nm_auto_close)
-
-static inline void
-_nm_auto_fclose (FILE **pfd)
-{
- if (*pfd) {
- int errsv = errno;
-
- (void) fclose (*pfd);
- errno = errsv;
- }
-}
-#define nm_auto_fclose nm_auto(_nm_auto_fclose)
-
-static inline void
_nm_auto_protect_errno (int *p_saved_errno)
{
errno = *p_saved_errno;
@@ -456,43 +338,6 @@ NM_G_ERROR_MSG (GError *error)
/*****************************************************************************/
-/* macro to return strlen() of a compile time string. */
-#define NM_STRLEN(str) ( sizeof (""str"") - 1 )
-
-/* returns the length of a NULL terminated array of pointers,
- * like g_strv_length() does. The difference is:
- * - it operats on arrays of pointers (of any kind, requiring no cast).
- * - it accepts NULL to return zero. */
-#define NM_PTRARRAY_LEN(array) \
- ({ \
- typeof (*(array)) *const _array = (array); \
- gsize _n = 0; \
- \
- if (_array) { \
- _nm_unused gconstpointer _type_check_is_pointer = _array[0]; \
- \
- while (_array[_n]) \
- _n++; \
- } \
- _n; \
- })
-
-/* Note: @value is only evaluated when *out_val is present.
- * Thus,
- * NM_SET_OUT (out_str, g_strdup ("hallo"));
- * does the right thing.
- */
-#define NM_SET_OUT(out_val, value) \
- G_STMT_START { \
- typeof(*(out_val)) *_out_val = (out_val); \
- \
- if (_out_val) { \
- *_out_val = (value); \
- } \
- } G_STMT_END
-
-/*****************************************************************************/
-
#ifndef _NM_CC_SUPPORT_AUTO_TYPE
#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 )))
#define _NM_CC_SUPPORT_AUTO_TYPE 1
@@ -716,156 +561,6 @@ NM_G_ERROR_MSG (GError *error)
/*****************************************************************************/
-#define _NM_IN_SET_EVAL_1( op, _x, y) (_x == (y))
-#define _NM_IN_SET_EVAL_2( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_1 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_3( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_2 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_4( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_3 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_5( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_4 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_6( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_5 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_7( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_6 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_8( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_7 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_9( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_8 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_10(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_9 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_11(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_10 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_12(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_11 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_13(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_12 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_14(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_13 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_15(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_14 (op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_16(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_15 (op, _x, __VA_ARGS__)
-
-#define _NM_IN_SET_EVAL_N2(op, _x, n, ...) (_NM_IN_SET_EVAL_##n(op, _x, __VA_ARGS__))
-#define _NM_IN_SET_EVAL_N(op, type, x, n, ...) \
- ({ \
- type _x = (x); \
- \
- /* trigger a -Wenum-compare warning */ \
- nm_assert (TRUE || _x == (x)); \
- \
- !!_NM_IN_SET_EVAL_N2(op, _x, n, __VA_ARGS__); \
- })
-
-#define _NM_IN_SET(op, type, x, ...) _NM_IN_SET_EVAL_N(op, type, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
-
-/* Beware that this does short-circuit evaluation (use "||" instead of "|")
- * which has a possibly unexpected non-function-like behavior.
- * Use NM_IN_SET_SE if you need all arguments to be evaluated. */
-#define NM_IN_SET(x, ...) _NM_IN_SET(||, typeof (x), x, __VA_ARGS__)
-
-/* "SE" stands for "side-effect". Contrary to NM_IN_SET(), this does not do
- * short-circuit evaluation, which can make a difference if the arguments have
- * side-effects. */
-#define NM_IN_SET_SE(x, ...) _NM_IN_SET(|, typeof (x), x, __VA_ARGS__)
-
-/* the *_TYPED forms allow to explicitly select the type of "x". This is useful
- * if "x" doesn't support typeof (bitfields) or you want to gracefully convert
- * a type using automatic type conversion rules (but not forcing the conversion
- * with a cast). */
-#define NM_IN_SET_TYPED(type, x, ...) _NM_IN_SET(||, type, x, __VA_ARGS__)
-#define NM_IN_SET_SE_TYPED(type, x, ...) _NM_IN_SET(|, type, x, __VA_ARGS__)
-
-/*****************************************************************************/
-
-#define NM_SWAP(a, b) \
- G_STMT_START { \
- typeof (a) _tmp; \
- \
- _tmp = (a); \
- (a) = (b); \
- (b) = _tmp; \
- } G_STMT_END
-
-/*****************************************************************************/
-
-static inline gboolean
-_NM_IN_STRSET_streq (const char *x, const char *s)
-{
- return s && strcmp (x, s) == 0;
-}
-
-#define _NM_IN_STRSET_EVAL_1( op, _x, y) _NM_IN_STRSET_streq (_x, y)
-#define _NM_IN_STRSET_EVAL_2( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_1 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_3( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_2 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_4( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_3 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_5( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_4 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_6( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_5 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_7( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_6 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_8( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_7 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_9( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_8 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_10(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_9 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_11(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_10 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_12(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_11 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_13(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_12 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_14(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_13 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_15(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_14 (op, _x, __VA_ARGS__)
-#define _NM_IN_STRSET_EVAL_16(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_15 (op, _x, __VA_ARGS__)
-
-#define _NM_IN_STRSET_EVAL_N2(op, _x, n, ...) (_NM_IN_STRSET_EVAL_##n(op, _x, __VA_ARGS__))
-#define _NM_IN_STRSET_EVAL_N(op, x, n, ...) \
- ({ \
- const char *_x = (x); \
- ( ((_x == NULL) && _NM_IN_SET_EVAL_N2 (op, ((const char *) NULL), n, __VA_ARGS__)) \
- || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2 (op, _x, n, __VA_ARGS__)) \
- ); \
- })
-
-/* Beware that this does short-circuit evaluation (use "||" instead of "|")
- * which has a possibly unexpected non-function-like behavior.
- * Use NM_IN_STRSET_SE if you need all arguments to be evaluated. */
-#define NM_IN_STRSET(x, ...) _NM_IN_STRSET_EVAL_N(||, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
-
-/* "SE" stands for "side-effect". Contrary to NM_IN_STRSET(), this does not do
- * short-circuit evaluation, which can make a difference if the arguments have
- * side-effects. */
-#define NM_IN_STRSET_SE(x, ...) _NM_IN_STRSET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
-
-#define NM_STRCHAR_ALL(str, ch_iter, predicate) \
- ({ \
- gboolean _val = TRUE; \
- const char *_str = (str); \
- \
- if (_str) { \
- for (;;) { \
- const char ch_iter = _str[0]; \
- \
- if (ch_iter != '\0') { \
- if (predicate) {\
- _str++; \
- continue; \
- } \
- _val = FALSE; \
- } \
- break; \
- } \
- } \
- _val; \
- })
-
-#define NM_STRCHAR_ANY(str, ch_iter, predicate) \
- ({ \
- gboolean _val = FALSE; \
- const char *_str = (str); \
- \
- if (_str) { \
- for (;;) { \
- const char ch_iter = _str[0]; \
- \
- if (ch_iter != '\0') { \
- if (predicate) { \
- ; \
- } else { \
- _str++; \
- continue; \
- } \
- _val = TRUE; \
- } \
- break; \
- } \
- } \
- _val; \
- })
-
-/*****************************************************************************/
-
/* NM_CACHED_QUARK() returns the GQuark for @string, but caches
* it in a static variable to speed up future lookups.
*
@@ -900,77 +595,6 @@ fcn (void) \
/*****************************************************************************/
-static inline int
-nm_strcmp0 (const char *s1, const char *s2)
-{
- int c;
-
- /* like g_strcmp0(), but this is inlinable.
- *
- * Also, it is guaranteed to return either -1, 0, or 1. */
- if (s1 == s2)
- return 0;
- if (!s1)
- return -1;
- if (!s2)
- return 1;
- c = strcmp (s1, s2);
- if (c < 0)
- return -1;
- if (c > 0)
- return 1;
- return 0;
-}
-
-static inline gboolean
-nm_streq (const char *s1, const char *s2)
-{
- return strcmp (s1, s2) == 0;
-}
-
-static inline gboolean
-nm_streq0 (const char *s1, const char *s2)
-{
- return (s1 == s2)
- || (s1 && s2 && strcmp (s1, s2) == 0);
-}
-
-#define NM_STR_HAS_PREFIX(str, prefix) \
- ({ \
- const char *const _str_has_prefix = (str); \
- \
- nm_assert (strlen (prefix) == NM_STRLEN (prefix)); \
- \
- _str_has_prefix \
- && (strncmp (_str_has_prefix, ""prefix"", NM_STRLEN (prefix)) == 0); \
- })
-
-#define NM_STR_HAS_SUFFIX(str, suffix) \
- ({ \
- const char *const _str_has_suffix = (str); \
- gsize _l; \
- \
- nm_assert (strlen (suffix) == NM_STRLEN (suffix)); \
- \
- ( _str_has_suffix \
- && ((_l = strlen (_str_has_suffix)) >= NM_STRLEN (suffix)) \
- && (memcmp (&_str_has_suffix[_l - NM_STRLEN (suffix)], \
- ""suffix"", \
- NM_STRLEN (suffix)) == 0)); \
- })
-
-/* whether @str starts with the string literal @prefix and is followed by
- * some other text. It is like NM_STR_HAS_PREFIX() && !nm_streq() together. */
-#define NM_STR_HAS_PREFIX_WITH_MORE(str, prefix) \
- ({ \
- const char *const _str_has_prefix_with_more = (str); \
- \
- NM_STR_HAS_PREFIX (_str_has_prefix_with_more, ""prefix"") \
- && _str_has_prefix_with_more[NM_STRLEN (prefix)] != '\0'; \
- })
-
-/*****************************************************************************/
-
static inline GString *
nm_gstring_prepare (GString **l)
{
@@ -1038,31 +662,11 @@ nm_str_realloc (char *str)
/*****************************************************************************/
-/* glib/C provides the following kind of assertions:
- * - assert() -- disable with NDEBUG
- * - g_return_if_fail() -- disable with G_DISABLE_CHECKS
- * - g_assert() -- disable with G_DISABLE_ASSERT
- * but they are all enabled by default and usually even production builds have
- * these kind of assertions enabled. It also means, that disabling assertions
- * is an untested configuration, and might have bugs.
- *
- * Add our own assertion macro nm_assert(), which is disabled by default and must
- * be explicitly enabled. They are useful for more expensive checks or checks that
- * depend less on runtime conditions (that is, are generally expected to be true). */
-
-#ifndef NM_MORE_ASSERTS
-#define NM_MORE_ASSERTS 0
-#endif
-
-#if NM_MORE_ASSERTS
-#define nm_assert(cond) G_STMT_START { g_assert (cond); } G_STMT_END
-#define nm_assert_se(cond) G_STMT_START { if (G_LIKELY (cond)) { ; } else { g_assert (FALSE && (cond)); } } G_STMT_END
-#define nm_assert_not_reached() G_STMT_START { g_assert_not_reached (); } G_STMT_END
-#else
-#define nm_assert(cond) G_STMT_START { if (FALSE) { if (cond) { } } } G_STMT_END
-#define nm_assert_se(cond) G_STMT_START { if (G_LIKELY (cond)) { ; } } G_STMT_END
-#define nm_assert_not_reached() G_STMT_START { ; } G_STMT_END
-#endif
+/* redefine assertions to use g_assert*() */
+#undef _nm_assert_call
+#undef _nm_assert_call_not_reached
+#define _nm_assert_call(cond) g_assert(cond)
+#define _nm_assert_call_not_reached() g_assert_not_reached()
/* Usage:
*
@@ -1170,9 +774,9 @@ nm_g_object_ref (gpointer obj)
static inline void
nm_g_object_unref (gpointer obj)
{
- /* g_object_unref() doesn't accept NULL. Usully, we workaround that
+ /* g_object_unref() doesn't accept NULL. Usually, we workaround that
* by using g_clear_object(), but sometimes that is not convenient
- * (for example as as destroy function for a hash table that can contain
+ * (for example as destroy function for a hash table that can contain
* NULL values). */
if (obj)
g_object_unref (obj);
@@ -1204,32 +808,6 @@ nm_g_object_unref (gpointer obj)
_changed; \
})
-#define nm_clear_pointer(pp, destroy) \
- ({ \
- typeof (*(pp)) *_pp = (pp); \
- typeof (*_pp) _p; \
- gboolean _changed = FALSE; \
- \
- if ( _pp \
- && (_p = *_pp)) { \
- _nm_unused gconstpointer _p_check_is_pointer = _p; \
- \
- *_pp = NULL; \
- /* g_clear_pointer() assigns @destroy first to a local variable, so that
- * you can call "g_clear_pointer (pp, (GDestroyNotify) destroy);" without
- * gcc emitting a warning. We don't do that, hence, you cannot cast
- * "destroy" first.
- *
- * On the upside: you are not supposed to cast fcn, because the pointer
- * types are preserved. If you really need a cast, you should cast @pp.
- * But that is hardly ever necessary. */ \
- (destroy) (_p); \
- \
- _changed = TRUE; \
- } \
- _changed; \
- })
-
/* basically, replaces
* g_clear_pointer (&location, g_free)
* with
@@ -1628,68 +1206,6 @@ nm_strcmp_p (gconstpointer a, gconstpointer b)
/*****************************************************************************/
-/* Taken from systemd's UNIQ_T and UNIQ macros. */
-
-#define NM_UNIQ_T(x, uniq) G_PASTE(__unique_prefix_, G_PASTE(x, uniq))
-#define NM_UNIQ __COUNTER__
-
-/*****************************************************************************/
-
-/* glib's MIN()/MAX() macros don't have function-like behavior, in that they evaluate
- * the argument possibly twice.
- *
- * Taken from systemd's MIN()/MAX() macros. */
-
-#define NM_MIN(a, b) __NM_MIN(NM_UNIQ, a, NM_UNIQ, b)
-#define __NM_MIN(aq, a, bq, b) \
- ({ \
- typeof (a) NM_UNIQ_T(A, aq) = (a); \
- typeof (b) NM_UNIQ_T(B, bq) = (b); \
- ((NM_UNIQ_T(A, aq) < NM_UNIQ_T(B, bq)) ? NM_UNIQ_T(A, aq) : NM_UNIQ_T(B, bq)); \
- })
-
-#define NM_MAX(a, b) __NM_MAX(NM_UNIQ, a, NM_UNIQ, b)
-#define __NM_MAX(aq, a, bq, b) \
- ({ \
- typeof (a) NM_UNIQ_T(A, aq) = (a); \
- typeof (b) NM_UNIQ_T(B, bq) = (b); \
- ((NM_UNIQ_T(A, aq) > NM_UNIQ_T(B, bq)) ? NM_UNIQ_T(A, aq) : NM_UNIQ_T(B, bq)); \
- })
-
-#define NM_CLAMP(x, low, high) __NM_CLAMP(NM_UNIQ, x, NM_UNIQ, low, NM_UNIQ, high)
-#define __NM_CLAMP(xq, x, lowq, low, highq, high) \
- ({ \
- typeof(x)NM_UNIQ_T(X,xq) = (x); \
- typeof(low) NM_UNIQ_T(LOW,lowq) = (low); \
- typeof(high) NM_UNIQ_T(HIGH,highq) = (high); \
- \
- ( (NM_UNIQ_T(X,xq) > NM_UNIQ_T(HIGH,highq)) \
- ? NM_UNIQ_T(HIGH,highq) \
- : (NM_UNIQ_T(X,xq) < NM_UNIQ_T(LOW,lowq)) \
- ? NM_UNIQ_T(LOW,lowq) \
- : NM_UNIQ_T(X,xq)); \
- })
-
-#define NM_MAX_WITH_CMP(cmp, a, b) \
- ({ \
- typeof (a) _a = (a); \
- typeof (b) _b = (b); \
- \
- ( ((cmp (_a, _b)) >= 0) \
- ? _a \
- : _b); \
- })
-
-/* evaluates to (void) if _A or _B are not constant or of different types */
-#define NM_CONST_MAX(_A, _B) \
- (__builtin_choose_expr (( __builtin_constant_p (_A) \
- && __builtin_constant_p (_B) \
- && __builtin_types_compatible_p (typeof (_A), typeof (_B))), \
- ((_A) > (_B)) ? (_A) : (_B), \
- ((void) 0)))
-
-/*****************************************************************************/
-
#define nm_g_slice_free(ptr) \
g_slice_free (typeof (*(ptr)), ptr)
@@ -1987,51 +1503,6 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro)
/*****************************************************************************/
-/**
- * The boolean type _Bool is C99 while we mostly stick to C89. However, _Bool is too
- * convenient to miss and is effectively available in gcc and clang. So, just use it.
- *
- * Usually, one would include "stdbool.h" to get the "bool" define which aliases
- * _Bool. We provide this define here, because we want to make use of it anywhere.
- * (also, stdbool.h is again C99).
- *
- * Using _Bool has advantages over gboolean:
- *
- * - commonly _Bool is one byte large, instead of gboolean's 4 bytes (because gboolean
- * is a typedef for int). Especially when having boolean fields in a struct, we can
- * thereby easily save some space.
- *
- * - _Bool type guarantees that two "true" expressions compare equal. E.g. the following
- * will not work:
- * gboolean v1 = 1;
- * gboolean v2 = 2;
- * g_assert_cmpint (v1, ==, v2); // will fail
- * For that, we often to use !! to coerce gboolean values to 0 or 1:
- * g_assert_cmpint (!!v2, ==, TRUE);
- * With _Bool type, this will be handled properly by the compiler.
- *
- * - For structs, we might want to safe even more space and use bitfields:
- * struct s1 {
- * gboolean v1:1;
- * };
- * But the problem here is that gboolean is signed, so that
- * v1 will be either 0 or -1 (not 1, TRUE). Thus, the following
- * fails:
- * struct s1 s = { .v1 = TRUE, };
- * g_assert_cmpint (s1.v1, ==, TRUE);
- * It will however work just fine with bool/_Bool while retaining the
- * notion of having a boolean value.
- *
- * Also, add the defines for "true" and "false". Those are nicely highlighted by the editor
- * as special types, contrary to glib's "TRUE"/"FALSE".
- */
-
-#ifndef bool
-#define bool _Bool
-#define true 1
-#define false 0
-#endif
-
#ifdef _G_BOOLEAN_EXPR
/* g_assert() uses G_LIKELY(), which in turn uses _G_BOOLEAN_EXPR().
* As glib's implementation uses a local variable _g_boolean_var_,
@@ -2044,70 +1515,11 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro)
* Workaround that by re-defining _G_BOOLEAN_EXPR()
**/
#undef _G_BOOLEAN_EXPR
-#define __NM_G_BOOLEAN_EXPR_IMPL(v, expr) \
- ({ \
- int NM_UNIQ_T(V, v); \
- \
- if (expr) \
- NM_UNIQ_T(V, v) = 1; \
- else \
- NM_UNIQ_T(V, v) = 0; \
- NM_UNIQ_T(V, v); \
- })
-#define _G_BOOLEAN_EXPR(expr) __NM_G_BOOLEAN_EXPR_IMPL (NM_UNIQ, expr)
+#define _G_BOOLEAN_EXPR(expr) NM_BOOLEAN_EXPR (expr)
#endif
/*****************************************************************************/
-/**
- * nm_steal_int:
- * @p_val: pointer to an int type.
- *
- * Returns: *p_val and sets *p_val to zero the same time.
- * Accepts %NULL, in which case also numeric 0 will be returned.
- */
-#define nm_steal_int(p_val) \
- ({ \
- typeof (p_val) const _p_val = (p_val); \
- typeof (*_p_val) _val = 0; \
- \
- if ( _p_val \
- && (_val = *_p_val)) { \
- *_p_val = 0; \
- } \
- _val; \
- })
-
-static inline int
-nm_steal_fd (int *p_fd)
-{
- int fd;
-
- if ( p_fd
- && ((fd = *p_fd) >= 0)) {
- *p_fd = -1;
- return fd;
- }
- return -1;
-}
-
-/**
- * nm_close:
- *
- * Like close() but throws an assertion if the input fd is
- * invalid. Closing an invalid fd is a programming error, so
- * it's better to catch it early.
- */
-static inline int
-nm_close (int fd)
-{
- int r;
-
- r = close (fd);
- nm_assert (r != -1 || fd < 0 || errno != EBADF);
- return r;
-}
-
#define NM_PID_T_INVAL ((pid_t) -1)
/*****************************************************************************/
diff --git a/shared/nm-glib-aux/nm-ref-string.c b/shared/nm-glib-aux/nm-ref-string.c
index 0a0b0d3a41..ccc29303b3 100644
--- a/shared/nm-glib-aux/nm-ref-string.c
+++ b/shared/nm-glib-aux/nm-ref-string.c
@@ -70,7 +70,7 @@ _ASSERT (const RefString *rstr0)
* nm_ref_string_new_len:
* @cstr: the string to intern. Must contain @len bytes.
* If @len is zero, @cstr may be %NULL. Note that it is
- * accetable that the string contains a NUL character
+ * acceptable that the string contains a NUL character
* within the first @len bytes. That is, the string is
* not treated as a NUL terminated string, but as binary.
* Also, contrary to strncpy(), this will read all the
@@ -83,7 +83,7 @@ _ASSERT (const RefString *rstr0)
* (at position @len).
*
* Note that NMRefString are always interned/deduplicated. If such a string
- * already exists, the existing instance will be refered and returned.
+ * already exists, the existing instance will be referred and returned.
*
*
* Since all NMRefString are shared and interned, you may use
diff --git a/shared/nm-glib-aux/nm-secret-utils.h b/shared/nm-glib-aux/nm-secret-utils.h
index 501e752071..de9f33eaa0 100644
--- a/shared/nm-glib-aux/nm-secret-utils.h
+++ b/shared/nm-glib-aux/nm-secret-utils.h
@@ -165,7 +165,7 @@ gboolean nm_utils_memeqzero_secret (gconstpointer data, gsize length);
* Otherwise, this will allocate a new buffer of the desired size, copy over the
* old data, and bzero the old buffer before freeing it. As such, it also behaves
* similar to g_realloc(), with the overhead of nm_explicit_bzero() and using
- * malloc/free intead of realloc().
+ * malloc/free instead of realloc().
*
* Returns: the new allocated buffer. Think of it behaving like g_realloc().
*/
@@ -200,7 +200,7 @@ nm_secret_mem_realloc (gpointer m_old, gboolean do_bzero_mem, gsize cur_len, gsi
* Otherwise, this will try to allocate a new buffer of the desired size, copy over the
* old data, and bzero the old buffer before freeing it. As such, it also behaves
* similar to g_try_realloc(), with the overhead of nm_explicit_bzero() and using
- * malloc/free intead of realloc().
+ * malloc/free instead of realloc().
*
* Returns: the new allocated buffer or NULL. Think of it behaving like g_try_realloc().
*/
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
index 681b4dd14a..ee917fdf6e 100644
--- a/shared/nm-glib-aux/nm-shared-utils.c
+++ b/shared/nm-glib-aux/nm-shared-utils.c
@@ -23,6 +23,9 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMUtilsNamedValue, value_ptr) == sizeof (const
/*****************************************************************************/
+const char _nm_hexchar_table_lower[16] = "0123456789abcdef";
+const char _nm_hexchar_table_upper[16] = "0123456789ABCDEF";
+
const void *const _NM_PTRARRAY_EMPTY[1] = { NULL };
/*****************************************************************************/
@@ -94,75 +97,6 @@ G_STATIC_ASSERT (ETH_ALEN == 6);
/*****************************************************************************/
-gsize
-nm_utils_get_next_realloc_size (gboolean true_realloc, gsize requested)
-{
- gsize n, x;
-
- /* https://doc.qt.io/qt-5/containers.html#growth-strategies */
-
- if (requested <= 40) {
- /* small allocations. Increase in small steps of 8 bytes.
- *
- * We get thus sizes of 8, 16, 32, 40. */
- if (requested <= 8)
- return 8;
- if (requested <= 16)
- return 16;
- if (requested <= 32)
- return 32;
-
- /* The return values for < 104 are essentially hard-coded, and the choice here is
- * made without very strong reasons.
- *
- * We want to stay 24 bytes below the power-of-two border 64. Hence, return 40 here.
- * However, the next step then is already 104 (128 - 24). It's a larger gap than in
- * the steps before.
- *
- * It's not clear whether some of the steps should be adjusted (or how exactly). */
- return 40;
- }
-
- if ( requested <= 0x2000u - 24u
- || G_UNLIKELY (!true_realloc)) {
- /* mid sized allocations. Return next power of two, minus 24 bytes extra space
- * at the beginning.
- * That means, we double the size as we grow.
- *
- * With !true_realloc, it means that the caller does not intend to call
- * realloc() but instead clone the buffer. This is for example the case, when we
- * want to nm_explicit_bzero() the old buffer. In that case we really want to grow
- * the buffer exponentially every time and not increment in page sizes of 4K (below).
- *
- * We get thus sizes of 104, 232, 488, 1000, 2024, 4072, 8168... */
-
- if (G_UNLIKELY (requested > G_MAXSIZE / 2u - 24u))
- return G_MAXSIZE;
-
- x = requested + 24u;
- n = 128u;
- while (n < x) {
- n <<= 1;
- nm_assert (n > 128u);
- }
-
- nm_assert (n > 24u && n - 24u >= requested);
- return n - 24u;
- }
-
- if (G_UNLIKELY (requested > G_MAXSIZE - 0x1000u - 24u))
- return G_MAXSIZE;
-
- /* For large allocations (with !true_realloc) we allocate memory in chunks of
- * 4K (- 24 bytes extra), assuming that the memory gets mmapped and thus
- * realloc() is efficient by just reordering pages. */
- n = ((requested + (0x0FFFu + 24u)) & ~((gsize) 0x0FFFu)) - 24u;
- nm_assert (n >= requested);
- return n;
-}
-
-/*****************************************************************************/
-
pid_t
nm_utils_gettid (void)
{
@@ -443,7 +377,7 @@ nm_utils_gbytes_equal_mem (GBytes *bytes,
gsize l;
if (!bytes) {
- /* as a special case, let %NULL GBytes compare idential
+ /* as a special case, let %NULL GBytes compare identical
* to an empty array. */
return (mem_len == 0);
}
@@ -478,50 +412,52 @@ nm_utils_gbytes_to_variant_ay (GBytes *bytes)
GVariant *
nm_utils_strdict_to_variant_ass (GHashTable *strdict)
{
- GHashTableIter iter;
- const char *key, *value;
+ gs_free NMUtilsNamedValue *values_free = NULL;
+ NMUtilsNamedValue values_prepared[20];
+ const NMUtilsNamedValue *values;
GVariantBuilder builder;
- guint i, len;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
-
- if (!strdict)
- goto out;
- len = g_hash_table_size (strdict);
- if (!len)
- goto out;
+ guint i;
+ guint n;
- g_hash_table_iter_init (&iter, strdict);
- if (!g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value))
- nm_assert_not_reached ();
+ values = nm_utils_named_values_from_strdict (strdict,
+ &n,
+ values_prepared,
+ &values_free);
- if (len == 1)
- g_variant_builder_add (&builder, "{ss}", key, value);
- else {
- gs_free NMUtilsNamedValue *idx_free = NULL;
- NMUtilsNamedValue *idx;
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
+ for (i = 0; i < n; i++) {
+ g_variant_builder_add (&builder,
+ "{ss}",
+ values[i].name,
+ values[i].value_str);
+ }
+ return g_variant_builder_end (&builder);
+}
- if (len > 300 / sizeof (NMUtilsNamedValue)) {
- idx_free = g_new (NMUtilsNamedValue, len);
- idx = idx_free;
- } else
- idx = g_alloca (sizeof (NMUtilsNamedValue) * len);
+/*****************************************************************************/
- i = 0;
- do {
- idx[i].name = key;
- idx[i].value_str = value;
- i++;
- } while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value));
- nm_assert (i == len);
+GVariant *
+nm_utils_strdict_to_variant_asv (GHashTable *strdict)
+{
+ gs_free NMUtilsNamedValue *values_free = NULL;
+ NMUtilsNamedValue values_prepared[20];
+ const NMUtilsNamedValue *values;
+ GVariantBuilder builder;
+ guint i;
+ guint n;
- nm_utils_named_value_list_sort (idx, len, NULL, NULL);
+ values = nm_utils_named_values_from_strdict (strdict,
+ &n,
+ values_prepared,
+ &values_free);
- for (i = 0; i < len; i++)
- g_variant_builder_add (&builder, "{ss}", idx[i].name, idx[i].value_str);
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+ for (i = 0; i < n; i++) {
+ g_variant_builder_add (&builder,
+ "{sv}",
+ values[i].name,
+ g_variant_new_string (values[i].value_str));
}
-
-out:
return g_variant_builder_end (&builder);
}
@@ -1075,39 +1011,53 @@ nm_utils_parse_next_line (const char **inout_ptr,
const char **out_line,
gsize *out_line_len)
{
+ gboolean eol_is_carriage_return;
const char *line_start;
- const char *line_end;
+ gsize line_len;
- g_return_val_if_fail (inout_ptr, FALSE);
- g_return_val_if_fail (inout_len, FALSE);
- g_return_val_if_fail (out_line, FALSE);
+ nm_assert (inout_ptr);
+ nm_assert (inout_len);
+ nm_assert (*inout_len == 0 || *inout_ptr);
+ nm_assert (out_line);
+ nm_assert (out_line_len);
- if (*inout_len <= 0)
- goto error;
+ if (G_UNLIKELY (*inout_len == 0))
+ return FALSE;
line_start = *inout_ptr;
- line_end = memchr (line_start, '\n', *inout_len);
- if (!line_end)
- line_end = memchr (line_start, '\0', *inout_len);
- if (!line_end) {
- line_end = line_start + *inout_len;
- NM_SET_OUT (inout_len, 0);
- } else
- NM_SET_OUT (inout_len, *inout_len - (line_end - line_start) - 1);
- NM_SET_OUT (out_line, line_start);
- NM_SET_OUT (out_line_len, (gsize) (line_end - line_start));
+ eol_is_carriage_return = FALSE;
+ for (line_len = 0; ; line_len++) {
+ if (line_len >= *inout_len) {
+ /* if we consumed the entire line, we place the pointer at
+ * one character after the end. */
+ *inout_ptr = &line_start[line_len];
+ *inout_len = 0;
+ goto done;
+ }
+ switch (line_start[line_len]) {
+ case '\r':
+ eol_is_carriage_return = TRUE;
+ /* fall-through*/
+ case '\0':
+ case '\n':
+ *inout_ptr = &line_start[line_len + 1];
+ *inout_len = *inout_len - line_len - 1u;
+ if ( eol_is_carriage_return
+ && *inout_len > 0
+ && (*inout_ptr)[0] == '\n') {
+ /* also consume "\r\n" as one. */
+ (*inout_len)--;
+ (*inout_ptr)++;
+ }
+ goto done;
+ }
+ }
- if (*inout_len > 0)
- NM_SET_OUT (inout_ptr, line_end + 1);
- else
- NM_SET_OUT (inout_ptr, NULL);
+done:
+ *out_line = line_start;
+ *out_line_len = line_len;
return TRUE;
-
-error:
- NM_SET_OUT (out_line, NULL);
- NM_SET_OUT (out_line_len, 0);
- return FALSE;
}
/*****************************************************************************/
@@ -1529,7 +1479,7 @@ nm_utils_dbus_path_cmp (const char *dbus_path_a, const char *dbus_path_b)
if (n_a == -1 && n_b == -1)
goto comp_l;
- /* both components must be convertiable to a number. If they are not,
+ /* both components must be convertible to a number. If they are not,
* (and only one of them is), then we must always strictly sort numeric parts
* after non-numeric components. If we wouldn't, we wouldn't have
* a total order.
@@ -3045,28 +2995,44 @@ nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll)
/*****************************************************************************/
+G_STATIC_ASSERT (G_STRUCT_OFFSET (NMUtilsNamedValue, name) == 0);
+
NMUtilsNamedValue *
-nm_utils_named_values_from_str_dict_with_sort (GHashTable *hash,
- guint *out_len,
- GCompareDataFunc compare_func,
- gpointer user_data)
+nm_utils_named_values_from_strdict_full (GHashTable *hash,
+ guint *out_len,
+ GCompareDataFunc compare_func,
+ gpointer user_data,
+ NMUtilsNamedValue *provided_buffer,
+ guint provided_buffer_len,
+ NMUtilsNamedValue **out_allocated_buffer)
{
GHashTableIter iter;
NMUtilsNamedValue *values;
guint i, len;
+ nm_assert (provided_buffer_len == 0 || provided_buffer);
+ nm_assert (!out_allocated_buffer || !*out_allocated_buffer);
+
if ( !hash
|| !(len = g_hash_table_size (hash))) {
NM_SET_OUT (out_len, 0);
return NULL;
}
+ if (provided_buffer_len >= len + 1) {
+ /* the buffer provided by the caller is large enough. Use it. */
+ values = provided_buffer;
+ } else {
+ /* allocate a new buffer. */
+ values = g_new (NMUtilsNamedValue, len + 1);
+ NM_SET_OUT (out_allocated_buffer, values);
+ }
+
i = 0;
- values = g_new (NMUtilsNamedValue, len + 1);
g_hash_table_iter_init (&iter, hash);
while (g_hash_table_iter_next (&iter,
(gpointer *) &values[i].name,
- (gpointer *) &values[i].value_ptr))
+ &values[i].value_ptr))
i++;
nm_assert (i == len);
values[i].name = NULL;
@@ -3324,7 +3290,7 @@ nm_utils_strv_make_deep_copied_n (const char **strv, gsize len)
*
* Note that if @len is non-negative, then it still must not
* contain any %NULL pointers within the first @len elements.
- * Otherwise you would leak elements if you try to free the
+ * Otherwise, you would leak elements if you try to free the
* array with g_strfreev(). Allowing that would be error prone.
*
* Returns: (transfer full): a clone of the strv array. Always
@@ -3779,7 +3745,7 @@ nm_utils_g_slist_find_str (const GSList *list,
* @b: the right #GSList of strings to compare.
*
* Compares two string lists. The data elements are compared with
- * strcmp(), alloing %NULL elements.
+ * strcmp(), allowing %NULL elements.
*
* Returns: 0, 1, or -1, depending on how the lists compare.
*/
@@ -4046,7 +4012,7 @@ nm_utils_memeqzero (gconstpointer data, gsize length)
* Returns: the binary value converted to a hex string. If @out is given,
* this always returns @out. If @out is %NULL, a newly allocated string
* is returned. This never returns %NULL, for buffers of length zero
- * an empty string is returend.
+ * an empty string is returned.
*/
char *
nm_utils_bin2hexstr_full (gconstpointer addr,
@@ -4949,7 +4915,7 @@ _nm_str_buf_ensure_size (NMStrBuf *strbuf,
{
_nm_str_buf_assert (strbuf);
- /* Currently this only supports strictly growing the buffer. */
+ /* Currently, this only supports strictly growing the buffer. */
nm_assert (new_size > strbuf->_priv_allocated);
if (!reserve_exact) {
@@ -5056,9 +5022,11 @@ void
_nm_utils_format_variant_attributes_full (GString *str,
const NMUtilsNamedValue *values,
guint num_values,
+ const NMVariantAttributeSpec *const *spec,
char attr_separator,
char key_value_separator)
{
+ const NMVariantAttributeSpec *const *s;
const char *name, *value;
GVariant *variant;
char *escaped;
@@ -5068,8 +5036,19 @@ _nm_utils_format_variant_attributes_full (GString *str,
for (i = 0; i < num_values; i++) {
name = values[i].name;
- variant = (GVariant *) values[i].value_ptr;
+ variant = values[i].value_ptr;
value = NULL;
+ s = NULL;
+
+ if (spec) {
+ for (s = spec; *s; s++) {
+ if (nm_streq0 ((*s)->name, name))
+ break;
+ }
+
+ if (!*s)
+ continue;
+ }
if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32))
value = nm_sprintf_buf (buf, "%u", g_variant_get_uint32 (variant));
@@ -5097,11 +5076,13 @@ _nm_utils_format_variant_attributes_full (GString *str,
g_string_append (str, escaped);
g_free (escaped);
- g_string_append_c (str, key_value_separator);
+ if (!s || !*s || !(*s)->no_value) {
+ g_string_append_c (str, key_value_separator);
- escaped = attribute_escape (value, attr_separator, key_value_separator);
- g_string_append (str, escaped);
- g_free (escaped);
+ escaped = attribute_escape (value, attr_separator, key_value_separator);
+ g_string_append (str, escaped);
+ g_free (escaped);
+ }
sep = attr_separator;
}
@@ -5109,25 +5090,34 @@ _nm_utils_format_variant_attributes_full (GString *str,
char *
_nm_utils_format_variant_attributes (GHashTable *attributes,
+ const NMVariantAttributeSpec *const *spec,
char attr_separator,
char key_value_separator)
{
+ gs_free NMUtilsNamedValue *values_free = NULL;
+ NMUtilsNamedValue values_prepared[20];
+ const NMUtilsNamedValue *values;
GString *str = NULL;
- gs_free NMUtilsNamedValue *values = NULL;
guint len;
g_return_val_if_fail (attr_separator, NULL);
g_return_val_if_fail (key_value_separator, NULL);
- if (!attributes || !g_hash_table_size (attributes))
+ if (!attributes)
return NULL;
- values = nm_utils_named_values_from_str_dict (attributes, &len);
+ values = nm_utils_named_values_from_strdict (attributes,
+ &len,
+ values_prepared,
+ &values_free);
+ if (len == 0)
+ return NULL;
str = g_string_new ("");
_nm_utils_format_variant_attributes_full (str,
values,
len,
+ spec,
attr_separator,
key_value_separator);
return g_string_free (str, FALSE);
diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h
index b17c8d1a09..ac091d8230 100644
--- a/shared/nm-glib-aux/nm-shared-utils.h
+++ b/shared/nm-glib-aux/nm-shared-utils.h
@@ -422,6 +422,7 @@ gboolean nm_utils_gbytes_equal_mem (GBytes *bytes,
GVariant *nm_utils_gbytes_to_variant_ay (GBytes *bytes);
GVariant *nm_utils_strdict_to_variant_ass (GHashTable *strdict);
+GVariant *nm_utils_strdict_to_variant_asv (GHashTable *strdict);
/*****************************************************************************/
@@ -630,23 +631,24 @@ nm_utils_escaped_tokens_escape (const char *str,
out_to_free);
}
-static inline GString *
-nm_utils_escaped_tokens_escape_gstr_assert (const char *str,
- const char *delimiters,
- GString *gstring)
+/**
+ * nm_utils_escaped_tokens_escape_unnecessary:
+ * @str: the string to check for "escape"
+ * @delimiters: the delimiters
+ *
+ * This asserts that calling nm_utils_escaped_tokens_escape()
+ * on @str has no effect and returns @str directly. This is only
+ * for asserting that @str is safe to not require any escaping.
+ *
+ * Returns: @str
+ */
+static inline const char *
+nm_utils_escaped_tokens_escape_unnecessary (const char *str,
+ const char *delimiters)
{
#if NM_MORE_ASSERTS > 0
- /* Just appends @str to @gstring, but also assert that
- * no escaping is necessary.
- *
- * Use nm_utils_escaped_tokens_escape_gstr_assert() instead
- * of nm_utils_escaped_tokens_escape_gstr(), if you *know* that
- * @str contains no delimiters, no backslashes, and no trailing
- * whitespace that requires escaping. */
-
nm_assert (str);
- nm_assert (gstring);
nm_assert (delimiters);
{
@@ -659,8 +661,16 @@ nm_utils_escaped_tokens_escape_gstr_assert (const char *str,
}
#endif
- g_string_append (gstring, str);
- return gstring;
+ return str;
+}
+
+static inline void
+nm_utils_escaped_tokens_escape_gstr_assert (const char *str,
+ const char *delimiters,
+ GString *gstring)
+{
+ g_string_append (gstring,
+ nm_utils_escaped_tokens_escape_unnecessary (str, delimiters));
}
static inline GString *
@@ -996,7 +1006,7 @@ nm_g_set_error_take (GError **error, GError *error_take)
* NMUtilsError:
* @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error
* @NM_UTILS_ERROR_CANCELLED_DISPOSING: when disposing an object that has
- * pending aynchronous operations, the operation is cancelled with this
+ * pending asynchronous operations, the operation is cancelled with this
* error reason. Depending on the usage, this might indicate a bug because
* usually the target object should stay alive as long as there are pending
* operations.
@@ -1455,24 +1465,22 @@ typedef struct {
};
union {
const char *value_str;
- gconstpointer value_ptr;
+ gpointer value_ptr;
};
} NMUtilsNamedValue;
#define NM_UTILS_NAMED_VALUE_INIT(n, v) { .name = (n), .value_ptr = (v) }
-NMUtilsNamedValue *nm_utils_named_values_from_str_dict_with_sort (GHashTable *hash,
- guint *out_len,
- GCompareDataFunc compare_func,
- gpointer user_data);
+NMUtilsNamedValue *nm_utils_named_values_from_strdict_full (GHashTable *hash,
+ guint *out_len,
+ GCompareDataFunc compare_func,
+ gpointer user_data,
+ NMUtilsNamedValue *provided_buffer,
+ guint provided_buffer_len,
+ NMUtilsNamedValue **out_allocated_buffer);
-static inline NMUtilsNamedValue *
-nm_utils_named_values_from_str_dict (GHashTable *hash, guint *out_len)
-{
- G_STATIC_ASSERT (G_STRUCT_OFFSET (NMUtilsNamedValue, name) == 0);
-
- return nm_utils_named_values_from_str_dict_with_sort (hash, out_len, nm_strcmp_p_with_data, NULL);
-}
+#define nm_utils_named_values_from_strdict(hash, out_len, array, out_allocated_buffer) \
+ nm_utils_named_values_from_strdict_full ((hash), (out_len), nm_strcmp_p_with_data, NULL, (array), G_N_ELEMENTS (array), (out_allocated_buffer))
gssize nm_utils_named_value_list_find (const NMUtilsNamedValue *arr,
gsize len,
@@ -1734,7 +1742,7 @@ static inline gboolean
nm_utils_process_state_is_dead (char pstate)
{
/* "/proc/[pid]/stat" returns a state as the 3rd fields (see `man 5 proc`).
- * Some of these states indicate the the process is effectively dead (or a zombie).
+ * Some of these states indicate the process is effectively dead (or a zombie).
*/
return NM_IN_SET (pstate, 'Z', 'x', 'X');
}
@@ -1815,6 +1823,17 @@ int nm_utils_getpagesize (void);
/*****************************************************************************/
+extern const char _nm_hexchar_table_lower[16];
+extern const char _nm_hexchar_table_upper[16];
+
+static inline char
+nm_hexchar (int x, gboolean upper_case)
+{
+ return upper_case
+ ? _nm_hexchar_table_upper[x & 15]
+ : _nm_hexchar_table_lower[x & 15];
+}
+
char *nm_utils_bin2hexstr_full (gconstpointer addr,
gsize length,
char delimiter,
@@ -1974,30 +1993,6 @@ void nm_indirect_g_free (gpointer arg);
/*****************************************************************************/
-/* nm_utils_get_next_realloc_size() is used to grow buffers exponentially, when
- * the final size is unknown. As such, it has borders for which it allocates
- * certain buffer sizes.
- *
- * The use of these defines is to get favorable allocation sequences.
- * For example, nm_str_buf_init() asks for an initial allocation size. Note that
- * it reserves the exactly requested amount, under the assumption that the
- * user may know how many bytes will be required. However, often the caller
- * doesn't know in advance, and NMStrBuf grows exponentially by calling
- * nm_utils_get_next_realloc_size().
- * Imagine you call nm_str_buf_init() with an initial buffer size 100, and you
- * add one character at a time. Then the first reallocation will increase the
- * buffer size only from 100 to 104.
- * If you however start with an initial buffer size of 104, then the next reallocation
- * via nm_utils_get_next_realloc_size() gives you 232, and so on. By using
- * these sizes, it results in one less allocation, if you anyway don't know the
- * exact size in advance. */
-#define NM_UTILS_GET_NEXT_REALLOC_SIZE_104 ((gsize) 104)
-#define NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 ((gsize) 1000)
-
-gsize nm_utils_get_next_realloc_size (gboolean true_realloc, gsize requested);
-
-/*****************************************************************************/
-
typedef enum {
NMU_IFACE_ANY,
NMU_IFACE_KERNEL,
@@ -2073,13 +2068,27 @@ nm_strvarray_set_strv (GArray **array, const char *const*strv)
/*****************************************************************************/
+struct _NMVariantAttributeSpec {
+ char *name;
+ const GVariantType *type;
+ bool v4:1;
+ bool v6:1;
+ bool no_value:1;
+ bool consumes_rest:1;
+ char str_type;
+};
+
+typedef struct _NMVariantAttributeSpec NMVariantAttributeSpec;
+
void _nm_utils_format_variant_attributes_full (GString *str,
const NMUtilsNamedValue *values,
guint num_values,
+ const NMVariantAttributeSpec *const *spec,
char attr_separator,
char key_value_separator);
char *_nm_utils_format_variant_attributes (GHashTable *attributes,
+ const NMVariantAttributeSpec *const *spec,
char attr_separator,
char key_value_separator);
diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h
index da082abe67..79de2d738f 100644
--- a/shared/nm-glib-aux/nm-str-buf.h
+++ b/shared/nm-glib-aux/nm-str-buf.h
@@ -85,9 +85,9 @@ nm_str_buf_maybe_expand (NMStrBuf *strbuf,
* nm_str_buf_set_size:
* @strbuf: the initialized #NMStrBuf
* @new_len: the new length
- * @honor_do_bzero_mem: if %TRUE, the shrinked memory will be cleared, if
+ * @honor_do_bzero_mem: if %TRUE, the shrunk memory will be cleared, if
* do_bzero_mem is set. This should be usually set to %TRUE, unless
- * you know that the shrinked memory does not contain data that requires to be
+ * you know that the shrunk memory does not contain data that requires to be
* cleared. When growing the size, this value has no effect.
* @reserve_exact: when growing the buffer, reserve the exact amount of bytes.
* If %FALSE, the buffer may allocate more memory than requested to grow
@@ -212,6 +212,16 @@ nm_str_buf_append_c4 (NMStrBuf *strbuf,
}
static inline void
+nm_str_buf_append_c_hex (NMStrBuf *strbuf,
+ char ch,
+ gboolean upper_case)
+{
+ nm_str_buf_maybe_expand (strbuf, 3, FALSE);
+ strbuf->_priv_str[strbuf->_priv_len++] = nm_hexchar (((guchar) ch) >> 4, upper_case);
+ strbuf->_priv_str[strbuf->_priv_len++] = nm_hexchar ((guchar) ch, upper_case);
+}
+
+static inline void
nm_str_buf_append_len (NMStrBuf *strbuf,
const char *str,
gsize len)
@@ -225,6 +235,25 @@ nm_str_buf_append_len (NMStrBuf *strbuf,
}
}
+static inline char *
+nm_str_buf_append_len0 (NMStrBuf *strbuf,
+ const char *str,
+ gsize len)
+{
+ _nm_str_buf_assert (strbuf);
+
+ /* this is basically like nm_str_buf_append_len() and
+ * nm_str_buf_get_str() in one. */
+
+ nm_str_buf_maybe_expand (strbuf, len + 1u, FALSE);
+ if (len > 0) {
+ memcpy (&strbuf->_priv_str[strbuf->_priv_len], str, len);
+ strbuf->_priv_len += len;
+ }
+ strbuf->_priv_str[strbuf->_priv_len] = '\0';
+ return strbuf->_priv_str;
+}
+
static inline void
nm_str_buf_append (NMStrBuf *strbuf,
const char *str)
@@ -234,6 +263,15 @@ nm_str_buf_append (NMStrBuf *strbuf,
nm_str_buf_append_len (strbuf, str, strlen (str));
}
+static inline char *
+nm_str_buf_append0 (NMStrBuf *strbuf,
+ const char *str)
+{
+ nm_assert (str);
+
+ return nm_str_buf_append_len0 (strbuf, str, strlen (str));
+}
+
void nm_str_buf_append_printf (NMStrBuf *strbuf,
const char *format,
...) _nm_printf (2, 3);
@@ -248,6 +286,65 @@ nm_str_buf_ensure_trailing_c (NMStrBuf *strbuf, char ch)
nm_str_buf_append_c (strbuf, ch);
}
+static inline NMStrBuf *
+nm_str_buf_append_required_delimiter (NMStrBuf *strbuf,
+ char delimiter)
+{
+ _nm_str_buf_assert (strbuf);
+
+ /* appends the @delimiter if it is required (that is, if the
+ * string is not empty). */
+ if (strbuf->len > 0)
+ nm_str_buf_append_c (strbuf, delimiter);
+ return strbuf;
+}
+
+static inline void
+nm_str_buf_reset (NMStrBuf *strbuf,
+ const char *str)
+{
+ _nm_str_buf_assert (strbuf);
+
+ if (strbuf->_priv_len > 0) {
+ if (strbuf->_priv_do_bzero_mem) {
+ /* we only clear the memory that we wrote to. */
+ nm_explicit_bzero (strbuf->_priv_str, strbuf->_priv_len);
+ }
+ strbuf->_priv_len = 0;
+ }
+
+ if (str)
+ nm_str_buf_append (strbuf, str);
+}
+
+/*****************************************************************************/
+
+/* Calls nm_utils_escaped_tokens_escape() on @str and appends the
+ * result to @strbuf. */
+static inline void
+nm_utils_escaped_tokens_escape_strbuf (const char *str,
+ const char *delimiters,
+ NMStrBuf *strbuf)
+{
+ gs_free char *str_to_free = NULL;
+
+ nm_assert (str);
+
+ nm_str_buf_append (strbuf,
+ nm_utils_escaped_tokens_escape (str, delimiters, &str_to_free));
+}
+
+/* Calls nm_utils_escaped_tokens_escape_unnecessary() on @str and appends the
+ * string to @strbuf. */
+static inline void
+nm_utils_escaped_tokens_escape_strbuf_assert (const char *str,
+ const char *delimiters,
+ NMStrBuf *strbuf)
+{
+ nm_str_buf_append (strbuf,
+ nm_utils_escaped_tokens_escape_unnecessary (str, delimiters));
+}
+
/*****************************************************************************/
static inline gboolean
@@ -332,6 +429,23 @@ nm_str_buf_finalize (NMStrBuf *strbuf,
return g_steal_pointer (&strbuf->_priv_str);
}
+static inline GBytes *
+nm_str_buf_finalize_to_gbytes (NMStrBuf *strbuf)
+{
+ char *s;
+ gsize l;
+
+ /* this always returns a non-NULL, newly allocated GBytes instance.
+ * The data buffer always has an additional NUL character after
+ * the data, and the data is allocated with malloc.
+ *
+ * That means, the caller who takes ownership of the GBytes can
+ * safely modify the content of the buffer (including the additional
+ * NUL sentinel). */
+ s = nm_str_buf_finalize (strbuf, &l);
+ return g_bytes_new_take (s ?: g_new0 (char, 1), l);
+}
+
/**
* nm_str_buf_destroy:
* @strbuf: an initialized #NMStrBuf
diff --git a/shared/nm-glib-aux/tests/meson.build b/shared/nm-glib-aux/tests/meson.build
index f6328db916..8136eff935 100644
--- a/shared/nm-glib-aux/tests/meson.build
+++ b/shared/nm-glib-aux/tests/meson.build
@@ -1,23 +1,43 @@
# SPDX-License-Identifier: LGPL-2.1+
-test_unit = 'test-shared-general'
-
-c_flags = [
- '-DNETWORKMANAGER_COMPILATION_TEST',
- '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)',
-]
-
exe = executable(
- test_unit,
- test_unit + '.c',
- c_args: c_flags,
+ 'test-shared-general',
+ 'test-shared-general.c',
+ c_args: [
+ '-DNETWORKMANAGER_COMPILATION_TEST',
+ '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)',
+ ],
dependencies: libnm_utils_base_dep,
link_with: libnm_systemd_logging_stub,
)
test(
- 'shared/nm-glib-aux/' + test_unit,
+ 'shared/nm-glib-aux/test-shared-general',
test_script,
args: test_args + [exe.full_path()],
timeout: default_test_timeout,
)
+
+if jansson_dep.found()
+ exe = executable(
+ 'test-json-aux',
+ 'test-json-aux.c',
+ c_args: [
+ '-DNETWORKMANAGER_COMPILATION_TEST',
+ '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)',
+ ],
+ dependencies: [
+ libnm_utils_base_dep,
+ jansson_dep,
+ dl_dep,
+ ],
+ link_with: libnm_systemd_logging_stub,
+ )
+
+ test(
+ 'shared/nm-glib-aux/test-json-aux',
+ test_script,
+ args: test_args + [exe.full_path()],
+ timeout: default_test_timeout,
+ )
+endif
diff --git a/shared/nm-glib-aux/tests/test-json-aux.c b/shared/nm-glib-aux/tests/test-json-aux.c
new file mode 100644
index 0000000000..cde1bef3b0
--- /dev/null
+++ b/shared/nm-glib-aux/tests/test-json-aux.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: LGPL-2.1+
+
+#define NM_TEST_UTILS_NO_LIBNM 1
+
+#include "nm-default.h"
+
+#include <jansson.h>
+
+#include "nm-glib-aux/nm-json-aux.h"
+
+#include "nm-utils/nm-test-utils.h"
+
+/*****************************************************************************/
+
+static void
+test_jansson (void)
+{
+ const NMJsonVt *vt;
+ nm_auto_decref_json nm_json_t *js1 = NULL;
+ nm_auto_decref_json nm_json_t *js2 = NULL;
+
+#define _ASSERT_FIELD(type1, type2, field) \
+ G_STMT_START { \
+ G_STATIC_ASSERT_EXPR (sizeof (((type1 *) NULL)->field) == sizeof (((type2 *) NULL)->field)); \
+ G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (type1, field) == G_STRUCT_OFFSET (type2, field)); \
+ } G_STMT_END
+
+ G_STATIC_ASSERT_EXPR (NM_JSON_REJECT_DUPLICATES == JSON_REJECT_DUPLICATES);
+
+ G_STATIC_ASSERT_EXPR (sizeof (nm_json_type) == sizeof (json_type));
+
+ G_STATIC_ASSERT_EXPR ((int) NM_JSON_OBJECT == JSON_OBJECT);
+ G_STATIC_ASSERT_EXPR ((int) NM_JSON_ARRAY == JSON_ARRAY);
+ G_STATIC_ASSERT_EXPR ((int) NM_JSON_STRING == JSON_STRING);
+ G_STATIC_ASSERT_EXPR ((int) NM_JSON_INTEGER == JSON_INTEGER);
+ G_STATIC_ASSERT_EXPR ((int) NM_JSON_REAL == JSON_REAL);
+ G_STATIC_ASSERT_EXPR ((int) NM_JSON_TRUE == JSON_TRUE);
+ G_STATIC_ASSERT_EXPR ((int) NM_JSON_FALSE == JSON_FALSE);
+ G_STATIC_ASSERT_EXPR ((int) NM_JSON_NULL == JSON_NULL);
+
+ G_STATIC_ASSERT_EXPR (sizeof (nm_json_int_t) == sizeof (json_int_t));
+
+ G_STATIC_ASSERT_EXPR (sizeof (nm_json_t) == sizeof (json_t));
+ _ASSERT_FIELD (nm_json_t, json_t, refcount);
+ _ASSERT_FIELD (nm_json_t, json_t, type);
+
+ G_STATIC_ASSERT_EXPR (NM_JSON_ERROR_TEXT_LENGTH == JSON_ERROR_TEXT_LENGTH);
+ G_STATIC_ASSERT_EXPR (NM_JSON_ERROR_SOURCE_LENGTH == JSON_ERROR_SOURCE_LENGTH);
+
+ G_STATIC_ASSERT_EXPR (sizeof (nm_json_error_t) == sizeof (json_error_t));
+ _ASSERT_FIELD (nm_json_error_t, json_error_t, line);
+ _ASSERT_FIELD (nm_json_error_t, json_error_t, column);
+ _ASSERT_FIELD (nm_json_error_t, json_error_t, position);
+ _ASSERT_FIELD (nm_json_error_t, json_error_t, source);
+ _ASSERT_FIELD (nm_json_error_t, json_error_t, text);
+
+ vt = nm_json_vt ();
+
+ g_assert (vt);
+ g_assert (vt->loaded);
+
+ js1 = vt->nm_json_loads ("{ \"a\": 5 }", 0, NULL);
+ g_assert (js1);
+ nm_json_decref (vt, g_steal_pointer (&js1));
+
+ js2 = vt->nm_json_loads ("{ \"a\": 6 }", 0, NULL);
+ g_assert (js2);
+
+#define CHECK_FCN(vt, fcn, nm_type, js_type) \
+ G_STMT_START { \
+ const NMJsonVt *const _vt = (vt); \
+ _nm_unused nm_type = (_vt->nm_##fcn); \
+ _nm_unused js_type = (fcn); \
+ \
+ g_assert (_vt->nm_##fcn); \
+ g_assert (_f_nm); \
+ g_assert (_f_js); \
+ g_assert (_f_nm == _vt->nm_##fcn); \
+ } G_STMT_END
+
+ CHECK_FCN (vt, json_array,
+ nm_json_t *(*_f_nm) (void),
+ json_t *(*_f_js) (void));
+ CHECK_FCN (vt, json_array_append_new,
+ int (*_f_nm) (nm_json_t *, nm_json_t *),
+ int (*_f_js) ( json_t *, json_t *));
+ CHECK_FCN (vt, json_array_get,
+ nm_json_t *(*_f_nm) (const nm_json_t *, gsize ),
+ json_t *(*_f_js) (const json_t *, size_t));
+ CHECK_FCN (vt, json_array_size,
+ gsize (*_f_nm) (const nm_json_t *),
+ size_t (*_f_js) (const json_t *));
+ CHECK_FCN (vt, json_delete,
+ void (*_f_nm) (nm_json_t *),
+ void (*_f_js) ( json_t *));
+ CHECK_FCN (vt, json_dumps,
+ char *(*_f_nm) (const nm_json_t *, gsize ),
+ char *(*_f_js) (const json_t *, size_t));
+ CHECK_FCN (vt, json_false,
+ nm_json_t *(*_f_nm) (void),
+ json_t *(*_f_js) (void));
+ CHECK_FCN (vt, json_integer,
+ nm_json_t *(*_f_nm) (nm_json_int_t),
+ json_t *(*_f_js) ( json_int_t));
+ CHECK_FCN (vt, json_integer_value,
+ nm_json_int_t (*_f_nm) (const nm_json_t *),
+ json_int_t (*_f_js) (const json_t *));
+ CHECK_FCN (vt, json_loads,
+ nm_json_t *(*_f_nm) (const char *, gsize , nm_json_error_t *),
+ json_t *(*_f_js) (const char *, size_t, json_error_t *));
+ CHECK_FCN (vt, json_object,
+ nm_json_t *(*_f_nm) (void),
+ json_t *(*_f_js) (void));
+ CHECK_FCN (vt, json_object_del,
+ int (*_f_nm) (nm_json_t *, const char *),
+ int (*_f_js) ( json_t *, const char *));
+ CHECK_FCN (vt, json_object_get,
+ nm_json_t *(*_f_nm) (const nm_json_t *, const char *),
+ json_t *(*_f_js) (const json_t *, const char *));
+ CHECK_FCN (vt, json_object_iter,
+ void *(*_f_nm) (nm_json_t *),
+ void *(*_f_js) ( json_t *));
+ CHECK_FCN (vt, json_object_iter_key,
+ const char *(*_f_nm) (void *),
+ const char *(*_f_js) (void *));
+ CHECK_FCN (vt, json_object_iter_next,
+ void *(*_f_nm) (nm_json_t *, void *),
+ void *(*_f_js) ( json_t *, void *));
+ CHECK_FCN (vt, json_object_iter_value,
+ nm_json_t *(*_f_nm) (void *),
+ json_t *(*_f_js) (void *));
+ CHECK_FCN (vt, json_object_key_to_iter,
+ void *(*_f_nm) (const char *),
+ void *(*_f_js) (const char *));
+ CHECK_FCN (vt, json_object_set_new,
+ int (*_f_nm) (nm_json_t *, const char *, nm_json_t *),
+ int (*_f_js) ( json_t *, const char *, json_t *));
+ CHECK_FCN (vt, json_object_size,
+ gsize (*_f_nm) (const nm_json_t *),
+ size_t (*_f_js) (const json_t *));
+ CHECK_FCN (vt, json_string,
+ nm_json_t *(*_f_nm) (const char *),
+ json_t *(*_f_js) (const char *));
+ CHECK_FCN (vt, json_string_value,
+ const char *(*_f_nm) (const nm_json_t *),
+ const char *(*_f_js) (const json_t *));
+ CHECK_FCN (vt, json_true,
+ nm_json_t *(*_f_nm) (void),
+ json_t *(*_f_js) (void));
+}
+
+/*****************************************************************************/
+
+NMTST_DEFINE ();
+
+int main (int argc, char **argv)
+{
+ nmtst_init (&argc, &argv, TRUE);
+
+ g_test_add_func ("/general/test_jansson", test_jansson);
+
+ return g_test_run ();
+}
diff --git a/shared/nm-glib-aux/tests/test-shared-general.c b/shared/nm-glib-aux/tests/test-shared-general.c
index 5c8bdf18e8..f389770a7a 100644
--- a/shared/nm-glib-aux/tests/test-shared-general.c
+++ b/shared/nm-glib-aux/tests/test-shared-general.c
@@ -636,6 +636,8 @@ test_nm_utils_get_next_realloc_size (void)
{ G_MAXSIZE - 24u, G_MAXSIZE, G_MAXSIZE },
{ G_MAXSIZE - 1u, G_MAXSIZE, G_MAXSIZE },
{ G_MAXSIZE, G_MAXSIZE, G_MAXSIZE },
+ { NM_UTILS_GET_NEXT_REALLOC_SIZE_32, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, NM_UTILS_GET_NEXT_REALLOC_SIZE_32 },
+ { NM_UTILS_GET_NEXT_REALLOC_SIZE_40, NM_UTILS_GET_NEXT_REALLOC_SIZE_40, NM_UTILS_GET_NEXT_REALLOC_SIZE_40 },
{ NM_UTILS_GET_NEXT_REALLOC_SIZE_104, NM_UTILS_GET_NEXT_REALLOC_SIZE_104, NM_UTILS_GET_NEXT_REALLOC_SIZE_104 },
{ NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 },
};
@@ -771,6 +773,109 @@ test_nm_str_buf (void)
/*****************************************************************************/
+static void
+test_nm_utils_parse_next_line (void)
+{
+ const char *data;
+ const char *data0;
+ gsize data_len;
+ const char *line_start;
+ gsize line_len;
+ int i_run;
+ gsize j, k;
+
+ data = NULL;
+ data_len = 0;
+ g_assert (!nm_utils_parse_next_line (&data, &data_len, &line_start, &line_len));
+
+ for (i_run = 0; i_run < 1000; i_run++) {
+ gs_unref_ptrarray GPtrArray *strv = g_ptr_array_new_with_free_func (g_free);
+ gs_unref_ptrarray GPtrArray *strv2 = g_ptr_array_new_with_free_func (g_free);
+ gsize strv_len = nmtst_get_rand_word_length (NULL);
+ nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT (0, nmtst_get_rand_bool ());
+
+ /* create a list of random words. */
+ for (j = 0; j < strv_len; j++) {
+ gsize w_len = nmtst_get_rand_word_length (NULL);
+ NMStrBuf w_buf = NM_STR_BUF_INIT (nmtst_get_rand_uint32 () % (w_len + 1), nmtst_get_rand_bool ());
+
+ for (k = 0; k < w_len; k++)
+ nm_str_buf_append_c (&w_buf, '0' + (k % 10));
+ nm_str_buf_maybe_expand (&w_buf, 1, TRUE);
+ g_ptr_array_add (strv, nm_str_buf_finalize (&w_buf, NULL));
+ }
+
+ /* join the list of random words with (random) line delimiters
+ * ("\0", "\n", "\r" or EOF). */
+ for (j = 0; j < strv_len; j++) {
+ nm_str_buf_append (&strbuf, strv->pdata[j]);
+again:
+ switch (nmtst_get_rand_uint32 () % 5) {
+ case 0:
+ nm_str_buf_append_c (&strbuf, '\0');
+ break;
+ case 1:
+ if ( strbuf.len > 0
+ && (nm_str_buf_get_str_unsafe (&strbuf))[strbuf.len - 1] == '\r') {
+ /* the previous line was empty and terminated by "\r". We
+ * must not join with "\n". Retry. */
+ goto again;
+ }
+ nm_str_buf_append_c (&strbuf, '\n');
+ break;
+ case 2:
+ nm_str_buf_append_c (&strbuf, '\r');
+ break;
+ case 3:
+ nm_str_buf_append (&strbuf, "\r\n");
+ break;
+ case 4:
+ /* the last word randomly is delimited or not, but not if the last
+ * word is "". */
+ if (j + 1 < strv_len) {
+ /* it's not the last word. Retry. */
+ goto again;
+ }
+ g_assert (j == strv_len - 1);
+ if (((const char *) strv->pdata[j])[0] == '\0') {
+ /* if the last word was "", we need a delimiter (to parse it back).
+ * Retry. */
+ goto again;
+ }
+ /* The final delimiter gets omitted. It's EOF. */
+ break;
+ }
+ }
+
+ data0 = nm_str_buf_get_str_unsafe (&strbuf);
+ if ( !data0
+ && nmtst_get_rand_bool ()) {
+ nm_str_buf_maybe_expand (&strbuf, 1, TRUE);
+ data0 = nm_str_buf_get_str_unsafe (&strbuf);
+ g_assert (data0);
+ }
+ data_len = strbuf.len;
+ g_assert ((data_len > 0 && data0) || data_len == 0);
+ data = data0;
+ while (nm_utils_parse_next_line (&data, &data_len, &line_start, &line_len)) {
+ g_assert (line_start);
+ g_assert (line_start >= data0);
+ g_assert (line_start < &data0[strbuf.len]);
+ g_assert (!memchr (line_start, '\0', line_len));
+ g_ptr_array_add (strv2, g_strndup (line_start, line_len));
+ }
+ g_assert (data_len == 0);
+ if (data0)
+ g_assert (data == &data0[strbuf.len]);
+ else
+ g_assert (!data);
+
+ g_assert (_nm_utils_strv_cmp_n ((const char *const*) strv->pdata, strv->len, (const char *const*) strv2->pdata, strv2->len) == 0);
+ }
+}
+
+/*****************************************************************************/
+
NMTST_DEFINE ();
int main (int argc, char **argv)
@@ -792,6 +897,7 @@ int main (int argc, char **argv)
g_test_add_func ("/general/test_string_table_lookup", test_string_table_lookup);
g_test_add_func ("/general/test_nm_utils_get_next_realloc_size", test_nm_utils_get_next_realloc_size);
g_test_add_func ("/general/test_nm_str_buf", test_nm_str_buf);
+ g_test_add_func ("/general/test_nm_utils_parse_next_line", test_nm_utils_parse_next_line);
return g_test_run ();
}
diff --git a/shared/nm-std-aux/nm-std-aux.h b/shared/nm-std-aux/nm-std-aux.h
new file mode 100644
index 0000000000..26317c2c27
--- /dev/null
+++ b/shared/nm-std-aux/nm-std-aux.h
@@ -0,0 +1,621 @@
+// SPDX-License-Identifier: LGPL-2.1+
+
+#ifndef __NM_STD_AUX_H__
+#define __NM_STD_AUX_H__
+
+#include <assert.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+/*****************************************************************************/
+
+#define _nm_packed __attribute__ ((__packed__))
+#define _nm_unused __attribute__ ((__unused__))
+#define _nm_used __attribute__ ((__used__))
+#define _nm_pure __attribute__ ((__pure__))
+#define _nm_const __attribute__ ((__const__))
+#define _nm_printf(a,b) __attribute__ ((__format__ (__printf__, a, b)))
+#define _nm_align(s) __attribute__ ((__aligned__ (s)))
+#define _nm_section(s) __attribute__ ((__section__ (s)))
+#define _nm_alignof(type) __alignof (type)
+#define _nm_alignas(type) _nm_align (_nm_alignof (type))
+#define nm_auto(fcn) __attribute__ ((__cleanup__(fcn)))
+
+/* This is required to make LTO working.
+ *
+ * See https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/76#note_112694
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48200#c28
+ */
+#ifndef __clang__
+#define _nm_externally_visible __attribute__ ((__externally_visible__))
+#else
+#define _nm_externally_visible
+#endif
+
+
+#if __GNUC__ >= 7
+#define _nm_fallthrough __attribute__ ((__fallthrough__))
+#else
+#define _nm_fallthrough
+#endif
+
+/*****************************************************************************/
+
+#ifdef thread_local
+#define _nm_thread_local thread_local
+/*
+ * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
+ * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
+ */
+#elif __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
+#define _nm_thread_local _Thread_local
+#else
+#define _nm_thread_local __thread
+#endif
+
+/*****************************************************************************/
+
+#define NM_PASTE_ARGS(identifier1,identifier2) identifier1 ## identifier2
+#define NM_PASTE(identifier1,identifier2) NM_PASTE_ARGS (identifier1, identifier2)
+
+/* Taken from systemd's UNIQ_T and UNIQ macros. */
+
+#define NM_UNIQ_T(x, uniq) NM_PASTE(__unique_prefix_, NM_PASTE(x, uniq))
+#define NM_UNIQ __COUNTER__
+
+/*****************************************************************************/
+
+#define _NM_BOOLEAN_EXPR_IMPL(v, expr) \
+ ({ \
+ int NM_UNIQ_T(V, v); \
+ \
+ if (expr) \
+ NM_UNIQ_T(V, v) = 1; \
+ else \
+ NM_UNIQ_T(V, v) = 0; \
+ NM_UNIQ_T(V, v); \
+ })
+#define NM_BOOLEAN_EXPR(expr) _NM_BOOLEAN_EXPR_IMPL (NM_UNIQ, expr)
+
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define NM_LIKELY(expr) (__builtin_expect (NM_BOOLEAN_EXPR (expr), 1))
+#define NM_UNLIKELY(expr) (__builtin_expect (NM_BOOLEAN_EXPR (expr), 0))
+#else
+#define NM_LIKELY(expr) NM_BOOLEAN_EXPR (expr)
+#define NM_UNLIKELY(expr) NM_BOOLEAN_EXPR (expr)
+#endif
+
+/*****************************************************************************/
+
+/* glib/C provides the following kind of assertions:
+ * - assert() -- disable with NDEBUG
+ * - g_return_if_fail() -- disable with G_DISABLE_CHECKS
+ * - g_assert() -- disable with G_DISABLE_ASSERT
+ * but they are all enabled by default and usually even production builds have
+ * these kind of assertions enabled. It also means, that disabling assertions
+ * is an untested configuration, and might have bugs.
+ *
+ * Add our own assertion macro nm_assert(), which is disabled by default and must
+ * be explicitly enabled. They are useful for more expensive checks or checks that
+ * depend less on runtime conditions (that is, are generally expected to be true). */
+
+#ifndef NM_MORE_ASSERTS
+#define NM_MORE_ASSERTS 0
+#endif
+
+#ifndef _nm_assert_call
+#define _nm_assert_call(cond) assert(cond)
+#define _nm_assert_call_not_reached() assert(0)
+#endif
+
+#if NM_MORE_ASSERTS
+#define nm_assert(cond) do { _nm_assert_call (cond); } while (0)
+#define nm_assert_se(cond) do { if (NM_LIKELY (cond)) { ; } else { _nm_assert_call (0 && (cond)); } } while (0)
+#define nm_assert_not_reached() do { _nm_assert_call_not_reached (); } while (0)
+#else
+#define nm_assert(cond) do { if (0) { if (cond) { } } } while (0)
+#define nm_assert_se(cond) do { if (NM_LIKELY (cond)) { ; } } while (0)
+#define nm_assert_not_reached() do { ; } while (0)
+#endif
+
+#define NM_STATIC_ASSERT(cond) static_assert(cond, "")
+#define NM_STATIC_ASSERT_EXPR(cond) ({ NM_STATIC_ASSERT (cond); 1; })
+
+/*****************************************************************************/
+
+#define NM_N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0]))
+
+/*****************************************************************************/
+
+/* glib's MIN()/MAX() macros don't have function-like behavior, in that they evaluate
+ * the argument possibly twice.
+ *
+ * Taken from systemd's MIN()/MAX() macros. */
+
+#define NM_MIN(a, b) __NM_MIN(NM_UNIQ, a, NM_UNIQ, b)
+#define __NM_MIN(aq, a, bq, b) \
+ ({ \
+ typeof (a) NM_UNIQ_T(A, aq) = (a); \
+ typeof (b) NM_UNIQ_T(B, bq) = (b); \
+ ((NM_UNIQ_T(A, aq) < NM_UNIQ_T(B, bq)) ? NM_UNIQ_T(A, aq) : NM_UNIQ_T(B, bq)); \
+ })
+
+#define NM_MAX(a, b) __NM_MAX(NM_UNIQ, a, NM_UNIQ, b)
+#define __NM_MAX(aq, a, bq, b) \
+ ({ \
+ typeof (a) NM_UNIQ_T(A, aq) = (a); \
+ typeof (b) NM_UNIQ_T(B, bq) = (b); \
+ ((NM_UNIQ_T(A, aq) > NM_UNIQ_T(B, bq)) ? NM_UNIQ_T(A, aq) : NM_UNIQ_T(B, bq)); \
+ })
+
+#define NM_CLAMP(x, low, high) __NM_CLAMP(NM_UNIQ, x, NM_UNIQ, low, NM_UNIQ, high)
+#define __NM_CLAMP(xq, x, lowq, low, highq, high) \
+ ({ \
+ typeof(x)NM_UNIQ_T(X,xq) = (x); \
+ typeof(low) NM_UNIQ_T(LOW,lowq) = (low); \
+ typeof(high) NM_UNIQ_T(HIGH,highq) = (high); \
+ \
+ ( (NM_UNIQ_T(X,xq) > NM_UNIQ_T(HIGH,highq)) \
+ ? NM_UNIQ_T(HIGH,highq) \
+ : (NM_UNIQ_T(X,xq) < NM_UNIQ_T(LOW,lowq)) \
+ ? NM_UNIQ_T(LOW,lowq) \
+ : NM_UNIQ_T(X,xq)); \
+ })
+
+#define NM_MAX_WITH_CMP(cmp, a, b) \
+ ({ \
+ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+ \
+ ( ((cmp (_a, _b)) >= 0) \
+ ? _a \
+ : _b); \
+ })
+
+/* evaluates to (void) if _A or _B are not constant or of different types */
+#define NM_CONST_MAX(_A, _B) \
+ (__builtin_choose_expr (( __builtin_constant_p (_A) \
+ && __builtin_constant_p (_B) \
+ && __builtin_types_compatible_p (typeof (_A), typeof (_B))), \
+ ((_A) > (_B)) ? (_A) : (_B), \
+ ((void) 0)))
+
+/*****************************************************************************/
+
+#define NM_SWAP(a, b) \
+ do { \
+ typeof (a) _tmp; \
+ \
+ _tmp = (a); \
+ (a) = (b); \
+ (b) = _tmp; \
+ } while (0)
+
+/*****************************************************************************/
+
+/* macro to return strlen() of a compile time string. */
+#define NM_STRLEN(str) ( sizeof (""str"") - 1u )
+
+/* returns the length of a NULL terminated array of pointers,
+ * like g_strv_length() does. The difference is:
+ * - it operates on arrays of pointers (of any kind, requiring no cast).
+ * - it accepts NULL to return zero. */
+#define NM_PTRARRAY_LEN(array) \
+ ({ \
+ typeof (*(array)) *const _array = (array); \
+ size_t _n = 0; \
+ \
+ if (_array) { \
+ _nm_unused const void * _type_check_is_pointer = _array[0]; \
+ \
+ while (_array[_n]) \
+ _n++; \
+ } \
+ _n; \
+ })
+
+/*****************************************************************************/
+
+static inline int
+nm_strcmp0 (const char *s1, const char *s2)
+{
+ int c;
+
+ /* like g_strcmp0(), but this is inlinable.
+ *
+ * Also, it is guaranteed to return either -1, 0, or 1. */
+ if (s1 == s2)
+ return 0;
+ if (!s1)
+ return -1;
+ if (!s2)
+ return 1;
+ c = strcmp (s1, s2);
+ if (c < 0)
+ return -1;
+ if (c > 0)
+ return 1;
+ return 0;
+}
+
+static inline int
+nm_streq (const char *s1, const char *s2)
+{
+ return strcmp (s1, s2) == 0;
+}
+
+static inline int
+nm_streq0 (const char *s1, const char *s2)
+{
+ return (s1 == s2)
+ || (s1 && s2 && strcmp (s1, s2) == 0);
+}
+
+#define NM_STR_HAS_PREFIX(str, prefix) \
+ ({ \
+ const char *const _str_has_prefix = (str); \
+ \
+ nm_assert (strlen (prefix) == NM_STRLEN (prefix)); \
+ \
+ _str_has_prefix \
+ && (strncmp (_str_has_prefix, ""prefix"", NM_STRLEN (prefix)) == 0); \
+ })
+
+#define NM_STR_HAS_SUFFIX(str, suffix) \
+ ({ \
+ const char *const _str_has_suffix = (str); \
+ size_t _l; \
+ \
+ nm_assert (strlen (suffix) == NM_STRLEN (suffix)); \
+ \
+ ( _str_has_suffix \
+ && ((_l = strlen (_str_has_suffix)) >= NM_STRLEN (suffix)) \
+ && (memcmp (&_str_has_suffix[_l - NM_STRLEN (suffix)], \
+ ""suffix"", \
+ NM_STRLEN (suffix)) == 0)); \
+ })
+
+/* whether @str starts with the string literal @prefix and is followed by
+ * some other text. It is like NM_STR_HAS_PREFIX() && !nm_streq() together. */
+#define NM_STR_HAS_PREFIX_WITH_MORE(str, prefix) \
+ ({ \
+ const char *const _str_has_prefix_with_more = (str); \
+ \
+ NM_STR_HAS_PREFIX (_str_has_prefix_with_more, ""prefix"") \
+ && _str_has_prefix_with_more[NM_STRLEN (prefix)] != '\0'; \
+ })
+
+/*****************************************************************************/
+
+#define _NM_IN_SET_EVAL_1( op, _x, y) (_x == (y))
+#define _NM_IN_SET_EVAL_2( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_1 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_3( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_2 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_4( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_3 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_5( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_4 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_6( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_5 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_7( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_6 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_8( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_7 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_9( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_8 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_10(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_9 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_11(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_10 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_12(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_11 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_13(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_12 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_14(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_13 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_15(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_14 (op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_16(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_15 (op, _x, __VA_ARGS__)
+
+#define _NM_IN_SET_EVAL_N2(op, _x, n, ...) (_NM_IN_SET_EVAL_##n(op, _x, __VA_ARGS__))
+#define _NM_IN_SET_EVAL_N(op, type, x, n, ...) \
+ ({ \
+ type _x = (x); \
+ \
+ /* trigger a -Wenum-compare warning */ \
+ nm_assert (true || _x == (x)); \
+ \
+ !!_NM_IN_SET_EVAL_N2(op, _x, n, __VA_ARGS__); \
+ })
+
+#define _NM_IN_SET(op, type, x, ...) _NM_IN_SET_EVAL_N(op, type, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
+
+/* Beware that this does short-circuit evaluation (use "||" instead of "|")
+ * which has a possibly unexpected non-function-like behavior.
+ * Use NM_IN_SET_SE if you need all arguments to be evaluated. */
+#define NM_IN_SET(x, ...) _NM_IN_SET(||, typeof (x), x, __VA_ARGS__)
+
+/* "SE" stands for "side-effect". Contrary to NM_IN_SET(), this does not do
+ * short-circuit evaluation, which can make a difference if the arguments have
+ * side-effects. */
+#define NM_IN_SET_SE(x, ...) _NM_IN_SET(|, typeof (x), x, __VA_ARGS__)
+
+/* the *_TYPED forms allow to explicitly select the type of "x". This is useful
+ * if "x" doesn't support typeof (bitfields) or you want to gracefully convert
+ * a type using automatic type conversion rules (but not forcing the conversion
+ * with a cast). */
+#define NM_IN_SET_TYPED(type, x, ...) _NM_IN_SET(||, type, x, __VA_ARGS__)
+#define NM_IN_SET_SE_TYPED(type, x, ...) _NM_IN_SET(|, type, x, __VA_ARGS__)
+
+/*****************************************************************************/
+
+static inline int
+_NM_IN_STRSET_streq (const char *x, const char *s)
+{
+ return s && strcmp (x, s) == 0;
+}
+
+#define _NM_IN_STRSET_EVAL_1( op, _x, y) _NM_IN_STRSET_streq (_x, y)
+#define _NM_IN_STRSET_EVAL_2( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_1 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_3( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_2 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_4( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_3 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_5( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_4 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_6( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_5 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_7( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_6 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_8( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_7 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_9( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_8 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_10(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_9 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_11(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_10 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_12(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_11 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_13(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_12 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_14(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_13 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_15(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_14 (op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_16(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_15 (op, _x, __VA_ARGS__)
+
+#define _NM_IN_STRSET_EVAL_N2(op, _x, n, ...) (_NM_IN_STRSET_EVAL_##n(op, _x, __VA_ARGS__))
+#define _NM_IN_STRSET_EVAL_N(op, x, n, ...) \
+ ({ \
+ const char *_x = (x); \
+ ( ((_x == NULL) && _NM_IN_SET_EVAL_N2 (op, ((const char *) NULL), n, __VA_ARGS__)) \
+ || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2 (op, _x, n, __VA_ARGS__)) \
+ ); \
+ })
+
+/* Beware that this does short-circuit evaluation (use "||" instead of "|")
+ * which has a possibly unexpected non-function-like behavior.
+ * Use NM_IN_STRSET_SE if you need all arguments to be evaluated. */
+#define NM_IN_STRSET(x, ...) _NM_IN_STRSET_EVAL_N(||, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
+
+/* "SE" stands for "side-effect". Contrary to NM_IN_STRSET(), this does not do
+ * short-circuit evaluation, which can make a difference if the arguments have
+ * side-effects. */
+#define NM_IN_STRSET_SE(x, ...) _NM_IN_STRSET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
+
+/*****************************************************************************/
+
+#define NM_STRCHAR_ALL(str, ch_iter, predicate) \
+ ({ \
+ int _val = true; \
+ const char *_str = (str); \
+ \
+ if (_str) { \
+ for (;;) { \
+ const char ch_iter = _str[0]; \
+ \
+ if (ch_iter != '\0') { \
+ if (predicate) {\
+ _str++; \
+ continue; \
+ } \
+ _val = false; \
+ } \
+ break; \
+ } \
+ } \
+ _val; \
+ })
+
+#define NM_STRCHAR_ANY(str, ch_iter, predicate) \
+ ({ \
+ int _val = false; \
+ const char *_str = (str); \
+ \
+ if (_str) { \
+ for (;;) { \
+ const char ch_iter = _str[0]; \
+ \
+ if (ch_iter != '\0') { \
+ if (predicate) { \
+ ; \
+ } else { \
+ _str++; \
+ continue; \
+ } \
+ _val = true; \
+ } \
+ break; \
+ } \
+ } \
+ _val; \
+ })
+
+/*****************************************************************************/
+
+/**
+ * nm_close:
+ *
+ * Like close() but throws an assertion if the input fd is
+ * invalid. Closing an invalid fd is a programming error, so
+ * it's better to catch it early.
+ */
+static inline int
+nm_close (int fd)
+{
+ int r;
+
+ r = close (fd);
+ nm_assert (r != -1 || fd < 0 || errno != EBADF);
+ return r;
+}
+
+/*****************************************************************************/
+
+/* Note: @value is only evaluated when *out_val is present.
+ * Thus,
+ * NM_SET_OUT (out_str, g_strdup ("hallo"));
+ * does the right thing.
+ */
+#define NM_SET_OUT(out_val, value) \
+ ({ \
+ typeof(*(out_val)) *_out_val = (out_val); \
+ \
+ if (_out_val) { \
+ *_out_val = (value); \
+ } \
+ \
+ (!!_out_val); \
+ })
+
+/*****************************************************************************/
+
+#define NM_AUTO_DEFINE_FCN_VOID(CastType, name, func) \
+static inline void name (void *v) \
+{ \
+ func (*((CastType *) v)); \
+}
+
+#define NM_AUTO_DEFINE_FCN_VOID0(CastType, name, func) \
+static inline void name (void *v) \
+{ \
+ if (*((CastType *) v)) \
+ func (*((CastType *) v)); \
+}
+
+#define NM_AUTO_DEFINE_FCN(Type, name, func) \
+static inline void name (Type *v) \
+{ \
+ func (*v); \
+}
+
+#define NM_AUTO_DEFINE_FCN0(Type, name, func) \
+static inline void name (Type *v) \
+{ \
+ if (*v) \
+ func (*v); \
+}
+
+/*****************************************************************************/
+
+/**
+ * nm_auto_free:
+ *
+ * Call free() on a variable location when it goes out of scope.
+ * This is for pointers that are allocated with malloc() instead of
+ * g_malloc().
+ *
+ * In practice, since glib 2.45, g_malloc()/g_free() always wraps malloc()/free().
+ * See bgo#751592. In that case, it would be safe to free pointers allocated with
+ * malloc() with gs_free or g_free().
+ *
+ * However, let's never mix them. To free malloc'ed memory, always use
+ * free() or nm_auto_free.
+ */
+NM_AUTO_DEFINE_FCN_VOID0 (void *, _nm_auto_free_impl, free)
+#define nm_auto_free nm_auto(_nm_auto_free_impl)
+
+/*****************************************************************************/
+
+static inline void
+_nm_auto_close (int *pfd)
+{
+ if (*pfd >= 0) {
+ int errsv = errno;
+
+ (void) nm_close (*pfd);
+ errno = errsv;
+ }
+}
+#define nm_auto_close nm_auto(_nm_auto_close)
+
+static inline void
+_nm_auto_fclose (FILE **pfd)
+{
+ if (*pfd) {
+ int errsv = errno;
+
+ (void) fclose (*pfd);
+ errno = errsv;
+ }
+}
+#define nm_auto_fclose nm_auto(_nm_auto_fclose)
+
+/*****************************************************************************/
+
+#define nm_clear_pointer(pp, destroy) \
+ ({ \
+ typeof (*(pp)) *_pp = (pp); \
+ typeof (*_pp) _p; \
+ int _changed = false; \
+ \
+ if ( _pp \
+ && (_p = *_pp)) { \
+ _nm_unused const void *_p_check_is_pointer = _p; \
+ \
+ *_pp = NULL; \
+ \
+ /* g_clear_pointer() assigns @destroy first to a local variable, so that
+ * you can call "g_clear_pointer (pp, (GDestroyNotify) destroy);" without
+ * gcc emitting a warning. We don't do that, hence, you cannot cast
+ * "destroy" first.
+ *
+ * On the upside: you are not supposed to cast fcn, because the pointer
+ * types are preserved. If you really need a cast, you should cast @pp.
+ * But that is hardly ever necessary. */ \
+ (destroy) (_p); \
+ \
+ _changed = true; \
+ } \
+ _changed; \
+ })
+
+#define nm_clear_free(pp) nm_clear_pointer (pp, free)
+
+/*****************************************************************************/
+
+static inline void *
+_nm_steal_pointer (void *pp)
+{
+ void **ptr = (void **) pp;
+ void *ref;
+
+ ref = *ptr;
+ *ptr = NULL;
+ return ref;
+}
+
+#define nm_steal_pointer(pp) \
+ ((typeof (*(pp))) _nm_steal_pointer (pp))
+
+/**
+ * nm_steal_int:
+ * @p_val: pointer to an int type.
+ *
+ * Returns: *p_val and sets *p_val to zero the same time.
+ * Accepts %NULL, in which case also numeric 0 will be returned.
+ */
+#define nm_steal_int(p_val) \
+ ({ \
+ typeof (p_val) const _p_val = (p_val); \
+ typeof (*_p_val) _val = 0; \
+ \
+ if ( _p_val \
+ && (_val = *_p_val)) { \
+ *_p_val = 0; \
+ } \
+ _val; \
+ })
+
+static inline int
+nm_steal_fd (int *p_fd)
+{
+ int fd;
+
+ if ( p_fd
+ && ((fd = *p_fd) >= 0)) {
+ *p_fd = -1;
+ return fd;
+ }
+ return -1;
+}
+
+#endif /* __NM_STD_AUX_H__ */
diff --git a/shared/nm-std-aux/nm-std-utils.c b/shared/nm-std-aux/nm-std-utils.c
new file mode 100644
index 0000000000..f6c2bc43ff
--- /dev/null
+++ b/shared/nm-std-aux/nm-std-utils.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: LGPL-2.1+
+
+#include "nm-default.h"
+
+#include "nm-std-utils.h"
+
+#include <stdint.h>
+
+/*****************************************************************************/
+
+size_t
+nm_utils_get_next_realloc_size (bool true_realloc, size_t requested)
+{
+ size_t n, x;
+
+ /* https://doc.qt.io/qt-5/containers.html#growth-strategies */
+
+ if (requested <= 40) {
+ /* small allocations. Increase in small steps of 8 bytes.
+ *
+ * We get thus sizes of 8, 16, 32, 40. */
+ if (requested <= 8)
+ return 8;
+ if (requested <= 16)
+ return 16;
+ if (requested <= 32)
+ return 32;
+
+ /* The return values for < 104 are essentially hard-coded, and the choice here is
+ * made without very strong reasons.
+ *
+ * We want to stay 24 bytes below the power-of-two border 64. Hence, return 40 here.
+ * However, the next step then is already 104 (128 - 24). It's a larger gap than in
+ * the steps before.
+ *
+ * It's not clear whether some of the steps should be adjusted (or how exactly). */
+ return 40;
+ }
+
+ if ( requested <= 0x2000u - 24u
+ || NM_UNLIKELY (!true_realloc)) {
+ /* mid sized allocations. Return next power of two, minus 24 bytes extra space
+ * at the beginning.
+ * That means, we double the size as we grow.
+ *
+ * With !true_realloc, it means that the caller does not intend to call
+ * realloc() but instead clone the buffer. This is for example the case, when we
+ * want to nm_explicit_bzero() the old buffer. In that case we really want to grow
+ * the buffer exponentially every time and not increment in page sizes of 4K (below).
+ *
+ * We get thus sizes of 104, 232, 488, 1000, 2024, 4072, 8168... */
+
+ if (NM_UNLIKELY (requested > SIZE_MAX / 2u - 24u))
+ return SIZE_MAX;
+
+ x = requested + 24u;
+ n = 128u;
+ while (n < x) {
+ n <<= 1;
+ nm_assert (n > 128u);
+ }
+
+ nm_assert (n > 24u && n - 24u >= requested);
+ return n - 24u;
+ }
+
+ if (NM_UNLIKELY (requested > SIZE_MAX - 0x1000u - 24u))
+ return SIZE_MAX;
+
+ /* For large allocations (with !true_realloc) we allocate memory in chunks of
+ * 4K (- 24 bytes extra), assuming that the memory gets mmapped and thus
+ * realloc() is efficient by just reordering pages. */
+ n = ((requested + (0x0FFFu + 24u)) & ~((size_t) 0x0FFFu)) - 24u;
+ nm_assert (n >= requested);
+ return n;
+}
diff --git a/shared/nm-std-aux/nm-std-utils.h b/shared/nm-std-aux/nm-std-utils.h
new file mode 100644
index 0000000000..0945c8600f
--- /dev/null
+++ b/shared/nm-std-aux/nm-std-utils.h
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: LGPL-2.1+
+
+#ifndef __NM_STD_UTILS_H__
+#define __NM_STD_UTILS_H__
+
+#include <stdbool.h>
+
+#include "nm-std-aux.h"
+
+/*****************************************************************************/
+
+/* nm_utils_get_next_realloc_size() is used to grow buffers exponentially, when
+ * the final size is unknown. As such, it has borders for which it allocates
+ * certain buffer sizes.
+ *
+ * The use of these defines is to get favorable allocation sequences.
+ * For example, nm_str_buf_init() asks for an initial allocation size. Note that
+ * it reserves the exactly requested amount, under the assumption that the
+ * user may know how many bytes will be required. However, often the caller
+ * doesn't know in advance, and NMStrBuf grows exponentially by calling
+ * nm_utils_get_next_realloc_size().
+ * Imagine you call nm_str_buf_init() with an initial buffer size 100, and you
+ * add one character at a time. Then the first reallocation will increase the
+ * buffer size only from 100 to 104.
+ * If you however start with an initial buffer size of 104, then the next reallocation
+ * via nm_utils_get_next_realloc_size() gives you 232, and so on. By using
+ * these sizes, it results in one less allocation, if you anyway don't know the
+ * exact size in advance. */
+#define NM_UTILS_GET_NEXT_REALLOC_SIZE_32 ((size_t) 32)
+#define NM_UTILS_GET_NEXT_REALLOC_SIZE_40 ((size_t) 40)
+#define NM_UTILS_GET_NEXT_REALLOC_SIZE_104 ((size_t) 104)
+#define NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 ((size_t) 1000)
+
+size_t nm_utils_get_next_realloc_size (bool true_realloc, size_t requested);
+
+#endif /* __NM_STD_UTILS_H__ */
diff --git a/shared/nm-test-utils-impl.c b/shared/nm-test-utils-impl.c
index ce7cc8d179..b63140c425 100644
--- a/shared/nm-test-utils-impl.c
+++ b/shared/nm-test-utils-impl.c
@@ -604,7 +604,7 @@ nmtstc_context_object_new_valist (GType gtype,
sync = TRUE;
inside_loop = FALSE;
} else {
- /* The caller allows to iterate the main context. That that point,
+ /* The caller allows to iterate the main context. On that point,
* we can both use the synchronous and the asynchronous initialization,
* both should yield the same result. Choose one randomly. */
sync = nmtst_get_rand_bool ();
diff --git a/shared/nm-version-macros.h.in b/shared/nm-version-macros.h.in
index 83da86ce10..c4d6efbcbe 100644
--- a/shared/nm-version-macros.h.in
+++ b/shared/nm-version-macros.h.in
@@ -65,6 +65,7 @@
#define NM_VERSION_1_22 (NM_ENCODE_VERSION (1, 22, 0))
#define NM_VERSION_1_24 (NM_ENCODE_VERSION (1, 24, 0))
#define NM_VERSION_1_26 (NM_ENCODE_VERSION (1, 26, 0))
+#define NM_VERSION_1_28 (NM_ENCODE_VERSION (1, 28, 0))
/* For releases, NM_API_VERSION is equal to NM_VERSION.
*
diff --git a/shared/systemd/nm-sd-utils-shared.c b/shared/systemd/nm-sd-utils-shared.c
index 4fe82ca053..2c72ba4d20 100644
--- a/shared/systemd/nm-sd-utils-shared.c
+++ b/shared/systemd/nm-sd-utils-shared.c
@@ -57,7 +57,7 @@ nm_sd_utils_unbase64char (char ch, gboolean accept_padding_equal)
* @l: the length of @p. @p is not treated as NUL terminated string but
* merely as a buffer of ascii characters.
* @secure: whether the temporary memory will be cleared to avoid leaving
- * secrets in memory (see also nm_explict_bzero()).
+ * secrets in memory (see also nm_explicit_bzero()).
* @mem: (transfer full): the decoded buffer on success.
* @len: the length of @mem on success.
*
diff --git a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h
index e2378c5b4d..5a28cdfc0d 100644
--- a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h
+++ b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h
@@ -91,7 +91,7 @@ G_STMT_START { \
/*****************************************************************************/
/* systemd cannot be compiled with "-Wdeclaration-after-statement". In particular
- * in combintation with assert_cc(). */
+ * in combination with assert_cc(). */
NM_PRAGMA_WARNING_DISABLE ("-Wdeclaration-after-statement")
/*****************************************************************************/
diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c
index 6dcb26fb6b..03ca04e175 100644
--- a/shared/systemd/src/basic/process-util.c
+++ b/shared/systemd/src/basic/process-util.c
@@ -1344,7 +1344,7 @@ int safe_fork_full(
ppid = getppid();
if (ppid == 0)
- /* Parent is in a differn't PID namespace. */;
+ /* Parent is in a different PID namespace. */;
else if (ppid != original_pid) {
log_debug("Parent died early, raising SIGTERM.");
(void) raise(SIGTERM);
diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c
index 512e7af9cb..e68262359d 100644
--- a/shared/systemd/src/basic/random-util.c
+++ b/shared/systemd/src/basic/random-util.c
@@ -77,7 +77,7 @@ int rdrand(unsigned long *ret) {
* hash functions for its hash tables, with a seed generated randomly. The hash tables
* systemd employs watch the fill level closely and reseed if necessary. This allows use of
* a low quality RNG initially, as long as it improves should a hash table be under attack:
- * the attacker after all needs to to trigger many collisions to exploit it for the purpose
+ * the attacker after all needs to trigger many collisions to exploit it for the purpose
* of DoS, but if doing so improves the seed the attack surface is reduced as the attack
* takes place.
*
diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c
index 9ced3a1291..cc592da870 100644
--- a/shared/systemd/src/basic/socket-util.c
+++ b/shared/systemd/src/basic/socket-util.c
@@ -110,7 +110,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
return -EINVAL;
} else {
- /* If there's no embedded NUL byte, then then the size needs to match the whole
+ /* If there's no embedded NUL byte, then the size needs to match the whole
* structure or the structure with one extra NUL byte suffixed. (Yeah, Linux is awful,
* and considers both equivalent: getsockname() even extends sockaddr_un beyond its
* size if the path is non NUL terminated.)*/